uer 实践
请注意,python 命令的脚本运行涉及到换行分隔符的区别,在 windows 系统请使用 git bash 运行 python 脚本
1 环境准备
1.1 windows系统
1.1.1 下载项目文件
在 windows 系统中需要安装 git 、git-lfs 。其中 git 是用来克隆较小容量的文件夹,而 git-lfs 则是用来克隆大文件夹
当你安装完以上软件后,你就可以运行如下命令来克隆本项目的代码和模型了:
git clone https://www.modelscope.cn/tiansz/uer_windows.git
1.1.2 python 环境
在克隆完仓库后,还需要安装 miniconda 和 vs code。其中 miniconda 包含了 conda 包管理工具和 python 编程语言。安装完以上两个软件后,python 编程环境就搭建完毕了。同时为了加速依赖包的下载,你可以替换 pip 源:
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
1.1.3 pytorch 环境
除了准备 python 编程环境之外,我们还需要构建深度学习环境,首先需要安装显卡驱动。安装好显卡驱动后,我们还需要安装 cuda 和 pytorch,在安装 cuda 前,你需要查看 pytorch 当前支持哪些版本的 cuda,请先安装对应版本的 cuda,之后我推荐你使用 pip 安装 pytorch,这样下载速度会快些,因为我们在前面已经替换了 pip 源。
除了最主要的 pytorch 外,我们还需要安装其他依赖,为了方便起见,我们可以从 requirements.txt
中安装:
pip install -r requirements.txt
1.2 wsl 和 ubuntu 系统
wsl 是 windows 的 linux 子系统,如果有需要,你也可以在 wsl 安装指南中下载并安装 ubuntu 发行版。
打开 wsl 后,你同样需要安装 git、git-lfs、miniconda、显卡驱动、cuda 和 pytorch
1.2.1 下载项目文件
在 linux 系统中,你只需要使用命令安装软件即可,安装 git 的命令如下:
sudo apt-get install git
安装 git-lfs 的命令如下:
sudo apt-get install git-lfs
当你安装完以上软件后,你就可以运行如下命令来克隆本项目的代码和模型了:
git clone https://www.modelscope.cn/tiansz/uer_windows.git
1.2.2 python 环境
安装 miniconda 的示例命令如下:(你可以在该镜像网站下载最新的miniconda)
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-py311_23.11.0-1-Linux-x86_64.sh
bash Miniconda3-py311_23.11.0-1-Linux-x86_64.sh
安装完成后还需要启动环境变量:source ~/.bashrc
1.2.3 pytorch 环境
若你的 windows 电脑本机已经安装了显卡驱动,那么 wsl 就不再需要安装显卡驱动了,你可以在 wsl 的终端运行 nvidia-smi
检查是否安装成功。若你使用的是物理机的 ubuntu 系统,则可以在 N卡官网 下载并安装显卡驱动。
同样的,cuda 和 pytorch 的安装和 windows 系统的类似
例如安装 cuda 12.1,请根据系统情况安装对应的版本,推荐下载 run 后缀的文件进行安装。
在安装完成后,你需要将 cuda 写入环境变量,可使用 vim 编辑环境变量:
vim ~/.bashrc
并在文件的末尾处添加如下内容:
export CUDA_HOME=/usr/local/cuda
export PATH=$PATH:$CUDA_HOME/bin
export LD_LIBRARY_PATH=/usr/local/cuda-12.1/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
编辑完成后退出即可,最后你还要激活修改后的环境变量:
source ~/.bashrc
同时你可以使用 nvcc -V
来验证 cuda 是否激活成功。若失败你还可以使用 switch-cuda 来配置 cuda 环境
除了最主要的 pytorch 外,我们还需要安装其他依赖,为了方便起见,我们可以从 requirements.txt
中安装:
pip install -r requirements.txt
2 数据准备
首先需要有适用于自然语言处理任务的数据集,例如豆瓣电影评论。这份数据是我从 kaggle 网站下载的开源数据集。类似的网站还有 github 、魔搭社区 和 huggingface 等。以下是我获取到的数据以及它们的格式,你可以在 corpora/电影评论/未清洗数据.csv
中找到它。除了在开源社区寻找语料外,你还可以从数据库中导出,或者用数据增强技术来生成。
3 数据清洗
在拿到一份数据时,需要将数据集中的句子转换为字符串,同时将重复数据剔除:
python process/clean.py \
--origin_path corpora/电影评论/未清洗数据.csv \
--clean_path corpora/电影评论/已清洗数据.csv
这可以减少我们后续标注数据的工作量,同时确保模型学习时的多样性。
4 增量预训练
目前效果较好的模型都是预训练模型,它们会在大量数据训练出一个模型,然后再用这个模型用于下游任务。我们会用预训练模型再在我们自己的数据上进行增量预训练,用于提升模型的效果。在训练过程中,BERT会随机地将输入文本中的一些单词掩盖(即替换为特殊的[MASK]
标记),然后尝试预测这些掩盖单词的正确词汇。通过这种方式,模型被迫学习上下文信息来填补被掩盖的单词,这有助于模型理解词汇在句子中的语境。
首先需要将清洗好的数据转换为预训练所需的文本格式:
python process/csv2txt.py \
--csv_path corpora/电影评论/已清洗数据.csv \
--txt_path corpora/电影评论/预训练数据.txt
接着还需要将数据进行处理,用于适配模型的输入格式:(dataset_path
是输出的数据集文件路径)
python preprocess.py \
--corpus_path corpora/电影评论/预训练数据.txt \
--dataset_path corpora/电影评论/dataset.pt
接着就可以进行增量预训练了:(dataset_path
是模型预训练的输入格式文件;output_model_path
是增量预训练之后的模型输出路径;world_size
是显卡的数量;
gpu_ranks
是显卡的编号,一般从0开始,若是双卡则为0 1
,其他以此类推;total_steps
是总的训练步数,该值需要根据总语料数量来调整;save_checkpoint_steps
则是每经过多少步数后就会将模型进行保存;
batch_size
是每次学习的样本数,一般为2的倍数;data_processor
和target
不需要进行更改)
python pretrain.py \
--dataset_path corpora/电影评论/dataset.pt \
--output_model_path corpora/电影评论/new_pretrain_model.bin \
--world_size 1 --gpu_ranks 0 \
--total_steps 500 \
--save_checkpoint_steps 500 \
--batch_size 32 \
--data_processor mlm --target mlm
5 下游任务微调
BERT模型会通过微调来适应特定的下游任务。微调过程涉及将预训练的BERT模型加载到一个下游任务的模型中,并将其权重调整为适合该任务的模型
5.1 文本分类
5.1.1 文本聚类
虽然目前很多开源数据集都已经进行了人工打标,但在实际处理业务时,面对的却是没有打标过的数据。在拿到数据时,首先需要确定这份数据有多少个类别,我建议先使用文本聚类对数据进行探索,找到有可能的分类。
(cluster_path
是有可能可以形成一个类别的语料路径;uncluster_path
是不能形成类别的语料的路径;text2vec_model
则是用于计算句子相似度的模型;batch_size
是每次计算的样本数量)
python process/cls/cluster.py \
--clean_path corpora/电影评论/已清洗数据.csv \
--cluster_path corpora/电影评论/已聚类数据.csv \
--uncluster_path corpora/电影评论/未聚类数据.csv \
--batch_size 64
在使用聚类脚本时,我们需要人工在命令行中确认当前的簇能否形成一个类别,并将当前可形成一个类别的数据剪切出来,让剩余的数据继续聚类,这样我们就可以找到当前这份数据中有可能形成的类别的数据集。后续我们还需要不断细化类别,但聚类工具确确实实帮助我们提升了标注的效率,并且当数据集比较大时格外明显。
5.1.2 数据标注
我们确定好类别标准之后就要进行打标了,而打标工具只需要使用 excel 即可。在以往我也使用过专业的标注工具,但远不如使用 excel 方便快捷,这是因为它是所有人都或多或少使用过的工具,所以还是比较熟悉的。若使用专业标注工具,就要面对不熟悉的英文,同时它们还没有 excel 那么多强大功能,例如文本筛选。而对于文本分类的标注而言,最重要的是理解每个类别的含义才能正确做出标注,所以数据标注也是一项需要大量思考的工作,你可以在 datasets/电影评论分类模型/文本分类数据.csv
中找到标注后的数据
5.1.3 数据增强
当项目处于冷启动状态时,我们可能没有那么多的语料,这就会导致有些类别的语料特别少,这时候我们可以借助大模型的的能力来生成更多相似的语料用于训练。
(unenhance_path
是人工标注后的语料;enhance_path
则是数据增强之后的样本)
python process/cls/enhance.py \
--unenhance_path datasets/电影评论分类模型/文本分类数据.csv \
--enhance_path datasets/电影评论分类模型/enhance.csv
5.1.4 微调
首先需要将数据拆分成训练集和开发集,其中训练集就是模型需要学习的数据了,而开发集就是让模型在开发集来验证当前的拟合效果,所以开发集有时也称为验证集。如果以往接触过相关知识的同学可能要问我为什么不设置测试集,这是因为测试集虽然确实能判断当前模型是否存在过拟合的情况,但由于测试集比较小,所以也无法覆盖所有应用场景,因此不再划分测试集。
(label_path
是数据增强之后的数据;train_path
是输出的训练集路径;dev_path
是输出的验证集路径;label2id_path
和 id2label_path
是标签名和数字的映射关系文件;dev_size
是验证集对于标注文件的数量占比)
python process/cls/split.py \
--label_path datasets/电影评论分类模型/enhance.csv \
--train_path datasets/电影评论分类模型/train.tsv \
--dev_path datasets/电影评论分类模型/dev.tsv \
--label2id_path datasets/电影评论分类模型/label2id.json \
--id2label_path datasets/电影评论分类模型/id2label.json
拆分训练集和验证集之后,我们就可以来微调分类模型了(pretrained_model_path
是增量预训练之后的模型路径;output_model_path
是微调之后的分类模型路径;
epochs_num
是对于训练集的学习次数;batch_size
则是每次学习的样本数量)
python finetune/run_classifier.py \
--pretrained_model_path corpora/电影评论/new_pretrain_model.bin-500 \
--output_model_path datasets/电影评论分类模型/finetuned_model.bin \
--train_path datasets/电影评论分类模型/train.tsv \
--dev_path datasets/电影评论分类模型/dev.tsv \
--epochs_num 10 --batch_size 32
5.1.5 模型迭代
我们在训练完模型后,还需要不断地迭代模型,所以需要在大量的未标注数据上进行推理。同时在推理完之后需要对推理后的数据重新进行标注,用以提升模型的准确率和泛化性。
(test_path
是没有标签的样本路径;prediction_path
是预测的标签;labels_num
是本次分类任务的标签数)
python inference/run_classifier_infer.py \
--load_model_path datasets/电影评论分类模型/finetuned_model.bin \
--test_path datasets/电影评论分类模型/test_nolabel.tsv \
--prediction_path datasets/电影评论分类模型/prediction.tsv \
--labels_num 3 --batch_size 32
不过最终得到的推理结果是保存在 tsv 格式的文件中,为了更方便标注,后续需要将推理结果转换为 xlsx 文件:
python process/cls/merge.py \
--test_path datasets/电影评论分类模型/test_nolabel.tsv \
--prediction_path datasets/电影评论分类模型/prediction.tsv \
--mapping_path datasets/电影评论分类模型/label2id.json \
--merge_path datasets/电影评论分类模型/合并语料.xlsx
5.1.6 模型推理
首先需要将模型转换为huggingface格式的模型:(同时你还要更改文件夹中的配置文件 config.json
中的 id2label
和 label2id
字段)
python scripts/convert_bert_text_classification_from_uer_to_huggingface.py \
--input_model_path datasets/电影评论分类模型/finetuned_model.bin \
--output_model_path datasets/电影评论分类模型/cls_model/pytorch_model.bin
接着我们再将该float32精度的模型降低精度到int8,这样可以提升模型的推理速度,但又不影响模型的效果。我们会使用 bitsandbytes 来量化模型,在 windows 系统中请使用如下命令安装:(若是 linux 系统则可以直接安装 bitsandbytes,无需指定特殊版本)
python -m pip install bitsandbytes==0.39.0 --prefer-binary --extra-index-url=https://jllllll.github.io/bitsandbytes-windows-webui
安装完成后即可量化模型:
python process/cls/quantization.py \
--model_path datasets/电影评论分类模型/cls_model \
--model_path_q datasets/电影评论分类模型/cls_model_q
然后我们就可以调用量化后的模型了:
python server/cls.py
5.1.7 模型部署
你可以运行如下命令以用于启动分类模型的服务,但如果想使用守护进程,你可以在 linux 系统中使用 gunicorn 来部署服务。
uvicorn server.cls_server:app --host 0.0.0.0 --port 7860
在启动服务的同时,我们可以在客户端 server/cls_client.py
调用该端口:
python server/cls_client.py
不仅如此,我还提供了 webui 的图形化界面用于方便展示,你可以运行运行如下命令启动该服务,接着按照提示打开对应的网址即可
python server/cls_webui.py
5.2 命名实体识别(序列标注)
5.2.1 数据标注
一般来说,我们会先进行文本分类,然后再进行序列标注,因为文本分类和序列标注有一些相似之处,我们在分类好数据后,就可以得到需要进行命名实体识别的数据,例如 地名、姓名和机构名等。这里为了方便演示,仍然采用电影评论数据集,并抽取出评论里面的姓名和地址,因为命名实体识别的标注比较复杂,因此我们采用专业的标注工具 label-studio 来进行标注。
首先我们需要安装 label-studio(该 python 包与 gradio 有冲突,可新建一个conda环境再安装):
pip install label-studio
接着即可在终端中启动它:
label-studio
5.2.2 微调
我们首先需要拆分数据集:
python process/ner/split.py \
--label_path datasets/电影评论序列标注模型/label_studio序列标注.csv \
--train_path datasets/电影评论序列标注模型/train.tsv \
--dev_path datasets/电影评论序列标注模型/dev.tsv \
--label2id_path datasets/电影评论序列标注模型/label2id.json \
--id2label_path datasets/电影评论序列标注模型/id2label.json
接着即可开始训练模型:
python finetune/run_ner.py \
--pretrained_model_path corpora/电影评论/new_pretrain_model.bin-500 \
--output_model_path datasets/电影评论序列标注模型/finetuned_model.bin \
--train_path datasets/电影评论序列标注模型/train.tsv \
--dev_path datasets/电影评论序列标注模型/dev.tsv \
--label2id_path datasets/电影评论序列标注模型/label2id.json \
--epochs_num 32 --batch_size 32
5.2.3 模型推理
首先需要将模型转换为 huggingface 格式:(需要修改模型文件中的 config.json
文件)
python scripts/convert_bert_token_classification_from_uer_to_huggingface.py \
--input_model_path datasets/电影评论序列标注模型/finetuned_model.bin \
--output_model_path datasets/电影评论序列标注模型/ner_model/pytorch_model.bin
接着我们再将该float32精度的模型降低精度到int8,这样可以提升模型的推理速度,但又不影响模型的效果:
python process/ner/quantization.py \
--model_path datasets/电影评论序列标注模型/ner_model \
--model_path_q datasets/电影评论序列标注模型/ner_model_q
然后我们就可以调用量化后的模型了:
python server/ner.py
5.2.4 模型部署
你可以运行如下命令以用于启动实体识别模型的服务,但如果想使用守护进程,你可以在 linux 系统中使用 gunicorn 来部署服务。
uvicorn server.ner_server:app --host 0.0.0.0 --port 7860
在启动服务的同时,我们可以在客户端调用该端口:
python server/ner_client.py
5.3 文本相似度
5.3.1 数据标注
首先获取所有句子的组合:
python process/sts/pair.py \
--clean_path corpora/电影评论/已清洗数据.csv \
--pair_path datasets/电影评论相似度模型/pair.csv
接着我们就可以对组合的句子对来进行标注,其中 1 表示相似,0 则表示不相似。最终得到的标注文件为datasets/电影评论相似度模型/人工标注数据.csv
5.3.2 微调
将增量预训练的模型转换为 huggingface 格式:
python scripts/convert_bert_from_uer_to_huggingface.py \
--input_model_path corpora/电影评论/new_pretrain_model.bin-500 \
--output_model_path datasets/电影评论相似度模型/new_pretrain_model/pytorch_model.bin \
--type mlm
然后即可进行模型训练:
python finetune/run_sts.py \
--csv_path datasets/电影评论相似度模型/人工标注数据.csv \
--pretrain_model_path datasets/电影评论相似度模型/new_pretrain_model \
--output_model_path datasets/电影评论相似度模型/sts_model \
--epoch_num 32 --batch_size 32
5.3.3 模型推理
python server/sts.py
5.3.4 模型部署
uvicorn server.sts_server:app --host 0.0.0.0 --port 7860
python server/sts_client.py
6 其他脚本
将 xlsx 文件转换为 csv 文件:
python process/xlsx2csv.py \
--xlsx_path datasets/电影评论相似度模型/人工标注数据.xlsx \
--csv_path datasets/电影评论相似度模型/人工标注数据.csv
将 csv 文件转换为 tsv 文件:
python process/csv2tsv.py \
--csv_path corpora/电影评论/已清洗数据.csv \
--tsv_path datasets/电影评论分类模型/test_nolabel.tsv
评论