前言
在开放域的问答系统中,我们需要从大量的文本数据中搜索匹配我们想要的答案(或者学习文档的“信息知识”用于生成答案),而对每个问题都进行全文的数据“学习”是不现实的,因此往往依赖于高效的文本检索来选择候选段落,进而缩小目标范围。
做法往往是将模型分为两大块,首先有一个 Document Retriever,对给定的问题 question,从所有文档中检索,检索到文档后切分成段落,然后用一个称之为 Document Reader 的模块在段落中预测答案位置并给出分数,或者是进行模型的学习生成。而本文的重点就在于Retriever,如何在Retriever阶段提高检索的效率。
传统的检索模型用的较多的有TF-IDF 或 BM25算法,它们通过高效匹配关键词将问题和context表示成一个稀疏的高维度空间向量,这些算法很高效,但是不足之处在于仅仅是在词的匹配上进行检索,并未考虑语义的相关性,有很大的局限性。
所以文中从一个很直观的思路,即通过稠密且能够包含语义信息的空间向量进行表示,那么问题来了,我们怎么样在不进行额外的预训练的前提下,只是用question和passage(或answer)对来训练一个足够好的embedding model呢?论文提出了的方案非常简单,通过优化question和相关passage向量的最大化内积,目的是比较batch中所有的question和passage,这种看似简单的方法,在 top-20 文章检索准确率上却比 Lucene-BM25 系统高出 9%-19%。
模型细节
本文目标的本质在于,从大量的语料库来检索出和question最相关的一些passage。本文假设抽取式QA设置(extractive QA setting),将检索的答案限制出现在语料库中的一个或多个段落跨度内。这里我们确定一下表示符号,假设documents集合为 D = { d 1 , d 2 , . . , d D } D=\{d_1,d_2,..,d_D\} D={d1,d2,..,dD},将每个document拆分为长度相同文本段落作为基本的检索单元,假设总共获得了 M M M 个段落,则另 C = { p 1 , p 2 , . . . , p m } C=\{p_1,p_2,...,p_m\} C={p1,p2,...,pm},而每个passage p i p_i pi 可以表示为序列token { w 1 ( i ) , w 2 ( i ) , . . . , w ∣ p i ∣ ( i ) } \{w_1^{(i)},w_2^{(i)},...,w_{|p_i|}^{(i)}\} {w1(i),w2(i),...,w∣pi∣(i)}。在给定一个question q q q ,那么我们的任务就是如何从passage p i p_i pi 中找到能够回答问题的跨度序列 { w s ( i ) , w s + 1 ( i ) , . . . , w e ( i ) } \{w_s^{(i)},w_{s+1}^{(i)},...,w_{e}^{(i)}\} {ws(i),ws+1(i),...,we(i)},那么我们就可以得到retriever映射 R : ( q , C ) → C F R:(q,C)\rightarrow C_F R:(q,C)→CF,即输入question q q q 和 一个语料库 C C C,返回一个最小的匹配文本 C F ⊂ C C_F\subset C CF⊂C,其中 ∣ C F ∣ = k ≪ ∣ C ∣ |C_F|=k\ll |C| ∣CF∣=k≪∣C∣。对于给定的 k k k ,可以使用 top-k retrieval accuracy来进行evaluate。
实际模型结构很简单,使用两个独立的BERT分别对question和passage进行编码,将得到的两个表示向量进行dot-product或cosine similarity等,可以表示为如下:
论文中提到对数据构造需要注意一些地方,通常在QA数据集中,一般都会有答案所在的段落标记,这个就可以用来作为训练的正样本,但是负样本呢?似乎有很多中可选择的段落,最简单的就是把剩下的没有答案的段落作为负样本,但是有的数据集只有一个正样本段落,这个就比较麻烦。在论文中,针对这个问题,也做了一系列的实验,最后提出了一个比较好的负样本构造方法,同时也可以加速训练。
- 负样本构造方法:
- Random:从语料中随机抽取;
- BM25:使用BM25检索的不包含答案的段落;
- Gold:训练集中其他问题的答案段落
- 正样本构造方法:因为数据集如TREC, WebQuestions 和 TriviaQA中只包含问题和答案,没有段落文本,因此,论文通过BM25算法,在Wikipedia中进行检索,取top-100的段落,如果答案没有在里面,则丢掉这个问题。对于 SQuAD 和 NQ数据集,同样使用问题在Wikipedia检索,如果检索到的正样本段落能够在数据集中匹配则留下,否则丢掉。
论文选择了1个正样本和n个负样本,共 m m m 个样本,表示为 D = { ⟨ q i , p i + , p i − , . . . , p i , n − ⟩ } i = 1 m D=\{\left \langle q_i,p_i^{+},p_i^{-},...,p_{i,n}^{-} \right \rangle\}_{i=1}^m D={⟨qi,pi+,pi−,...,pi,n−⟩}i=1m,然后使用softmax损失作为loss函数,如下:
L ( q i , p i + , p i − , . . . , p i , n − ) = − l o g e s i m ( q i , p i + ) e s i m ( q i , p i + ) + ∑ j = 1 n e s i m ( q i , p i , j − ) L(q_i,p_i^{+},p_i^{-},...,p_{i,n}^{-} )=-log\frac{e^{sim(q_i,p_i^{+})}}{e^{sim(q_i,p_i^{+})+\sum_{j=1}^ne^{sim(q_i,p_{i,j}^{-})}}} L(qi,pi+,pi−,...,pi,n−)=−logesim(qi,pi+)+∑j=1nesim(qi,pi,j−)esim(qi,pi+)
其中, s i m ( q , p ) = E Q ( q ) T E P ( p ) sim(q,p)=E_Q(q)^TE_P(p) sim(q,p)=EQ(q)TEP(p)
论文中还提到一个小trick,就是in-batch negatives,怎么实施呢?假设我们一个mini-batch有 B B B 个question以及其配套的一个相关的passage,这样我们就得到了 Q Q Q 和 P P P (假设维度大小是 d d d),则矩阵大小为 B × d B\times d B×d,那么我们使用dot-product计算相似度矩阵得到 S = Q P T S=QP^T S=QPT,大小为 B × B B\times B B×B,我们怎么理解这个相似度矩阵呢?就是一个question和 B B B 个passage做内积,除了与之相对应passage视为正样本外,其余视为负样本,这样我们就在一个mini-batch内完成了正负样本的学习。
实验结果
如下图所示,DPR算法模型使用仅仅1k的数据的时候就已经全面超越了BM25算法的准确性。当训练的数据量逐渐增加时,准确性逐渐提升。当使用全量数据时,DPR算法的准确性超越了BM25算法10个点以上,top-n的数量越少,DPR算法的优势越大。
下表显示了在DPR训练时使用的训练数据源和不同的算法组合的结果。Single表示仅使用对应的数据集进行训练,Multi表示将表中的4个数据集全部加入训练。可以看到,大部分的情况下,将其他类型的问题段落数据加入训练时有利于当前数据集的准确率的。其中BM25+DPR整合的方式为: B M 25 ( q , p ) + λ ⋅ s i m ( q , p ) BM25(q,p)+\lambda\cdot sim(q,p) BM25(q,p)+λ⋅sim(q,p),其中 λ = 1.1 \lambda = 1.1 λ=1.1
IB策略即In-Batch,表示负样本是否在当前batch选取,#N标识负样本数量,得到结果如下图所示:
使用dot-product还是cosine区别不大:
如最开始提到的,DPR相对于传统的BM25检索方法,有着更好的语义理解检索:
下图是使用各检索方法得到的数据集进行QA模型训练,对最终QA效果的影响,基本可以得到检索效果直接影响了最终的QA模型效果: