引言
本文介绍指代消歧(Coreference Resolution)任务。
因为指代消歧是我们介绍的8类NLP任务的例外,所以我们这里特别拿出来探讨一下。
指代消歧
指代消歧就是找到每个代词指代的东西,比如上面的“他”指的是举起拳头的人,“它”指的就是拳头。
指代消歧还是很重要的,比如问系统,什么东西会锤倒高墙?如果是一个一般的模型,可能会回答“它”。
因此过去需要做一个指代消歧,告诉模型每个代词实际上指的是什么东西。
然后就可以把里面的代词换掉,比如把“他”换成“钟佳播”,“它”换成”钟佳播的拳头“。
这样一般的QA模型才能看得懂。
但是现在的QA模型一般直接做端到端的学习,不需要进行这种指代消歧了。
但是指代消歧还是一个比较重要的任务,其中有一个Winograd Schema Challenge希望可以取代图灵测试。
Winograd 其实是一个人,上图那个看起来像爱因斯坦的人。Winograd Schema Challenge是一个QA问题,问题是
“The trophy would not fit in the brown suitcase because it was too big. What was too big? ”
奖杯放不到行李箱里面,因为它太大了。什么太大了?
我们人类当然可以知道是奖杯太大,但是机器不太容易知道这件事。
如果换一种问法
“The trophy would not fit in the brown suitcase because it was too small. What was too small? ”
奖杯放不到行李箱里面,因为它太小了。什么太小了?
此时答案应该就是“行李箱”。
机器需要对物理世界有一定程度的立即,才能回答好这个问题。所以这件事情没有那么容易。
当你看到这句话时,其实我们能想象相关场景,并且知道有一人叫 钟佳播, 有一个人叫 乐加。
这句话说的故事里面的东西,称为mention。“钟佳播”和“乐加”以及“他”都是一个mention,如果两个mention指向同一个实体,这种现象就叫corefer。把corefer的mention找出来,就叫coreference。
所以Coreference Resolution并不仅仅要把代词和名词串起来,还要把句子里面的mention都找出来。
然后找出哪些mention指的是同样的东西。
有些mention只出现一次,这种就叫singleton。
假设有两个mention,它们有coreference的关系,先出现的那个叫antecedent(先行词),后出现的叫anaphor。
那什么东西算是mention,什么东西不算mention呢。这件事情还比较复杂,我们今天不展开叙述。
我们只定义一个Coreference任务要做什么事情。
Coreference任务要做两件事情:
(1)标注出所有的mention(通常不需要标注singleton的mention)
有时候一个mention会在另一个mention里面,比如“他的拳头”是一个mention,“他”又是另一个mention。
(2)然后这些mention会被聚类成某个类别,同一个类别的mention,表示指的是同一个实体。
这种问题要如何解决呢?看起来指代消歧有两个步骤:先侦测出哪里有mention,然后把mention进行归类。
那这两个步骤要如何用深度学习的方法解决呢,我们先来看看如何找出mention。
首先需要一个二分类器,它的输入是一个span(一串token),输出这串token是否为mention。
只要训练出一个这样的二分类器,就能检测mention了。但是这里有一个复杂之处,这个二分类器要输入一个span,而不是某个token。因为mention里面可能包含了mention。
假设你现在有一个长为 N N N的序列,那么你需要跑 N ( N − 1 ) / 2 N(N-1)/2 N(N−1)/2次,就能找到所有可能的mention。
在训练的时候,训练数据会标好哪些序列合起来是mention,把这些序列喂给二分类器,它要输出YES。
没有被标出来是mention的,它要输出NO。
第二步我们要知道哪些mention可以放到同一个类里面。
我们又要训练一个新的二分类器,它有两个输入,即两个不同的mention,它要输出这两个不同的mention是否为同一个类别。
比如输入“钟佳播”和“他”,要输出YES;把“他的拳头”和“它”输入,也要输入YES。
如果把输入”钟佳播“和”乐加“,就要输出NO。
假设第一步得到了 K K K个mention,那么第二步的分类器需要跑 K ( K − 1 ) / 2 K(K-1)/2 K(K−1)/2次。
我们知道端到端的学习的话,分成两个步骤,不能算是真正的端到端。
如果真的要做到端到端,需要把上面提到的两个分类器合成一个。
输入两个span给它,它就会输出YES或NO。
如果这两个span都是mention,并且指的是同一个实体,那么就输出YES;
反之,就输出NO。这样训练下去就可以了。我们就把上面蓝色和绿色的分类器合成了一个黄色的分类器。这就是端到端的训练。
那总共要跑这个黄色的二分类器多少次呢。
我们现在有 N N N个token,可能的span有 N ( N − 1 ) / 2 = K N(N-1)/2=K N(N−1)/2=K个。
接下来二分类器需要让这 K K K个span两两输入,需要跑 K ( K − 1 ) / 2 K(K-1)/2 K(K−1)/2次。
所以总共的时间复杂度是 O ( n 4 ) O(n^4) O(n4)。
具体的训练就是给这个分类器两个span,告诉他输入这两个span,输出是yes还是no。
在训练完这个二分类器后,我们下面来看看这个分类器实际上长什么样。
今天给你一个token序列,你首先要做的是,丢给BERT或ELMO预训练模型,把每个token变成一个嵌入向量。
接下来需要一个Span Feature Extraction模型把一个Span里面所有token的嵌入汇聚成一个嵌入。
然后有一个mention检测模型,它看一个向量,输出这个向量是否为mention,输出一个得分。
还有一个模型,它输入两个span,输出一个分数。
接下来组合这三个分数,可能是直接相加,就是你的分类器最终的输出。
如果输入的两个token的子序列它们都是mention,并且指向同一个实体,那么就要输出YES,或者输出的分数越大越好;
反之,这两者其中一个不是mention,或者没有指向同一个实体,那么就要输出NO,或者输出的分数越小越小。
就这样端到端的硬Train一发就结束了。
我们上面提到了Span Feature Extraction,我们来看一下要怎么做。
常见的做法是,假设你有一个span,里面有4个嵌入向量,然后把开头向量和结尾向量取出来,作为start和end。
接下来把这4个嵌入用另一个注意力模型计算权重,然后做加权平均,得到注意力向量。
把这三个向量串起来,就是Span Feature Extraction的输出。
这里面的注意力机制很重要,因为往往在一个mention里面,也不是每个token都重要。
比如“湖边小屋”,你可能不在意这个小屋是不是在湖边,你在意的是它是一个小屋。然后在同样的文章中,看到其他的mention,可能和房屋有关,那么你可能推测出,都是指的是小屋。
如果用注意力的方法,可能机器就会比较关注“小屋”的特征。
我们上面知道如果要用这种方法做指代消歧,运算量是 O ( n 4 ) O(n^4) O(n4),不大不小。
但是我们还是希望运算量能小一点,要怎么做呢
我们知道在训练端到端模型时,里面有一块是mention检测模型,我们其实可以先拿出这块。
先做mention检测,先跑 N ( N − 1 ) / 2 N(N-1)/2 N(N−1)/2次,先觉得是mention的部分框出来,再决定mention两两之间是否为同一个类。
即可以先得到 K K K个mention,再进行下面的处理。如果 K K K远小于 N N N,那么可以大幅减少运算量。
还有一种减少运算量的方法是限制mention的长度,假设你限制mention最长为 10 10 10,那么计算复杂度就变成了 10 n 10 n 10n。可以进一步减少mention检测的运算量。
然后我们假设得到了有 K K K个真正的mention是要去考虑的,接下来完整的模型只需要跑 K ( K − 1 ) / 2 K(K-1)/2 K(K−1)/2次。
最早在没有BERT的时代,指代消歧既可以进行端到端的训练了,那时可以用LSTM。
后来有人用了ELMo和BERT。上图的结果中小括号括出了mention,其中的颜色代表在做Span Feature Extraction的时候,注意力的权重,颜色越深,代表权重越大。
表示你的模型知道,每个文章中最重要的词汇。
刚才讲的指代消歧的模型还不够端到端,有一个更加端到端的想法是上面这样。
上面这篇文章1其实要解决的不是指代消歧的问题,而是聊天机器人和人聊天过程中,机器如何了解对话历史的问题。
比如人类问机器人:“梅西有多高”,然后机器人回答“有5英尺7英寸”。
接下来人类问“他和C罗谁是最好的球员?”
如果你的机器人是一个seq2seq模型,并且只输入了当前问题,那就很难答对这个问题。
这篇论文期待能否把上面的“他”用指代消歧的方法,换成“梅西”。
然后用另外一个模型去读了整个对话的记录,然后直接把用户的提问改写成“梅西和C罗谁是最好的球员”。
这篇文章不仅关注指代消歧的问题,他们想通用的接近对话无法考虑历史信息的问题。
比如人类输入“你最喜欢什么电影”,
机器回答“泰坦尼克”
然后人类问“为什么呢?”
这时候期望另外的模型能完善这个句子,变成“为什么最喜欢泰坦尼克?”。
你这篇文章是怎么做的呢,他们首先收集好成对的数据,比如看到上面的”他“,就要改写成”梅西“。
然后训练一个seq2seq模型,读入上面的对话记录,然后输出修改后的句子。
从指代消歧的角度看,这也许可以看成是指代消歧的一种新方法。我们知道指代消歧的目的是为了让接下来的NLP下游任务做起来更容易,把一些代词换成它真正指向的名词。我们前面介绍了一个很复杂的模型来检测哪些mention是属于同一个类别。
其实也可以做得更简单一点,我们的目的就是为了把所有的代词换成指向的名词。那我们就标一组训练数据,这组训练数据就是把代词换成真正指向的名词。然后训练一个seq2seq模型,输入是带有代词的句子,输出是把代词换成指向的名词的句子,就结束了。
这样感觉是一个比较简单的硬做指代消歧的方法。
在指代消歧里面还有很多进阶问题我们上面没有说到。一个是我们刚才在做分类的时候,其实没有真的在分类,我们是把两两mention拿出来比较,然后判断这两个mention是不是指向同样的东西,如果是的话,就放到同一个类别里面。
这里可能会遇到这样的问题,假设你在句子中已经确定了三个mention,分别是“Mr.Lee”,“Lee”和“she”。
如果你训练一个mention检测器,它可能看“Mr.Lee”和“Lee”觉得是同一个东西,看“Lee”和“she”觉得是同一个东西。但是如果把这三个mention放到一个类别里面,肯定问题。 因为“she”指代女性,而“Mr.Lee”说的是李先生。所以需要类别的层级来考虑这个结果对不对,上面列出了一个文献。
目前为止我们讲的接近指代消歧方法都是监督学习方法,那有没有可能做到无监督学习。
上面的文献提出,在做指代消歧时,直接盖住一些代词,然后用预训练的模型去决定盖住的部分应该是什么词汇。
上面盖住了“he”,而BERT擅长做的事情就是把盖住的部分补回去。然后我们看BERT补进去哪个人名。
可能BERT真的还原出了“he”,那我们可以要求BERT不能补入代词。也许这种方法就能做到指代消歧。