瑞金知识图谱比赛总结

这个小破赛到昨天才答辩,吐槽一波(恩,好像没隔壁oppo惨,hh)

前言

涨分的应该都说了,但有些具体涨多少实在忘掉了
答辩队友没准备充分,部分答错加答漏,导致被翻盘少了两万,此处拉出来鞭尸
复赛2nd,答辩3rd

初赛

命名体识别问题,采用序列标注方式
数据特点:数据集脏,句子不易切分,句子长度方差较大,长句严重影响训练调试速度

我们初期着重点一直在如何加速调试
我们初期直接采用了sota:LSTM+CRF(不考虑外部工具及模型)
然而这个模型实在训练太慢了
0) 预处理一种是按规则切分和按行切分,按行略差3个千
1) 改模型LSTM为CuDNNGRU/CuDNNLSTM
  速度*5~10具体多少忘了,分数下降10个点(CuDNNGRU/CuDNNLSTM不支持mask zero)
2) 由于CuDNNGRU/CuDNNLSTM不支持mask zero
  实现伪mask zero(解决循环单元前传,反传无法解决),上涨8个点
3) 解决句子边缘识别太差
  sample = [sentence1,sentence2,sentence3]
  y = [y1,y2,y3]
  输入输出改成窗口为三同时输入三句话的方式,最后结果只取y2
  因为中间句sentence2没有边缘信息不足问题
  这个方式训练速度下降三倍,不用CuDNNGRU一般是跑不动的。。。
  分数上涨2-4个点
4) 添加词性词边界特征将其embedding后与字向量拼接
  上涨1-2个点
5) 将GRU容量压到最小后开始逐层调Spatial Dropout
6) 差分学习率,embedding层学习率小十倍,上涨1个点左右
7) 按行切分和按规则切分集成分数上涨0.2~0.3个点


以上是初赛的解决方案
其实线下再加一层CuDNNGRU还可以涨3-4个百分点
由于之前实验未控制好变量,得到错误结论故一直没采用
CuDNNGRU两层后速度彻底和两层GRU的速度拉开来了超多倍

初赛主要赢在让模型训练速度大幅度加倍的同时只是略降分数
使得我们可以采用很暴力的上分方式

复赛

实体对关系分类问题
数据特点:
1) 已知实体对可能关系类别,但未知是否成立
2) 数据集标签存在一定噪声(存在关系的实体对相隔太远)

核心思路
0) 实体对两两组合,并将覆盖他们的句子切出进行分类,其中过滤长度大于200的句子
1) 覆盖实体对的句子在两端各取一定长度的短句丰富上下文信息

if end - begin <= 100:
padding = 50 # window是在两边补多少词
elif end - begin <= 140:
padding = 30
else:
padding = 0

2) 特征工程
  1.实体对距离特征:这个特征原本没有用,因为句子的补0数量可以让模型捕捉到长度信息
  但是1)中的方法使得这个信息丢失,让模型不易捕捉
  2.词性特征+position embedding(每个字到实体1,2的距离),与字向量拼接
  3.实体segment特征,实体1标0.1,实体2为-0.1,其他为0,与字向量相加
    选0.1主要考虑到默认初始化的方差大小,故选择一个较小的值
    这个特征一方面是标示出实体对 yu的差异与其他字的差异
    另一方面是为了后面利用他获得实体1,2的特征向量
  4.邻近实体对存在关系的概率特征(这个好像没什么人发现)
    example:
      中国2型糖尿病防治指南(2010)在LSM和二甲双胍基础上HBA1C,≥7.O%:
      新诊断有明显体重减轻或其他严重高血糖状的患者
    我们观察到 (2型糖尿病,LSM) 是否存在关系,还与 (2型糖尿病,二甲双胍) ,(2型糖尿病,HBA1C)有关

    其实这个特征真不是看数据得到的。。
    主要是开始分fold发现不按文档分而按句子分会严重leak验证集,线上线下对不上
    既然leak了验证集,如果能利用好还是能劣势转优势的
    查找leak的原因后,观察发现文章中某些实体对强相关。
    然后用初版模型对实体对打分,将邻近实体对的分数作为特征上了不到一个百
    (前面特征用太多了,快上限了)
3) 模型
  两层GRU + SpatialDropout + attention pooling + dropout + fc + 差分学习率
4) attention (1~2个点)
  使用之前的segment标示出的实体位置,在输入的text中取出对应字向量
  并将其平均处理,再通过权重共享的全连接层将文本和字映射到同一个空间
  使用e2-(e1+text)作为相似度计算的方式(参考知识图谱的embedding算法)
  e2-(e1+text)越小权重越高
  然后用获得的attention pooling进行加权平均
5) prior mask实现独立分类器
  我们的输出非11个单元,也非1个单元的二分类
  而是输出了10个单元的二分类(即sigmoid激活,不是softmax)
  由于我们之前知道了实体对可能的类别
  故可以生成类似如下的向量
  prior mask = [0,0,0,0,0,1,0,0,0,0]
  而模型输出output = [0.1,0.9,0.5,0.4,0.3,0.2,0.1,0.5,0.6,0.7]
  output = output * prior mask = [0,0,0,0,0,0.2,0,0,0,0]
  然后用bce计算loss回传梯度
  这个方式结合了11分类与2分类的好处
  11分类会有类间干扰,2分类会导致所有类别用同一个分类器权重
6) 知识蒸馏二次训练3个千
7) 替换GRU为LSTM训练集成,3个千

最后
比赛比较懒,数据清洗方面一直懒得下功夫
模型也都是用之前的经验,懒得调试
loss也懒得动
其他队正好和我们队互补,可以参考一下他们的