直接使用
请打开基于CK-BERT的中文序列标注,并点击右上角 “ 在DSW中打开” 。
基于CK-BERT的中文序列标注
序列标注(Sequence Labeling)是NLP中较为基础的任务,应用十分广泛,如分词,词性标注(Part-of-speech tagging),命名实体识别(Named Entity Recognition,NER),关键词抽取(Keywords extraction),语义角色标注(Semantic Role Labeling,SRL)等。它的目标是对给定序列中的文本单元进行打标,以获取文本单元的额外信息。CK-BERT(Revisiting and Advancing Chinese Natural Language Understanding with Accelerated Heterogeneous Knowledge Pre-training)是由Alibaba-EasyNLP团队自研的中文预训练模型,结合了两种知识类型(外部知识图谱,内部语言学知识)对模型进行知识注入,同时使得知识注入的方式方便模型可扩展。
在EasyNLP中,我们提供了中文版CK-BERT,以便用户能够受益于模型强大的建模能力。本文将以命名实体识别任务为例,将CK-BERT作为模型底座构建NER模型,展示如何利用EasyNLP进行模型构建、训练、评估、预测。
运行环境要求
PAI-Pytorch 1.7/1.8镜像, GPU机型 P100 or V100, 内存 16/32G
EasyNLP安装
建议从GitHub下载EasyNLP源代码进行安装,命令如下:
! echo y | pip uninstall pai-easynlp easynlp ! git clone https://github.com/alibaba/EasyNLP.git ! pip install -r EasyNLP/requirements.txt -i http://mirrors.aliyun.com/pypi/simple ! cd EasyNLP && python setup.py install
安装完成easynlp之后,建议重启notebook,防止环境存在缓存,未更新
您可以使用如下命令验证是否安装成功:
import easynlp easynlp.__file__
/home/pai/bin/easynlp
如果您系统内已经安装完easynlp的CLI工具,则说明EasyNLP代码库已经安装。
数据准备
首先,您需要下载用于本示例的训练和测试集,并创建保存模型的文件夹,命令如下:
! wget http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/sequence_labeling/train.csv ! wget http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/sequence_labeling/dev.csv
--2022-10-14 06:12:18-- http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/sequence_labeling/train.csv Resolving atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com... 47.101.88.27 Connecting to atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com|47.101.88.27|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 2565663 (2.4M) [text/csv] Saving to: ‘train.csv’ train.csv 100%[===================>] 2.45M 12.4MB/s in 0.2s 2022-10-14 06:12:18 (12.4 MB/s) - ‘train.csv’ saved [2565663/2565663] --2022-10-14 06:12:19-- http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/sequence_labeling/dev.csv Resolving atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com... 47.101.88.27 Connecting to atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com|47.101.88.27|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 1109771 (1.1M) [text/csv] Saving to: ‘dev.csv’ dev.csv 100%[===================>] 1.06M --.-KB/s in 0.09s 2022-10-14 06:12:19 (12.3 MB/s) - ‘dev.csv’ saved [1109771/1109771]
数据下载完成后,可以通过以下代码查看前5条数据。其中,每一行为一条数据,包括需要进行命名实体识别的句子以及对应每个字的标签,可以根据字的标签组合成完整的命名实体标签。比如。在验证数据集dev.csv中,'中 共 中 央'对应的标签为B-ORG I-ORG I-ORG I-ORG。B-ORG表示组织名起始位,I-ORG表示组织名中间位或结尾位,组合起来表示‘中共中央’是一个组织名称。
print('Training data sample:') ! head -n 5 train.csv print('Development set data sample:') ! head -n 5 dev.csv
Training data sample: 当 希 望 工 程 救 助 的 百 万 儿 童 成 长 起 来 , 科 教 兴 国 蔚 然 成 风 时 , 今 天 有 收 藏 价 值 的 书 你 没 买 , 明 日 就 叫 你 悔 不 当 初 ! O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O 藏 书 本 来 就 是 所 有 传 统 收 藏 门 类 中 的 第 一 大 户 , 只 是 我 们 结 束 温 饱 的 时 间 太 短 而 已 。 O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O 因 有 关 日 寇 在 京 掠 夺 文 物 详 情 , 藏 界 较 为 重 视 , 也 是 我 们 收 藏 北 京 史 料 中 的 要 件 之 一 。 O O O B-LOC O O B-LOC O O O O O O O O O O O O O O O O O O O O B-LOC I-LOC O O O O O O O O O 我 们 藏 有 一 册 1 9 4 5 年 6 月 油 印 的 《 北 京 文 物 保 存 保 管 状 态 之 调 查 报 告 》 , 调 查 范 围 涉 及 故 宫 、 历 博 、 古 研 所 、 北 大 清 华 图 书 馆 、 北 图 、 日 伪 资 料 库 等 二 十 几 家 , 言 及 文 物 二 十 万 件 以 上 , 洋 洋 三 万 余 言 , 是 珍 贵 的 北 京 史 料 。 O O O O O O O O O O O O O O O O O B-LOC I-LOC O O O O O O O O O O O O O O O O O O O O O B-LOC I-LOC O B-LOC I-LOC O B-ORG I-ORG I-ORG O B-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC O B-LOC I-LOC O B-LOC O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O B-LOC I-LOC O O O 以 家 乡 的 历 史 文 献 、 特 定 历 史 时 期 书 刊 、 某 一 名 家 或 名 著 的 多 种 出 版 物 为 专 题 , 注 意 精 品 、 非 卖 品 、 纪 念 品 , 集 成 系 列 , 那 收 藏 的 过 程 就 已 经 够 您 玩 味 无 穷 了 。 O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O O Development set data sample: 中 共 中 央 致 中 国 致 公 党 十 一 大 的 贺 词 B-ORG I-ORG I-ORG I-ORG O B-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG O O O 各 位 代 表 、 各 位 同 志 : O O O O O O O O O O 在 中 国 致 公 党 第 十 一 次 全 国 代 表 大 会 隆 重 召 开 之 际 , 中 国 共 产 党 中 央 委 员 会 谨 向 大 会 表 示 热 烈 的 祝 贺 , 向 致 公 党 的 同 志 们 O B-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG O O O O O O O B-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG I-ORG O O O O O O O O O O O O O B-ORG I-ORG I-ORG O O O O 致 以 亲 切 的 问 候 ! O O O O O O O O 在 过 去 的 五 年 中 , 致 公 党 在 邓 小 平 理 论 指 引 下 , 遵 循 社 会 主 义 初 级 阶 段 的 基 本 路 线 , 努 力 实 践 致 公 党 十 大 提 出 的 发 挥 参 政 党 职 能 、 加 强 自 身 建 设 的 基 本 任 务 。 O O O O O O O O B-ORG I-ORG I-ORG O B-PER I-PER I-PER O O O O O O O O O O O O O O O O O O O O O O O O O O B-ORG I-ORG I-ORG I-ORG I-ORG O O O O O O O O O O O O O O O O O O O O O O O
初始化
在Python 3.6环境下,我们首先从刚刚安装好的EasyNLP中引入模型运行需要的各种库,并做一些初始化。在本教程中,我们使用pai-ck_bert-base-zh。EasyNLP中集成了丰富的预训练模型库,如果想尝试其他预训练模型,如bert、albert等,可以在user_defined_parameters中进行相应修改,具体的模型名称可见模型列表。
# 为了避免EasyNLP中的args与Jupyter系统的冲突,需要手动设置,否则无法进行初始化。 # 在命令行或py文件中运行文中代码则可忽略下述代码。 import sys sys.argv = ['main.py']
import torch.cuda from easynlp.appzoo import SequenceLabelingDataset from easynlp.appzoo import get_application_predictor, get_application_model, get_application_evaluator from easynlp.appzoo import get_application_model_for_evaluation from easynlp.core import PredictorManager from easynlp.core import Trainer 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 = "pretrain_model_name_or_path=alibaba-pai/pai-ck_bert-base-zh" user_defined_parameters = parse_user_defined_parameters(user_defined_parameters) # 保存位置 args.checkpoint_dir = "./seq_labeling/" # 训练批次 args.train_batch_size = 8 args.micro_batch_size = 8
注意:上述代码如果出现“Address already in use”错误,则需要运行以下代码清理端口(默认为6000)上正在执行的程序。
netstat -tunlp|grep 6000
kill -9 PID (需要替换成上一行代码执行结果中对应的程序ID)
载入数据
我们使用EasyNLP中自带的ClassificationDataset,对训练和测试数据进行载入。主要参数如下:
- pretrained_model_name_or_path:预训练模型名称路径,这里我们使用封装好的get_pretrain_model_path函数,来处理模型名称”chinese-roberta-wwm-ext”,并自动下载模型
- max_seq_length:文本最大长度,超过将截断,不足将padding
- input_schema:输入数据的格式,逗号分隔的每一项对应数据文件中每行以\t分隔的一项,每项开头为其字段标识,如label、sent1等
- first_sequence、label_name:用于说明input_schema中哪些字段用于作为输入句子和标签列等
- label_enumerate_values:label类型列举
- is_training:是否为训练过程,train_dataset为True,valid_dataset为False
- app_name:指定当前需要执行的任务,如文本分类、序列标注、文本匹配等
下面我们将手动设置一些参数以便进行实验
args.tables = "./train.csv,./dev.csv" args.input_schema = "content:str:1,label:str:1" args.first_sequence = "content" args.label_name = "label" args.label_enumerate_values = "B-LOC,B-ORG,B-PER,I-LOC,I-ORG,I-PER,O" args.learning_rate = 3e-5 args.epoch_num = 1 args.save_checkpoint_steps = 50 args.sequence_length = 128 args.micro_batch_size = 32 args.app_name = "sequence_labeling" args.pretrained_model_name_or_path = user_defined_parameters.get('pretrain_model_name_or_path', None) args.pretrained_model_name_or_path = get_pretrain_model_path(args.pretrained_model_name_or_path) train_dataset = SequenceLabelingDataset( pretrained_model_name_or_path=args.pretrained_model_name_or_path, data_file=args.tables.split(",")[0], max_seq_length=args.sequence_length, input_schema=args.input_schema, first_sequence=args.first_sequence, label_name=args.label_name, label_enumerate_values=args.label_enumerate_values, is_training=True) valid_dataset = SequenceLabelingDataset( pretrained_model_name_or_path=args.pretrained_model_name_or_path, data_file=args.tables.split(",")[-1], max_seq_length=args.sequence_length, input_schema=args.input_schema, first_sequence=args.first_sequence, label_name=args.label_name, label_enumerate_values=args.label_enumerate_values, is_training=False)
Trying downloading name_mapping.json Success Downloading `alibaba-pai/pai-ck_bert-base-zh` to /root/.easynlp/modelzoo/alibaba-pai/pai-ck_bert-base-zh.tgz ****./train.csv ****./dev.csv
模型训练
处理好数据与模型载入后,我们开始训练模型。 我们使用EasyNLP中封装好的get_application_model函数进行训练时的模型构建,其参数如下:
- app_name:任务名称,这里选择序列标注”sequence_labeling”
- pretrained_model_name_or_path:预训练模型名称路径,这里我们使用封装好的get_pretrain_model_path函数,来处理模型名称”chinese-roberta-wwm-ext”,并自动下载模型
- user_defined_parameters:用户自定义参数,直接填入刚刚处理好的自定义参数user_defined_parameters
构建模型并读取
model = get_application_model(app_name=args.app_name, pretrained_model_name_or_path=args.pretrained_model_name_or_path, num_labels=len(valid_dataset.label_enumerate_values), user_defined_parameters=args.user_defined_parameters)
构建训练器并训练
trainer = Trainer(model=model, train_dataset=train_dataset, evaluator=get_application_evaluator(app_name=args.app_name, valid_dataset=valid_dataset, eval_batch_size=args.micro_batch_size, user_defined_parameters=user_defined_parameters)) trainer.train()
模型评估
训练过程结束后,train好的模型被我们保存在一开始指定好的checkpoint_dir中,本地路径为”./sequence_labeling/”。我们可以对训练好的模型进行效果评估。我们使用EasyNLP中的get_application_evaluator来初始化evaluator,并模型迁移至GPU机器,进行模型评估。
args.tables = "dev.csv" evaluator = get_application_evaluator(app_name=args.app_name, valid_dataset=valid_dataset, eval_batch_size=args.micro_batch_size, user_defined_parameters=user_defined_parameters) model.to(torch.cuda.current_device()) evaluator.evaluate(model=model)
模型预测
我们同样可以使用训练好的模型进行序列标注(此处为命名实体识别)。我们首先创建一个predictor,并据此实例化一个PredictorManager实例。我们指定预测好的结果输出在dev.pred.tsv。
args.tables = "dev.csv" args.outputs = "dev.pred.csv" args.output_schema = "output" args.append_cols="label" predictor = get_application_predictor( app_name=args.app_name, model_dir=args.checkpoint_dir, first_sequence=args.first_sequence, second_sequence=args.second_sequence, sequence_length=args.sequence_length, user_defined_parameters=user_defined_parameters) predictor_manager = PredictorManager( predictor=predictor, input_file=args.tables.split(",")[-1], input_schema=args.input_schema, output_file=args.outputs, output_schema=args.output_schema, append_cols=args.append_cols, batch_size=args.micro_batch_size ) predictor_manager.run()
print('Labeled samples:') ! tail -n 5 dev.csv print('Predicted results:') ! tail -n 5 dev.pred.csv
Labeled samples: 人 们 愿 意 与 他 做 生 意 , 有 时 商 业 事 务 通 过 电 话 即 可 办 理 。 O O O O O O O O O O O O O O O O O O O O O O O O O 经 过 十 几 年 的 努 力 , 他 已 成 为 世 界 最 大 的 私 人 集 装 箱 船 船 主 。 O O O O O O O O O O O O O O O O O O O O O O O O O O O 妻 贤 子 孝 家 庭 幸 福 O O O O O O O O 希 腊 人 将 瓦 西 里 斯 与 奥 纳 西 斯 比 较 时 总 不 忘 补 充 一 句 : 他 和 奥 纳 西 斯 不 同 , 他 没 有 改 组 家 庭 。 B-LOC I-LOC O O B-PER I-PER I-PER I-PER O B-PER I-PER I-PER I-PER O O O O O O O O O O O O O B-PER I-PER I-PER I-PER O O O O O O O O O O O 重 视 传 统 家 庭 观 念 的 希 腊 人 , 对 瓦 西 里 斯 幸 福 的 家 庭 充 满 赞 誉 。 O O O O O O O O O B-LOC I-LOC O O O B-PER I-PER I-PER I-PER O O O O O O O O O O Predicted results: [] O O O O O O O O O O O O O O O O O O O O O O O O O [] O O O O O O O O O O O O O O O O O O O O O O O O O O O [] O O O O O O O O [{'word': '希', 'tag': 'LOC', 'start': 0, 'end': 1}, {'word': '腊', 'tag': 'LOC', 'start': 3, 'end': 4}, {'word': '瓦', 'tag': 'PER', 'start': 12, 'end': 13}, {'word': '奥', 'tag': 'PER', 'start': 27, 'end': 28}] B-LOC I-LOC O O B-PER I-PER I-PER I-PER O B-PER I-PER I-PER I-PER O O O O O O O O O O O O O B-PER I-PER I-PER I-PER O O O O O O O O O O O [] O O O O O O O O O B-LOC I-LOC O O O B-PER I-PER I-PER I-PER O O O O O O O O O O
上面展示了数据集中的五条数据以及经过训练以后模型的预测结果。可以看出,模型对于上述样本的拟合结果较为准确。
一步执行
值得一提的是,上述所有训练/评估/预测代码,都已经被集成在EasyNLP/examples/appzoo_tutorials/sequence_labeling/main.py中,此外,我们也预先编写好了多种可供直接执行的脚本。用户可以通过带参数运行上述main.py文件,或者直接执行脚本文件run_user_defined_local.sh的方式,一步执行上述所有训练/评估/预测操作。
mian.py文件一步执行
用户通过以下代码带参数执行main.py中的指令,可直接对模型进行训练/评估/预测操作。 训练代码指令如下。具体的参数解释可见上文,此处不再赘述。
模型训练代码如下:
! python EasyNLP/examples/appzoo_tutorials/sequence_labeling/main.py \ --mode train \ --tables=./train.csv,./dev.csv \ --input_schema=content:str:1,label:str:1 \ --first_sequence=content \ --label_name=label \ --label_enumerate_values=B-LOC,B-ORG,B-PER,I-LOC,I-ORG,I-PER,O \ --checkpoint_dir=./seq_labeling/ \ --learning_rate=3e-5 \ --epoch_num=1 \ --save_checkpoint_steps=50 \ --sequence_length=128 \ --micro_batch_size=32 \ --app_name=sequence_labeling \ --user_defined_parameters='pretrain_model_name_or_path=pai-ck_bert-base-zh'
模型评估代码如下:
! python EasyNLP/examples/appzoo_tutorials/sequence_labeling/main.py \ --mode=evaluate \ --tables=dev.csv \ --input_schema=content:str:1,label:str:1 \ --first_sequence=content \ --label_name=label \ --label_enumerate_values=B-LOC,B-ORG,B-PER,I-LOC,I-ORG,I-PER,O \ --checkpoint_dir=./seq_labeling/ \ --sequence_length=128 \ --micro_batch_size=32 \ --app_name=sequence_labeling
模型预测代码如下:
! EasyNLP/examples/appzoo_tutorials/sequence_labeling/python main.py \ --mode=predict \ --tables=dev.csv \ --outputs=dev.pred.csv \ --input_schema=content:str:1,label:str:1 \ --output_schema=output \ --append_cols=label \ --first_sequence=content \ --checkpoint_path=./seq_labeling/ \ --micro_batch_size 32 \ --sequence_length=128 \ --app_name=sequence_labeling
利用bash文件命令行执行
我们在EasyNLP/examples/appzoo_tutorials/sequence_labeling/文件夹下封装好了多种可直接执行的bash脚本,用户同样可以通过使用bash文件命令行执行的方式来一步完成模型的训练/评估/预测。以下以run_train_eval_predict_appzoo_cli_local.sh脚本为例。该bash文件需要传入两个参数,第一个参数为运行程序的GPU编号,一般为0;第二个参数代表模型的训练/评估/预测。
模型训练:
! cd EasyNLP/examples/appzoo_tutorials/sequence_labeling && bash run_train_eval_predict_appzoo_cli_local.sh 0 train
模型评估:
! cd EasyNLP/examples/appzoo_tutorials/sequence_labeling && bash run_train_eval_predict_appzoo_cli_local.sh 0 evaluate
模型预测:
! cd EasyNLP/examples/appzoo_tutorials/sequence_labeling && bash run_train_eval_predict_appzoo_cli_local.sh 0 predict