直接使用
请打开基于EasyNLP的BERT文本分类,并点击右上角 “ 在DSW中打开” 。
基于EasyNLP的BERT文本分类
EasyNLP是阿里云PAI算法团队基于PyTorch开发的易用且丰富的NLP算法框架( https://github.com/alibaba/EasyNLP ),支持常用的中文预训练模型和大模型落地技术,并且提供了从训练到部署的一站式NLP开发体验。EasyNLP提供多种模型的训练及预测功能,旨在帮助自然语言开发者方便快捷地构建模型并应用于生产。
本文以文本分类为例,为您介绍如何在PAI-DSW中基于EasyNLP快速使用BERT进行文本匹配模型的训练、评估、预测。
关于BERT
BERT是2018年10月由Google AI研究院提出的一种预训练语言表征模型,全称是Bidirectional Encoder Representation from Transformers。与当前许多广泛应用于NLP领域的模型一样,BERT也采用Transformer encoder结构,不过相比传统方法中只使用单向语言模型、或把两个单向语言模型进行浅层拼接来预训练,BERT采用新的masked language model(MLM),以生成深度的双向语言表征。作为当前NLP领域最常用的模型之一,BERT刚提出时便在11种不同的NLP任务中创造出SOTA表现,成为NLP发展史上的里程碑式的模型成就。
运行环境要求
建议用户使用: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/sequence_classification/bert_classify ! wget http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/classification/train.tsv ! wget http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/classification/dev.tsv
训练和测试数据都是以\t隔开的.tsv文件,数据下载完成后,可以通过以下代码查看前5条数据。每行为一个数据,每列为一个字段值,包括需要进行文本分类的句子,以及对应的类别标签。
print('Training data sample:') ! head -n 5 train.csv print('Development set data sample:') ! head -n 5 dev.csv
初始化
在Python 3.6环境下,我们首先从刚刚安装好的EasyNLP中引入模型运行需要的各种库,并做一些初始化。在本教程中,我们使用最基础的BERT模型:bert-base-uncased。EasyNLP中集成了丰富的预训练模型库,如果想尝试其他预训练模型,如bert-large、albert等,也可以在user_defined_parameters中进行相应修改,具体的模型名称可见模型列表。
# 为了避免EasyNLP中的args与Jupyter系统的冲突,需要手动设置,否则无法进行初始化。 # 在命令行或py文件中运行文中代码则可忽略下述代码。 import sys sys.argv = ['main.py']
import torch.cuda from easynlp.appzoo import ClassificationDataset 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=bert-base-uncased') args.checkpoint_dir = "./classification_model/"
注意:上述代码如果出现“Address already in use”错误,则需要运行以下代码清理端口上正在执行的程序。 netstat -tunlp|grep 6000 kill -9 PID (需要替换成上一行代码执行结果中对应的程序ID)
载入数据
我们使用EasyNLP中自带的ClassificationDataset,对训练和测试数据进行载入。主要参数如下:
- pretrained_model_name_or_path:预训练模型名称路径,这里我们使用封装好的get_pretrain_model_path函数,来处理模型名称"bert-base-uncased"以得到其路径,并自动下载模型
- max_seq_length:文本最大长度,超过将截断,不足将padding
- input_schema:输入tsv数据的格式,逗号分隔的每一项对应数据文件中每行以\t分隔的一项,每项开头为其字段标识,如label、sent1等
- first_sequence、label_name:用于说明input_schema中哪些字段用于作为输入句子和标签列等
- label_enumerate_values:label类型列举
- is_training:是否为训练过程,train_dataset为True,valid_dataset为False
train_dataset = ClassificationDataset( pretrained_model_name_or_path=get_pretrain_model_path("bert-base-uncased"), data_file="train.tsv", max_seq_length=128, input_schema="label:str:1,sid1:str:1,sid2:str:1,sent1:str:1,sent2:str:1", first_sequence="sent1", second_sequence="sent2", label_name="label", label_enumerate_values="0,1", user_defined_parameters=user_defined_parameters, is_training=True) valid_dataset = ClassificationDataset( pretrained_model_name_or_path=get_pretrain_model_path("bert-base-uncased"), data_file="dev.tsv", max_seq_length=128, input_schema="label:str:1,sid1:str:1,sid2:str:1,sent1:str:1,sent2:str:1", first_sequence="sent1", second_sequence="sent2", label_name="label", label_enumerate_values="0,1", is_training=False)
由于之前我们选用了bert-base-uncased,因此这里也会对预训练模型进行自动下载并载入。
模型训练
处理好数据与模型载入后,我们开始训练模型。 我们使用EasyNLP中封装好的get_application_model函数进行训练时的模型构建,其参数如下:
- app_name:任务名称,这里选择文本分类"text_classify"
- pretrained_model_name_or_path:预训练模型名称路径,这里我们使用封装好的get_pretrain_model_path函数,来处理模型名称"bert-base-uncased"以得到其路径,并自动下载模型
- num_labels:类别个数,本例中数据集为二分类数据集
- user_defined_parameters:用户自定义参数,直接填入刚刚处理好的自定义参数user_defined_parameters
model = get_application_model(app_name="text_classify", pretrained_model_name_or_path=get_pretrain_model_path("bert-base-uncased"), num_labels=2, user_defined_parameters=user_defined_parameters)
从日志中可以看出,我们对预训练模型的参数进行了载入。下一步我们使用EasyNLP中的Train类创建训练实例,并进行训练。
trainer = Trainer(model=model, train_dataset=train_dataset, user_defined_parameters=user_defined_parameters, evaluator=get_application_evaluator(app_name="text_classify", valid_dataset=valid_dataset, user_defined_parameters=user_defined_parameters, eval_batch_size=32)) trainer.train()
出现如下日志,代表训练结束:
模型评估
训练过程结束后,train好的模型被我们保存在一开始指定好的checkpoint_dir中,本地路径为"./classification_model/"。我们可以对train好的模型进行效果评估。我们同样先使用EasyNLP中的get_application_model_for_evaluation方法构建评估模型。
model = get_application_model_for_evaluation(app_name="text_classify", pretrained_model_name_or_path="./classification_model/", user_defined_parameters=user_defined_parameters)
之后我们使用EasyNLP中的get_application_evaluator来初始化evaluator,并指定当前device下的当前模型,进行模型评估。
evaluator = get_application_evaluator(app_name="text_classify", valid_dataset=valid_dataset, user_defined_parameters=user_defined_parameters, eval_batch_size=32) model.to(torch.cuda.current_device()) evaluator.evaluate(model=model)
模型预测
我们同样可以使用训练好的模型进行文本分类的预测。我们首先创建一个predictor,并据此实例化一个PredictorManager实例。我们指定预测好的结果输出在"dev.pred.tsv",并指定输出格式为"predictions,probabilities,logits,output"。
predictor = get_application_predictor(app_name="text_classify", model_dir="./classification_model/", first_sequence="sent1", second_sequence="sent2", sequence_length=128, user_defined_parameters=user_defined_parameters) predictor_manager = PredictorManager(predictor=predictor, input_file="dev.tsv", input_schema="label:str:1,sid1:str:1,sid2:str:1,sent1:str:1,sent2:str:1", output_file="dev.pred.tsv", output_schema="predictions,probabilities,logits,output", append_cols="label", batch_size=32) predictor_manager.run() exit()
一步执行
值得一提的是,上述所有训练/评估/预测代码,都已经被集成在EasyNLP/examples/appzoo_tutorials/sequence_classification/bert_classify/main.py中,此外,我们也预先编写好了多种可供直接执行的脚本。用户可以通过带参数运行main.py中指令,或者直接使用bash文件命令行执行的方式,一步执行上述所有训练/评估/预测操作。
main文件一步执行
用户通过以下代码带参数执行main.py中的指令,可直接对模型进行训练/评估/预测操作。
训练代码指令如下。参数中,tables指定了训练集和验证集tsv文件的路径,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.tsv,dev.tsv \ --input_schema=label:str:1,sid1:str:1,sid2:str:1,sent1:str:1,sent2:str:1 \ --first_sequence=sent1 \ --second_sequence=sent2 \ --label_name=label \ --label_enumerate_values=0,1 \ --checkpoint_dir=./classification_model \ --learning_rate=3e-5 \ --epoch_num=3 \ --random_seed=42 \ --save_checkpoint_steps=50 \ --sequence_length=128 \ --micro_batch_size=32 \ --app_name=text_classify \ --user_defined_parameters='pretrain_model_name_or_path=bert-base-uncased'
评估代码如下,参数含义与训练是一致的。
! python main.py \ --mode evaluate \ --tables=dev.tsv \ --input_schema=label:str:1,sid1:str:1,sid2:str:1,sent1:str:1,sent2:str:1 \ --first_sequence=sent1 \ --second_sequence=sent2 \ --label_name=label \ --label_enumerate_values=0,1 \ --checkpoint_dir=./classification_model \ --sequence_length=128 \ --micro_batch_size=32 \ --app_name=text_classify
预测代码如下。参数同样与上面保持一致,输出结果可在dev.pred.tsv中查看。
! python main.py \ --mode predict \ --tables=dev.tsv \ --outputs=dev.pred.tsv \ --input_schema=label:str:1,sid1:str:1,sid2:str:1,sent1:str:1,sent2:str:1 \ --output_schema=predictions,probabilities,logits,output \ --append_cols=label \ --first_sequence=sent1 \ --second_sequence=sent2 \ --checkpoint_path=./classification_model \ --micro_batch_size=32 \ --sequence_length=128 \ --app_name=text_classify
利用bash文件命令行执行
我们在EasyNLP/examples/appzoo_tutorials/sequence_classification/bert_classify/文件夹下封装好了多种可直接执行的bash脚本,用户同样可以通过直接使用bash文件命令行执行的方式来一步完成模型的训练/评估/预测。以下以run_train_eval_predict_appzoo_cli_local.sh脚本为例。该bash文件需要传入两个参数,第一个参数为运行程序的GPU编号,一般为0;第二个参数代表模型的训练/评估/预测。
模型训练:
! bash run_train_eval_predict_appzoo_cli_local.sh 0 train
模型评估:
! bash run_train_eval_predict_appzoo_cli_local.sh 0 evaluate
模型预测:
! bash run_train_eval_predict_appzoo_cli_local.sh 0 predict