当前位置:   article > 正文

信息抽取(四)【NLP论文复现】Multi-head Selection和Deep Biaffine Attention在关系抽取中的实现和效果_关系抽取论文复现

关系抽取论文复现


前言

最近在磕一人之力,刷爆三路榜单!信息抽取竞赛夺冠经验分享这篇文章,文章对关系抽取任务的解码方式做了简单的概述,在之前的文章中本人已经实现了指针标注网络,并对其进了优化(详情见改良后的层叠式指针网络,让我的模型F1提升近4%),因此这次把文中提到的多头选择和Biaffine关系矩阵构建的原论文拿出来研究了一下,并根据实际的关系抽取任务做了复现和改良。

本文主要涉及以下论文:

多头选择与关系抽取:
Joint entity recognition and relation extraction as a multi-head selection problem

Bert版多头选择:
BERT-Based Multi-Head Selection for Joint Entity-Relation Extraction

双仿射注意力机制:
Deep Biaffine Attention for Neural Dependency Parsing(基于深层双仿射注意力的神经网络依存解析)

新论文,采取Biaffine机制构造Span矩阵:
Named Entity Recognition as Dependency Parsing

本文只是记录自己的思考和实现,只对每篇论文核心部分做简单理解,可能有错误,感兴趣的同学建议直接看原文。


Multi-head Selection

一、Joint entity recognition and relation extraction as a multi-head selection problem

该网络结构将实体识别和关系抽取 joint 在一起,先通过在隐藏层上连接CRF,来抽取实体标签,并将实体标签信息embedding后与隐藏层一起传递给sigmoid_layer,来与其他实体特征进行交互抽取关系。
实体抽取部分比较好理解,对于多头选择部分,以下原文的几条核心公式:

理解如下:
当Token(j)为Subject的End 且 Token(i)为Object的End的概率分数为

非常简明的意思是:将Token(j)和Token(i)的Z(隐藏层➕label embedding)分别经过U,W线性变换后相加再加上偏置b,最后再进行一次整体线性变换V,得到的值经过sigmoid函数后即转换为对应的概率分数。
别急!后文会讨论多类别关系时,各个矩阵的维度关系。

二、BERT-Based Multi-Head Selection for Joint Entity-Relation Extraction

Bert + Multi-head Selection,除了引入了Bert作为编码层外,其他创新点如下:

  1. 考虑在训练时我们可以通过传入真实的实体标签的embedding给Multi-head Selection层,但在模型推理时,为了利用CRF的softmax在各个标签上产生的分值信息和考虑到推理时可能产生的错误标签结果,作者将softmax结果与各个标签的embedding进行加权后传给Multi-head Selection层。
  1. 引入句子级关系分类任务来指导特征学习,如图中的用CLS来获得稳定的维度特征。(关于这一改进我并没有进行尝试,还不是因为没有数据!因此持有怀疑态度,原本就将两个任务的解码压力放在一组encoder上,现在又增加了句子分类任务。这不会加大模型压力吗?文中给出的实验结果表明,单独增加Global predicate Prediction并没有带来明显的提升,而组合各种策略能带来的较高提升不一定是该方法的贡献。)
  1. Soft label embedding of the ith token hi is feed into two separate fully connected layers to get the subject representation hsi and object representation hoi. where f(·) means neural network, ri,j is the relation when the ith token is subject and the jth token is object, rj,i is the relation when the jth token is subject and the ith token is object.(论文原文,多头选择方法与上文相同,将构建好的token特征通过两个不同的全连接层后经过一个F网络输出两者的关系分值)

三、实现方法和模型代码展示

以三元关系抽取任务为例,我们多头选择该如何更好的理解和应用?功夫不负有心人我找大了夕大姐文章里一张图虽然和多头选择没多少关系,但能比较形象的展示Multi-head Selection的流程:

对于一个句子中的所有的token形成的SO组合,一共有N2种。假设我们的Token都已经经过了线性变化或者全连接层的洗礼,如图中对于每一个City,我们将其作为S,我们应该考虑其他所有token是否能和它形成SO关系,所以我们要计算每一个token和city经过V变换后的分数。

具体实现上也非常简单,我们可以构建一个NNHidden_size的token组合矩阵,经过一个P_num(关系类别总数)的Dense层后即可得到各个token之间在各个关系上的分值。

Subject = tf.keras.layers.Dense(hidden_size)(Encode)
Object = tf.keras.layers.Dense(hidden_size)(Encode)
'''
将原token的encode经过两个不同的全连接层后,得到Subject,Object两个token序列
对应公式中的 U*zj 和 W*zi
'''
Subject = tf.expand_dims(Subject,1)
#TensorShape([batch_size, 1, MAX_LEN, hidden_size])
Object = tf.expand_dims(Object,2)
#TensorShape([batch_size, MAX_LEN, 1, hidden_size])
Subject = tf.tile(Subject,multiples=(1,MAX_LEN,1,1))
#TensorShape([batch_size, MAX_LEN, MAX_LEN, hidden_size])
Object = tf.tile(Object,multiples=(1,1,MAX_LEN,1))
#TensorShape([batch_size, MAX_LEN, MAX_LEN, hidden_size])
concat_SO = tf.keras.layers.Concatenate(axis=-1)([Subject,Object])
#TensorShape([batch_size, MAX_LEN, MAX_LEN, 2*hidden_size])
output_logist = tf.keras.layers.Dense(P_num,activation='sigmoid')(concat_SO)
#TensorShape([batch_size, MAX_LEN, MAX_LEN, P_num])
'''
将组合后的 U*zj 与 W*zi 经过一个V全连接层,V.shape = (2*hidden_size,P_num)
对应公式中的 V*U*zj + V*W*zi = V(U*zj + W*zj + b)
'''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

样本构建部分: 我们需要将一个标注好的[ MAX_LEN, MAX_LEN, P_num ]的矩阵作为Multi-Head Selection 结果的 Y值。

关于样本标注问题:

  1. 一个实体包含多个字符且可能存在实体嵌套的问题,如“我是歌手的主演是阿瓜”,需要抽取的关系为“我是歌手的主演是阿瓜”、“阿瓜是歌手”。

  2. 我们并不需要将“我是歌手”的四个token和“阿瓜”的两个token在P=主演的得分上全都标注为1,因为在实体抽取部分我们对实体的头和尾进行了识别,我们仅需要将 S“手”和O“瓜”所对应的P=主演的分值标注为1即可。本例中即 [3,9,indenx of 主演] = 1即可。如果阿瓜还是个歌手,则 [9,3,indenx of 职业] = 1即可,因为对于不同类型的嵌套的实体,可能存在尾字符相同的情况极少,因此我们标注尾字符而不是首字符。

以上就是Multi-head Selection Model部分的核心思路和代码。

完整模型代码如下:

  1. 用bert代替了原文的LSTM编码层。
  2. 这里将CRF替换为指针标注,并引入了实体的类别信息。
  3. 将实体的硬标签与实体的end_token拼接后传入Multi-head Selection层,这也是本人灵光一闪的部分,既然在Multi-head Selection层我们希望model能识别S的end_token和O的end_token, 我们就只给这两个token传入有效的实体标签信息,其余token类别都编码为0即可,实验正面这确实比你对所有的SOtoken都传入对应的实体类别embedding效果更好。
  4. 没有使用上文的软标签,软标签的具体实现可以通过自定义 layer 实现。
def build_model(pretrained_path,config,MAX_LEN,Cs_num,cs_em_size,R_num):
    ids = tf.keras.layers.Input((MAX_LEN,), dtype=tf.int32)
    att = tf.keras.layers.Input((MAX_LEN,), dtype=tf.int32)
    cs = tf.keras.layers.Input((MAX_LEN,), dtype=tf.int32)
    
    config.output_hidden_states = True
    bert_model = TFBertModel.from_pretrained(pretrained_path,config=config,from_pt=True)
    x, _, hidden_states = bert_model(ids,attention_mask=att)
    layer_1 = hidden_states[-1]
    
    start_logits = tf.keras.layers.Dense(Cs_num,activation = 'sigmoid')(layer_1)
    start_logits = tf.keras.layers.Lambda(lambda x: x**2,name='s_start')(start_logits)
    
    end_logits = tf.keras.layers.Dense(Cs_num,activation = 'sigmoid')(layer_1)
    end_logits = tf.keras.layers.Lambda(lambda x: x**2,name='s_end')(end_logits)
    
    cs_emb = tf.keras.layers.Embedding(Cs_num
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/469590
推荐阅读
相关标签
  

闽ICP备14008679号