本文为李弘毅老师【Deep Learning for Question Answering (2/2)】的课程笔记,课程视频youtube地址,点这里👈(需翻墙)。
下文中用到的图片均来自于李宏毅老师的PPT,若有侵权,必定删除。
文章索引:
上篇 - 7-10 Deep Learning for Question Answering (1/2)
下篇 - 7-12 Controllable Chatbot
1 Simple Question: Match & Extract
Simple Question指的就是可以从给定的source中通过Match和Extract的方法找到答案的问题。比如SQuAD中的问题就是Simple Question。下图中的第一个问题,我们可以通过"precipitation"和"fall"这两个关键词定位到答案在source中的第一句话中(Match),然后从中抽取出答案"gravity"(Extract)。
解决这样的问题的模型架构如下图所示,通常被称为"Query-to-context Attention"。我们自底向上来看,首先我们会把source输入到"module for source"中,然后输出每个token对应的embedding,这里每个token会输出两个embedding,一个相当于attention中的key,另一个相当于attention中的value。同时,也会把问题输入到"module for answer"中,得到一个embedding,这个就相当于attention中的query。我们会把右下角得到的黄色的query和左下角得到的蓝色的key进行match,归一化后,每个绿色的value会得到一个权重。加权求和得到上方深蓝色的特征向量,将其输入到"module for answer"当中,得到最终的结果。如果答案只有一个token,就是一个分类问题;如果答案是其中的一串span,那就预测头尾token的位置。
这种架构最经典的模型就是2015年的End-To-End Memory Networks。
上面的架构可以做一个变形。就是当"module for question"输出的embedding有多个的时候,也就是有多个query的时候,我们该怎么办?我们可以把每个query和key去做一个match,那样每个value就会得到多个权重,我们取其中最大的那个就可以了。
这种方法的一个典型例子就是2016年的Ask, Attend and Answer: Exploring Question-Guided
Spatial Attention for Visual Question Answering。
还有一种架构,叫做"context-to-query attention"。这种attention是把source每个token对应的embedding当作query,question每个token对应的embedding当作key,然后这两者做attention。最后会得到一个向量,再把这个向量和query时的attention结合,变成下图中绿色的向量,每个蓝色的token都会得到一个绿色的向量,然后把所有绿色的向量输入"module for answer"中,得到答案。
上图的架构在实际操作时,可能还会对context做self-attention,比较经典的有Gated Self-Matching Networks for Reading Comprehension and Question Answering
那么query-to-context和context-to-query这两者到底是谁好呢?既然分不清楚,我们不妨两者都用。Bidirectional Attention Flow for Machine Comprehension, Dynamic Coattention Networks
For Question Answerin,QANet: Combining Local Convolution
with Global Self-Attention for Reading Comprehension这几篇文章都是两者都用的。
不过在今天看来,上面讲到的一切,BERT里都有了,这也是BERT强大的原因,我们只要一个BERT就够了。
2 Complex Question: Reasoning
complex question的问题在今天看来也是一个尚未找到合适的办法的问题,所以这里只是大概介绍一下什么是complex question以及现有的解决办法。
complex question和simple question的区别在于,simple question的答案必然在source的某一段话中可以直接找到,而complex question需要在多个source之间反复跳跃,综合多个信息来得出答案。Qangaroo就是一个complex question的数据集。比如下面图中的这个问题是问"Hanging gardens of Mumbai"在哪个国家,根据第一个source只能知道在"Arabian Sea",但Arabian Sea并不是国家,我们还要再根据后面的source才能知道在India。
属于complex question的数据集还有Hoppot QA,DROP等等。其中的一些问题甚至需要机器根据source的内容去做加减乘除的操作。
这种在source之间跳来跳去的做法可以表示成下图这样。先根据问题match到一句话,然后根据extract的内容更新query,再进行一次match和extract以及更新,直到找到我们需要的答案为止。一般跳几次是人为预先设定好的超参数。
在网络架构中,就可以表示成下图这样。source中的每个token可以变成两个embedding(蓝和橙),分别表示key和value。用query的embedding去做attention,结合之前的query得到新的query。如此反复,反复次数由人预先设定。
当然也有让模型自己去学习要跳多少次的模型,可参见ReasoNet。
这种跳跃的方式非常适合用图网络来做,于是也有人做了用图网络来解决complex question的尝试,可参见 Dynamically Fused Graph Network for Multi-hop Reasoning。但也有人发现,当在训练时,把BERT也进行finetune时,用不用图网络的效果时差不多的,因为BERT里的self-attention就是一个密集的图网络,可参见Is Graph Structure Necessary for Multi-hop Reasoning?。
3 Dialogue QA
Dialogue QA与之前两类问题的区别在于,Dialogue QA会会有多个连续的问题,当前问的问题会需要用到之前问的问题的信息,比较典型的有CoQA。答案必然是在source当中的。
也有问问题的人完全没有看过source的情况,这种情况下,可能就会问到一些没有答案的问题,可参见QuAC。
解这类问题的时候,问题的embedding通常需要对之前的问题的embedding也做attention。
目前针对Dialogue QA各个模型在SQuAD上的效果如下图所示,最上面一行时人类的表现,下面的时排名前5的模型的表现,可以看见前5的模型都超过了人类。但是,模型真的已经这么厉害了吗?
事实并非如此,模型的泛化能力非常差,在SQuAD上训练的模型,在bAbI上的表现非常差。
甚至有人发现,当把问题从"What did Tesla spend Astor’s money on"缩减为"did"时,模型竟然也能答对,而且置信度还变高了。可见模型并不是真正学到了语义,只是训练集和验证集的分布很像,模型学到了某个分布而已。
当有人把训练集和验证集的分布改了一下之后,模型就惨败了。
看来在研究QA的地方,人类还有很长的路要走。