科大讯飞大赛 事件抽取挑战赛冠军分享

赛题名称:科大讯飞事件抽取挑战赛

赛题链接:http://challenge.xfyun.cn/topic/info?type=hotspot

赛题类型:NLP、事件抽取

文章内容:冠军思路+代码分享

事件抽取系统,包含触发词(trigger),事件论元(role),事件属性(attribution)的抽取。基于 Pytorch 的 pipeline 解决方案。

赛题介绍

赛题背景

事件抽取将非结构化文本中的事件信息展现为结构化形式,在舆情监测、文本摘要、自 动问答、事理图谱自动构建等领域有着重要应用。在真实新闻中,由于文本中可能存在句式 复杂,主被动转换,多事件主客体共享等难点,因此“事件抽取”是一项极具挑战的抽取任 务。

赛事任务

本赛事任务旨在从通用新闻文本中抽取事件触发词、事件论元以及事件属性。在传统的事件定义中,事件由事件触发词( Trigger) 和描述事件结构的元素 (Argument)构成。事件触发词标识着事件的发生。事件论元为事件主体(Subject)、客体(Object)、时间(Time)、地点(Location)等,是表达事件重要信息的载体。

事件属性包括事件极性(Polarity)、时态(Tense),是衡量事件是否真实发生的重要依据。通过极性,事件分为肯定、否定、可能事件。通过时态,事件分为过去发生的事件、现在正 在发生的事件、将要发生的事件以及其他无法确定时态的事件。

本赛事任务一为初赛任务,任务二为复赛任务,在任务一的基础上增加了事件属性识别。为 了模拟真实场景,数据中包含了非实际发生的事件。

  • 任务一:事件触发词及论元抽取

该任务旨在从文本中抽取标识事件发生的触发词和论元,触发词往往为动词和名词。触发词 对应的事件论元,主要为主体、客体、时间、地点,其中主体为必备论元。

  • 任务二:事件属性抽取

该任务旨在从文本中抽取表达事件发生状态的属性,包括极性、时态。极性分为:肯定、否定、可能;时态分为:过去、现在、将来、其他。

评审规则

  1. 初赛数据说明:本次比赛初赛为参赛选手提供了6958条中文句子,及其9644条提取结果(存在一对多的情况)。

  2. 复赛数据说明:本次比赛复赛为参赛选手提供了3335条中文句子,及其3384条提取结果(存在一对多的情况):

  3. 评价指标:本模型依据提交的结果文件,采用F值进行评价。

冠军思路

将任务分割为触发词抽取论元抽取属性抽取。具体而言是论元和属性的抽取结果依赖于触发词,因此只有一步误差传播。

因 time loc 并非每个句子中都存在,并且分布较为稀疏,因此将 time & loc 与 sub & obj 的抽取分开(role1 提取 sub & obj;role2 提取 time & loc)

模型先进行触发词提取,由于复赛数据集的特殊性,模型限制抽取的事件仅有一个,如果抽取出多个触发词,选择 logits 最大的 trigger 作为该句子的触发词,如果没有抽取触发词,筛选整个句子的 logits,取 argmax 来获取触发词;

然后根据触发词抽取模型抽取的触发词,分别输入到 role1 & role2 & attribution 模型中,进行后序的论元提取和属性分类;四种模型都是基于 Roberta-wwm 进行实验,加入了不同的特征。最后将识别的结果进行整合,得到提交文件。

pipeline 思路

trigger 提取器:

trigger 提取采用的特征是远程监督 trigger,把所有标注数据当做一个知识库,对当前文本进行匹配。

注:在训练时,需要排除自身的label,我们采用的是KFold的训练集 distant trigger 构造,即将训练集分成K份,用前K-1份的所有label当做后一份的知识库,构造训练数据的distant trigger;test 时候采用所有 trigger。

在测试时若出现预测为空,选取 distant trigger logits 最大的解码输出 trigger。

具体模型如下:

role 提取器

role 采用的特征是trigger的相对距离,然后采用了苏神的 Conditional Layer Norm 来让整个句子融入 trigger 信息,同样采用 Span 解码的方式。

由于数据中 subject/object 分布相似,同时与 time/loc 分布相差很大,我们进一步进行了优化,将前两者和后两者的抽取分开,防止 time/loc 的数据对 subject/object 的 logits 稀疏化。

attribution 分类器

attribution 分类器并没有进行特殊优化,采用了一个动态窗口的方法,我们认为某一 trigger 的 tense & polarity 只与其附近的语境有关。

因此我们设定了一个窗口,对该窗口内进行 pooling 操作,然后利用 pooling 后的 logits 进行多任务学习,同时分类出 tense 和 polarity。因属性数据类别不均及其严重,最后我们用 ERNIE 模型做了一个10折交叉验证,有较大的提升。

数据增强

本次比赛主要的上分点在于数据增强的工作,初赛和复赛数据的分布差别极大,一起训练反而会导致结果下降。

因此我们做了一个初赛数据筛选的工作,筛选出与复赛数据分布相近的数据进行增量训练。主要流程详见PPT中基于标签验证的数据增强部分

项目运行主要环境

运行系统:

Ubuntu 18.04.4
python3.7

python 运行环境,可以通过以下代码完成依赖包安装:

pip install -r requirements.txt
transformers==2.10.0
pytorch_crf==0.7.2
numpy==1.16.4
torch==1.5.1+cu101
tqdm==4.46.1
scikit_learn==0.23.2
torchcrf==1.1.0

CUDA:

CUDA Version: 10.2  Driver 440.100 GPU:Tesla V100 (32G) * 2

项目目录说明

xf_ee
├── data                                    # 数据文件夹
│   ├── final                               # 复赛数据(处理过的)
│   │   ├── mid_data                        # 中间数据 (词典等)
│   │   ├── preliminary_clean               # 清洗后的初赛数据
│   │   └── raw_data                        # 复赛经过初步清洗后的 raw_data
│   └── preliminary                         # 初赛数据(略)

├── out                                     # 存放训练的模型
│   ├── final                               # 复赛各个单模型(trigger/role/attribution)
│   └── stack                               # 十折交叉验证的 attribution 模型

├── script/final                            # 放训练 / 评估 / 测试 的脚本
│   ├── train.sh                            
│   ├── dev.sh                     
│   └── test.sh                

├── src_final
│   ├── features_analysis                   # 数据分析
│   │   └── images                          # 分析时画得一些图 
│   ├── preprocess                       
│   │   ├── convert_raw_data.py             # 处理转换原始数据
│   │   ├── convert_raw_data_preliminary.py     # 转换初赛数据为复赛格式并处理
│   │   └── processor.py                    # 转换数据为 Bert 模型的输入
│   ├── utils                      
│   │   ├── attack_train_utils.py           # 对抗训练 FGM / PGD
│   │   ├── dataset_utils.py                # torch Dataset
│   │   ├── evaluator.py                    # 模型评估
│   │   ├── functions_utils.py              # 跨文件调用的一些 functions
│   │   ├── model_utils.py                  # 四个任务的 models
│   │   ├── options.py                      # 命令行参数
│   |   └── trainer.py                      # 训练器
|
├── 答辩PPT                                 # 决赛PPT
├── dev.py                                  # 用于模型评估
├── ensemble_predict.py                     # 用百度 ERNIE 模型对 attribution 十折交叉验证
├── predict_preliminary.py                  # 对初赛数据进行清洗
├── readme.md                               # ...
├── test.py                                 # pipeline 预测复赛数据 (包含 ensemble)
└── train.py                                # 模型训练

使用说明

数据转换

数据转换部分只提供代码和已经转换好的数据,具体操作在 src_final/preprocess中的 convert_raw_data中,包含对初赛/复赛数据的清洗和转换。

训练阶段

bash ./script/final/train.sh

注:脚本中指定的 BERT_DIR 指BERT所在文件夹,BERT采用的是哈工大的全词覆盖wwm模型,下载地址 https://github.com/ymcui/Chinese-BERT-wwm ,自行下载并制定对应文件夹,并将 vocab.txt 中的两个 unused 改成 [INV] 和 [BLANK](详见 processor 代码中的 fine_grade_tokenize)

如果设备显存不够,自行调整 train_batch_size,脚本中的 batch_size(32)在上述环境中占用显存为16G

最终训练的结果是每一个 epoch 下存一次,线下评估结果在 eval_metric.txt 下,保留最优线下结果作为训练结果,其余删掉即可

可更改的公共参数有

lr: bert 模块的学习率
other_lr: 除了bert模块外的其他学习率(差分学习率)
weight_decay:...
attack_train: 'pgd' / 'fgm' / '' 对抗训练 fgm 训练速度慢一倍, pgd 慢两倍,但是效果都有提升
swa_start: 滑动权重平均开始的epoch
trigger提取模型训练 (TASK_TYPE=“trigger”)

可更改的参数有

use_distant_trigger: 是否使用复赛数据构造的远程监督库中的 trigger 信息
role 提取模型训练 (TASK_TYPE=“role1/role2”)

可更改的参数有

use_trigger_distance: 是否使用句子中的其他词到 trigger 的距离这一个特征

attribution 分类模型训练 (TASK_TYPE=“attribution”)

未使用其他特征

MODE=“stack” 时候对 attribution 任务进行十折交叉验证,换用百度 ERNIE1.0 模型作为预训练模型

验证阶段

bash ./script/final/dev.sh

主要的参数有三个:

  • TASK_TYPE:需要验证任务的 type
  • start/end threshold :trigger / role1 model 需要进行调整的阈值
  • dev_dir: 需要验证的模型的文件夹

测试阶段

bash ./script/final/test.sh

利用训练最优的四个单模型进行 pipeline 式的预测 sentences.json 文件,获取最终的 submit 文件,

其中 submit_{version},json 为四个单模型的结果, submit_{version}ensemble,json 为单模型 + attribution 交叉验证后的结果。

四个任务 model 的上级文件夹必须指定,同时文件夹名称应包含模型的参数特征。

  • trigger_ckpt_dir:             trigger 所在的文件夹
  • role1_ckpt_dir:                role1 所在的文件夹
  • role2_ckpt_dir:                 role2 所在的文件夹
  • attribution_ckpt_dir:    attribution所在的文件夹

测试效果

classification score
submit_v1.json 0.73684
submit_v1_ensemble.json 0.73859

各阶段提升

数据增强

在我们的训练过程中,实际使用了组委会提供的初赛(经过清洗和转换)+复赛数据进行训练,在项目内部提供了清洗完毕的初赛数据;具体清洗流程如下所示:

  • 只使用复赛数据train得到trigger抽取模型和role1抽取模型(需指定model的上级文件夹)

    trigger_simple_ckpt_dir:            单独复赛数据train trigger 所在的文件夹role1_simple_ckpt_dir:              单独复赛数据train role1 所在的文件夹

  • 使用predict_prelimiary.py调用train好的trigger model 和role1 model 预测初赛数据的trigger和sub/ob

python predict_preliminary.py --dev_dir_trigger trigger_simple_ckpt_dir  --dev_dir_role role1_simple_ckpt_dir
  • 运行src_final/preprocess下的convert_raw_data_preliminary.py
python convert_raw_data_preliminary.py
  • 运行src_final/preprocess下的convert_raw_data.py 即完成了初赛数据的清洗
python convert_raw_data.py

由于微信平台算法改版,公号内容将不再以时间排序展示,如果大家想第一时间看到我们的推送,强烈建议星标我们和给我们多点点【在看】。星标具体步骤为:

(1)点击页面最上方'AINLP',进入公众号主页。

(2)点击右上角的小点点,在弹出页面点击“设为星标”,就可以啦。

感谢支持,比心

欢迎加入预竞赛技术交流群
(0)

相关推荐