小样本UIE 信息抽取微调快速上手(不含doccona标注)
知其然也知其所以然,能到快速上手阶段,肯定已经了解了UIE的一些相关介绍,这里仅从偏实践角度,简短剖析一下任务细节,具体介绍可参照官方github。UIE(Universal Information Extraction) 针对少样本、低资源、不同领域等场景,实现从非结构化文本中抽取结构化信息,包含了实体识别、关系抽取、事件抽取、情感分析、评论抽取等任务。该任务的亮点在于:(1)将多任务的信息抽取
文章目录
1.安装环境(可略过)
模型快速复现的基本思路,只要两步,一是安装环境,二是跑模型。
安装GPU版本的paddlepaddle看参照此博客,如果不幸地,你报错缺少libcudart动态库文件,请参照此博客解决环境安装问题,毕竟安装环境是AIer不可逾越的鸿沟。
2.模型简介(略读)
知其然也知其所以然,能到快速上手阶段,肯定已经了解了UIE的一些相关介绍,这里仅从偏实践角度,简短剖析一下任务细节,具体介绍可参照官方github。
UIE(Universal Information Extraction) 针对少样本、低资源、不同领域等场景,实现从非结构化文本中抽取结构化信息,包含了实体识别、关系抽取、事件抽取、情感分析、评论抽取等任务。
该任务的亮点在于:
(1)将多任务的信息抽取统一为一个抽取模板
(2)基于结构化生成的预训练模型,可以实现少样本、跨领域的模型微调,且能够达到工业级可应用的SOTA效果。
统一模板可结合UIE整体框架来理解,如下图所示。
其底座是基于T5模型预训练的,多任务模型那就少不了prompt,这个prompt设计也非常巧妙,把prompt提示抽象成两种类别,Spotting进行实体识别,Associating进行关系类别识别,那么格式化就是:[spot] 实体类别 [asso] 关系类别 [text]。与实体识别、关系抽取、事件抽取任务联系起来,实体识别、事件触发词识别以及事件论元识别就是在做Spotting操作,找取目标信息片段,关系抽取、事件论元与事件触发词之间的关系是做Associating操作,寻找目标信息片段之间的关系。
对于不同的抽取任务只要给出统一的schema,那么该任务就会自动将其组装为prompt喂给模型,进行Spotting、Associating操作。
抽取任务输入输出示例:
1.实体识别
from pprint import pprint>>> from paddlenlp import Taskflow
schema = [‘时间’, ‘选手’, ‘赛事名称’] # Define the schema for entity extraction
ie = Taskflow(‘information_extraction’, schema=schema)
pprint(ie(“2月8日上午北京冬奥会自由式滑雪女子大跳台决赛中中国选手谷爱凌以188.25分获得金牌!”)) # Better print results using pprint
[{‘时间’: [{‘end’: 6,
‘probability’: 0.9857378532924486,
‘start’: 0,
‘text’: ‘2月8日上午’}],
‘赛事名称’: [{‘end’: 23,
‘probability’: 0.8503089953268272,
‘start’: 6,
‘text’: ‘北京冬奥会自由式滑雪女子大跳台决赛’}],
‘选手’: [{‘end’: 31,
‘probability’: 0.8981548639781138,
‘start’: 28,
‘text’: ‘谷爱凌’}]}]
2.关系抽取
schema = {‘竞赛名称’: [‘主办方’, ‘承办方’, ‘已举办次数’]} # Define the schema for relation extraction
ie.set_schema(schema) # Reset schema
pprint(ie(‘2022语言与智能技术竞赛由中国中文信息学会和中国计算机学会联合主办,百度公司、中国中文信息学会评测工作委员会和中国计算机学会自然语言处理专委会承办,已连续举办4届,成为全球最热门的中文NLP赛事之一。’))
[{‘竞赛名称’: [{‘end’: 13,
‘probability’: 0.7825402622754041,
‘relations’: {‘主办方’: [{‘end’: 22,
‘probability’: 0.8421710521379353,
‘start’: 14,
‘text’: ‘中国中文信息学会’},
{‘end’: 30,
‘probability’: 0.7580801847701935,
‘start’: 23,
‘text’: ‘中国计算机学会’}],
‘已举办次数’: [{‘end’: 82,
‘probability’: 0.4671295049136148,
‘start’: 80,
‘text’: ‘4届’}],
‘承办方’: [{‘end’: 39,
‘probability’: 0.8292706618236352,
‘start’: 35,
‘text’: ‘百度公司’},
{‘end’: 72,
‘probability’: 0.6193477885474685,
‘start’: 56,
‘text’: ‘中国计算机学会自然语言处理专委会’},
{‘end’: 55,
‘probability’: 0.7000497331473241,
‘start’: 40,
‘text’: ‘中国中文信息学会评测工作委员会’}]},
‘start’: 0,
‘text’: ‘2022语言与智能技术竞赛’}]}]
以上的两个任务可以直接利用paddlenlp的Taskflow直接输出结果,这是预训练模型通用的抽取任务,输出效果也不错。Taskflow可理解为paddle为是产业实践研发的任务框架,包含数据的预处理、模型推理、后处理等任务执行所遵循的框架。细分场景中一般需要一定的标注数据进行微调,才能保证一个较好的抽取效果。
3.快速上手(主菜)
项目中代码结构,如果不修改模型,不部署,仅微调的话,仅用到doccano.py、finetune.py、evaluate.py就足够了。
├── utils.py # 数据处理工具
├── model.py # 模型组网脚本
├── doccano.py # 数据标注脚本
├── doccano.md # 数据标注文档
├── finetune.py # 模型微调、压缩脚本
├── evaluate.py # 模型评估脚本
└── README.md
(1)转换数据
将自己的数据直接转化为doccona标注后的数据示例(这里的转换程序需要自己写一个,毕竟我也不知道你的原始数据长什么样,只用转换成跟标注数据样例一样的格式就行),为什么不直接转换为喂给模型的训练、验证数据,因为官方提供了转换脚本,里面包含正负样例构造、shuffle以及划分训练、验证、测试集,非常方便。
标注数据样例
{"id": 1, "text": "昨天晚上十点加班打车回家58元", "relations": [], "entities": [{"id": 0, "start_offset": 0, "end_offset": 6, "label": "时间"}, {"id": 1, "start_offset": 11, "end_offset": 12, "label": "目的地"}, {"id": 2, "start_offset": 12, "end_offset": 14, "label": "费用"}]}
{"id": 2, "text": "三月三号早上12点46加班,到公司54", "relations": [], "entities": [{"id": 3, "start_offset": 0, "end_offset": 11, "label": "时间"}, {"id": 4, "start_offset": 15, "end_offset": 17, "label": "目的地"}, {"id": 5, "start_offset": 17, "end_offset": 19, "label": "费用"}]}
注:我刚开始纠结该示例任务的schema = [‘出发地’, ‘目的地’, ‘费用’, ‘时间’],有的示例数据没有“目的地”无法定位offset怎么办?
看了示例数据后,就不纠结了。
标注数据,没有的实体类别项,忽略不记录就行。
因为转换为训练数据集的时候,每个示例是根据类别分别转换的,如第一条数据,会转化为抽取"时间"类别数据,抽取"目的地"类别数据,抽取"费用"类别数据的3条数据,"出发地"类别就不用管,因为输入的text也没有提及"出发地"类别。
(2)生成训练数据
经过doccona标注后的数据样例,通过doccona.py进行转换,生成训练集、验证集、测试集,命令如下所示。
python doccano.py \
--doccano_file ./data/doccano_ext.json \
--save_dir ./data \
--splits 0.8 0.1 0.1
训练数据样例
{"content": "出租车从酒店到公司一共34元时间是10月21日", "result_list": [{"text": "10月21日", "start": 17, "end": 23}], "prompt": "时间"}
{"content": "二零一九年十一月十三日晚上十点三十四分加班打车回家,四十三元", "result_list": [{"text": "家", "start": 24, "end": 25}], "prompt": "目的地"}
{"content": "月五号凌晨0点08分打车回家三十点五元", "result_list": [{"text": "家", "start": 13, "end": 14}], "prompt": "目的地"}
(3)微调训练
因为我有多张显卡,一开始想用多卡并行微调训练,没想到还需要安装一个ncll2,果断放弃,选择单卡也能微调,且速度挺快。总共100多条标注数据,生成训练集600多条数据,10多分钟就训练完了。
注意,我修改的参数,–device gpu:8 指定了特定的gpu,batch_size改为了8,因为显卡内存被别程序占用,8才能跑起来。
微调命令如下所示:
python finetune.py \
--device gpu:8 \
--logging_steps 5 \
--save_steps 25 \
--eval_steps 25 \
--seed 42 \
--model_name_or_path uie-base \
--output_dir ./checkpoint/model_best \
--train_path data/train.txt \
--dev_path data/dev.txt \
--max_seq_len 512 \
--per_device_train_batch_size 8 \
--per_device_eval_batch_size 8 \
--num_train_epochs 10 \
--learning_rate 1e-5 \
--do_train \
--do_eval \
--do_export \
--export_model_dir ./checkpoint/model_best \
--overwrite_output_dir \
--disable_tqdm True \
--metric_for_best_model eval_f1 \
--load_best_model_at_end True \
--save_total_limit 1
(4)评估模型
注意模型评估的时候,evaluate.py在定义“–device”参数的时候添加了一个,*choices=[“gpu”, “cpu”, “npu”]*限制,将其注释掉就能随意指定GPU卡了。
python evaluate.py \
--device gpu:8 \
--model_path ./checkpoint/model_best \
--test_path ./data/test1.txt \
--max_seq_len 512 \
--batch_size 8
(5)采用模型进行推理
嵌入进下面一段代码,就可以对模型进行推理预测,或者封装接口、部署。
from pprint import pprint
from paddlenlp import Taskflow
input_text = " " # 输入你需要预测的文本
schema = ['开票日期', '名称', '纳税人识别号', '开户行及账号', '金额', '价税合计', 'No', '税率', '地址、电话', '税额']
my_ie = Taskflow("information_extraction", model="uie-x-base", schema=schema, task_path='./checkpoint/model_best', precision='fp16')
pprint(myie(input_text))
参考:
[1].https://mp.weixin.qq.com/s/lL950H9T7UFsJRopuWQ59w
[2].https://github.com/PaddlePaddle/PaddleNLP/blob/develop/model_zoo/uie/README.md#%E6%A8%A1%E5%9E%8B%E5%BE%AE%E8%B0%83
更多推荐
所有评论(0)