直接使用
请打开基于EasyNLP的RoBERTa中文文本匹配,并点击右上角 “ 在DSW中打开” 。
基于EasyNLP的RoBERTa中文文本匹配
EasyNLP是阿里云PAI算法团队基于PyTorch开发的易用且丰富的NLP算法框架( https://github.com/alibaba/EasyNLP ),支持常用的中文预训练模型和大模型落地技术,并且提供了从训练到部署的一站式NLP开发体验。EasyNLP提供多种模型的训练及预测功能,旨在帮助自然语言开发者方便快捷地构建模型并应用于生产。
本文以文本匹配为例,为您介绍如何在PAI-DSW中基于EasyNLP快速使用RoBERTa进行中文文本匹配模型的构建、训练、评估、预测。
关于RoBERTa
RoBERTa是2019年7月由FaceBook(现为META)AI研究院提出的一种基于BERT改进的预训练语言表征模型,全称是Robustly Optimized BERT pretraining Approach。与BERT一样,RoBERTa也采用Transformer encoder结构。不过它在BERT的基础上增加了额外的训练数据、改进了预训练策略,从而获得了更强有力的预训练语言模型。这使得其在自然语言理解(NLU)任务中的性能表现显著强于BERT。
运行环境要求
建议用户使用:Python 3.6,Pytorch 1.8镜像,GPU机型 P100 or V100,内存至少为 32G
EasyNLP安装
建议从GitHub下载EasyNLP源代码进行安装,命令如下:
! git clone https://github.com/alibaba/EasyNLP.git ! pip install -r EasyNLP/requirements.txt ! cd EasyNLP && python setup.py install
您可以使用如下命令验证是否安装成功:
! which easynlp
如果您系统内已经安装完easynlp的CLI工具,则说明EasyNLP代码库已经安装。
数据准备
首先,您需要进入指定模型目录,下载用于本示例的训练和测试集,并创建保存模型的文件夹,命令如下:
! cd examples/appzoo_tutorials/text_match/single_tower ! wget http://atp-modelzoo.oss-cn-hangzhou.aliyuncs.com/release/tutorials/ez_text_match/afqmc_public/train.csv ! wget http://atp-modelzoo.oss-cn-hangzhou.aliyuncs.com/release/tutorials/ez_text_match/afqmc_public/dev.csv
训练和测试数据都是以\t隔开的.csv文件,数据下载完成后,可以通过以下代码查看前5条数据。每行为一个数据,每列为一个字段值,包括需要进行文本匹配的两个句子,以及对应的匹配结果标签。
print('Training data sample:') ! head -n 5 train.csv print('Development set data sample:') ! head -n 5 dev.csv
初始化
在Python 3.6环境下,我们首先从刚刚安装好的EasyNLP中引入模型运行需要的各种库,并做一些初始化。在本教程中,我们使用chinese-roberta-wwm-ext。EasyNLP中集成了丰富的预训练模型库,如果想尝试其他预训练模型,如bert、albert等,也可以在user_defined_parameters中进行相应修改,具体的模型名称可见模型列表。
# 为了避免EasyNLP中的args与Jupyter系统的冲突,需要手动设置,否则无法进行初始化。 # 在命令行或py文件中运行文中代码则可忽略下述代码。 import sys sys.argv = ['main.py']
import torch.cuda from easynlp.appzoo import SingleTowerDataset from easynlp.appzoo import get_application_predictor, get_application_model, get_application_evaluator, get_application_model_for_evaluation from easynlp.core import Trainer, PredictorManager from easynlp.utils import initialize_easynlp, get_args, get_pretrain_model_path from easynlp.utils.global_vars import parse_user_defined_parameters initialize_easynlp() args = get_args() user_defined_parameters = parse_user_defined_parameters('pretrain_model_name_or_path=hfl/chinese-roberta-wwm-ext loss_type=hinge_loss margin=0.45 gamma=32 embedding_size=256') args.checkpoint_dir = "./text_match_single_tower_model_dir"
注意:上述代码如果出现“Address already in use”错误,则需要运行以下代码清理端口上正在执行的程序。 netstat -tunlp|grep 6000 kill -9 PID (需要替换成上一行代码执行结果中对应的程序ID)
载入数据
我们使用EasyNLP中自带的SingleTowerDataset,对训练和测试数据进行载入。主要参数如下:
- pretrained_model_name_or_path:预训练模型名称路径,这里我们使用封装好的get_pretrain_model_path函数,来处理模型名称"hfl/chinese-roberta-wwm-ext"以得到其路径,并自动下载模型
- max_seq_length:文本最大长度,超过将截断,不足将padding
- input_schema:输入csv数据的格式,逗号分隔的每一项对应数据文件中每行以\t分隔的一项,每项开头为其字段标识,如label、sent1、sent2等
- first_sequence、second_sequence、label_name:用于说明input_schema中哪些字段用于作为输入句子对和标签列等
- label_enumerate_values:label类型列举
- is_training:是否为训练过程,train_dataset为True,valid_dataset为False
train_dataset = SingleTowerDataset( pretrained_model_name_or_path=get_pretrain_model_path("hfl/chinese-roberta-wwm-ext"), data_file="train.csv", max_seq_length=128, input_schema="example_id:str:1,sent1:str:1,sent2:str:1,label:str:1,cate:str:1,score:str:1", first_sequence="sent1", second_sequence="sent2", label_name="label", label_enumerate_values="0,1", is_training=True) valid_dataset = SingleTowerDataset( pretrained_model_name_or_path=get_pretrain_model_path("hfl/chinese-roberta-wwm-ext"), data_file="dev.csv", max_seq_length=128, input_schema="example_id:str:1,sent1:str:1,sent2:str:1,label:str:1,cate:str:1,score:str:1", first_sequence="sent1", second_sequence="sent2", label_name="label", label_enumerate_values="0,1", is_training=False)
由于之前我们选用了hfl/chinese-roberta-wwm-ext,因此这里也会对预训练模型进行自动下载并载入。
模型训练
处理好数据与模型载入后,我们开始训练模型。 我们使用EasyNLP中封装好的get_application_model函数进行训练时的模型构建,其参数如下:
- app_name:任务名称,这里选择文本匹配"text_match"
- pretrained_model_name_or_path:预训练模型名称路径,这里我们使用封装好的get_pretrain_model_path函数,来处理模型名称"hfl/chinese-roberta-wwm-ext"以得到其路径,并自动下载模型
- num_labels:类别个数,本例中数据集为二分类数据集
- user_defined_parameters:用户自定义参数,直接填入刚刚处理好的自定义参数user_defined_parameters
model = get_application_model(app_name="text_match", pretrained_model_name_or_path=get_pretrain_model_path("hfl/chinese-roberta-wwm-ext"), num_labels=2, user_defined_parameters=user_defined_parameters)
从日志中可以看出,我们对预训练模型的参数进行了载入。下一步我们使用EasyNLP中的Train类创建训练实例,并进行训练。
trainer = Trainer(model=model, train_dataset=train_dataset, evaluator=get_application_evaluator(app_name="text_match", valid_dataset=valid_dataset, eval_batch_size=32, user_defined_parameters=user_defined_parameters)) trainer.train()
模型评估
训练过程结束后,train好的模型被我们保存在一开始指定好的checkpoint_dir中,本地路径为"./text_match_single_tower_model_dir/"。我们可以对train好的模型进行效果评估。我们同样先使用EasyNLP中的get_application_model_for_evaluation方法构建评估模型。
model = get_application_model_for_evaluation(app_name="text_match", pretrained_model_name_or_path="./text_match_single_tower_model_dir/", user_defined_parameters=user_defined_parameters)
之后我们使用EasyNLP中的get_application_evaluator来初始化evaluator,并指定当前device下的当前模型,进行模型评估。
evaluator = get_application_evaluator(app_name="text_match", valid_dataset=valid_dataset, eval_batch_size=32, user_defined_parameters=user_defined_parameters) model.to(torch.cuda.current_device()) evaluator.evaluate(model=model)
模型预测
我们同样可以使用训练好的模型进行文本分类的预测。我们首先创建一个predictor,并据此实例化一个PredictorManager实例。我们指定预测好的结果输出在"dev.pred.csv",并指定输出格式为"predictions,probabilities,logits,output"。
predictor = get_application_predictor(app_name="text_match", model_dir="./text_match_single_tower_model_dir", first_sequence="sent1", second_sequence="sent2", sequence_length=128, user_defined_parameters=user_defined_parameters) predictor_manager = PredictorManager(predictor=predictor, input_file="dev.csv", input_schema="example_id:str:1,sent1:str:1,sent2:str:1,label:str:1,cate:str:1,score:str:1", output_file="dev.pred.csv", output_schema="predictions,probabilities,logits,output", append_cols="label", batch_size=32) predictor_manager.run() exit()
一步执行
值得一提的是,上述所有训练/评估/预测代码,都已经被集成在EasyNLP/examples/appzoo_tutorials/text_match/single_tower/main.py中,此外,我们也预先编写好了多种可供直接执行的脚本。用户可以通过带参数运行main.py中指令,或者直接使用bash文件命令行执行的方式,一步执行上述所有训练/评估/预测操作。
main文件一步执行
用户通过以下代码带参数执行main.py中的指令,可直接对模型进行训练/评估/预测操作。
训练代码指令如下。参数中,tables指定了训练集和验证集csv文件的路径,input_schema表示csv的数据格式,first_sequence、second_sequence和label_name用于说明input_schema中哪些字段用于作为输出和标签列,label_enumerate_values列举了所有的标签。 模型存储的路径位于checkpoint_dir,learning_rate、epoch_num、random_seed、save_checkpoint_steps、sequence_length和micro_batch_size为训练的超参数。在本示例中,预训练模型指定为bert-base-uncased。
! python main.py \ --mode train \ --tables=train.csv,dev.csv \ --input_schema=example_id:str:1,sent1:str:1,sent2:str:1,label:str:1,cate:str:1,score:str:1 \ --first_sequence=sent1 \ --second_sequence=sent2 \ --label_name=label \ --label_enumerate_values=0,1 \ --checkpoint_dir=./text_match_single_tower_model_dir \ --learning_rate=3e-5 \ --epoch_num=30 \ --random_seed=42 \ --save_checkpoint_steps=100 \ --sequence_length=128 \ --train_batch_size=32 \ --app_name=text_match \ --user_defined_parameters=' pretrain_model_name_or_path=hfl/chinese-roberta-wwm-ext loss_type=hinge_loss margin=0.45 gamma=32 embedding_size=256
评估代码如下,参数含义与训练是一致的。
! python main.py \ --mode evaluate \ --worker_gpu=1 \ --tables=dev.csv \ --input_schema=example_id:str:1,sent1:str:1,sent2:str:1,label:str:1,cate:str:1,score:str:1 \ --first_sequence=sent1 \ --second_sequence=sent2 \ --label_name=label \ --label_enumerate_values=0,1 \ --checkpoint_dir=./text_match_single_tower_model_dir \ --sequence_length=128 \ --train_batch_size=32 \ --app_name=text_match \ --user_defined_parameters=' pretrain_model_name_or_path=hfl/chinese-roberta-wwm-ext loss_type=hinge_loss margin=0.45 gamma=32 embedding_size=256 '
预测代码如下。参数同样与上面保持一致,输出结果可在dev.pred.tsv中查看。
! python main.py \ --mode predict \ --worker_gpu=1 \ --tables=dev.csv \ --outputs=dev.pred.csv \ --input_schema=example_id:str:1,sent1:str:1,sent2:str:1,label:str:1,cate:str:1,score:str:1 \ --output_schema=predictions,probabilities,logits,output \ --first_sequence=sent1 \ --second_sequence=sent2 \ --label_name=label \ --label_enumerate_values=0,1 \ --checkpoint_dir=./text_match_single_tower_model_dir \ --sequence_length=128 \ --train_batch_size=32 \ --app_name=text_match \ --user_defined_parameters=' pretrain_model_name_or_path=hfl/chinese-roberta-wwm-ext loss_type=hinge_loss margin=0.45 gamma=32 embedding_size=256 '
利用bash文件命令行执行
我们在EasyNLP/examples/appzoo_tutorials/text_match/single_tower/文件夹下封装好了多种可直接执行的bash脚本,用户同样可以通过使用bash文件命令行执行的方式来一步完成模型的训练/评估/预测。以下以run_train_eval_predict_user_defined_local.sh脚本为例。该bash文件需要传入两个参数,第一个参数为运行程序的GPU编号,一般为0;第二个参数代表模型的训练/评估/预测。
模型训练:
! bash run_train_eval_predict_user_defined_local.sh 0 train
模型评估:
! bash run_train_eval_predict_user_defined_local.sh 0 evaluate
模型预测:
! bash run_train_eval_predict_user_defined_local.sh 0 predict