写在前面
大家好,我是刘聪NLP。
今天给大家带来一篇好友小杨的一篇《一文梳理DPR(Dense Passage Retrieval)的发展》。综述文章,请慢慢品尝!!
信息检索领域目前普遍采用的是两阶段架构:召回+排序,召回是首先在海量文档中选出可能与query相关的文档,这些候选文档然后经过排序模型按相关性进行排序,最终给出检索结果。本文主要聚焦召回阶段,尤其是基于dense的向量召回,并简单梳理了dense召回的发展历程。
目前dense retrieval主要有两种形式,一种是**「single vector」** ,query与doc分别编码成单个向量,这种方式的优点是检索方便,存储空间相对较小,检索速度较快,缺点是单向量较难获得细粒度表征,效果一般而言相对较差;另一种是**「multi-vectors」** ,主要对doc进行多向量表征,query仍然用单向量表示,这种方式的优缺点正好和单向量表征相反,它的优点是doc有细粒度或多视角表征,往往检索效果较好,但向量存储空间大,所占资源多,检索速度慢。
Single Vector
单向量表征上的优化主要分为3个方面:1)预训练方向的优化;2)训练方式或流程的改进;3)蒸馏辅助。
预训练方向的优化
- Condenser
Condenser的思想来源于一个已发现的现象:一个预训练好的bert transformer结构中,中间层的cls与句子中的其他token的attention系数很低,往往在最后1-2层cls才与所有的token有一个比较大的attention系数,因此作者认为在训练过程中cls并没有很好聚集所有token的信息,所以cls作为句子的表征能力不够。因此,他们引入了一个额外的聚合层condenser head,它是一个两层的transformer encoder结构,并且把原来的bert一分为二,前六层为early encoder,后六层为late encoder。其中early encoder的token embeddings(不包括cls)与late encoder的cls向量拼在一起输入到head中做进一步交互,在head上借一个MLM任务,同时为了约束head的权重优化,保留了原始bert的,即late encoder的MLM任务,两个loss相加为最终的优化目标。在微调时,去掉head层,按原DPR的方式去微调剩余的12层。 - coCondenser
coCondenser是在Condenser的结构基础上在预训练过程中引入了对比学习任务,目的是优化cls的向量表征空间。具体来说,首先按Condenser的方式训练一个模型权重,然后以该权重作为coCondenser的开始,训练数据为wikipedia或MSMARCO中的所有docs(query用不上),每次选取其中2K的文档数为一个列表,其中每篇文档随机抽取两个长片段作为piar,这样可以抽出4K个片段,然后根据对比学习任务,每个片段只与其对应的片段是语义相近的,而与其他所有的片段是语义远离的,得到NCE损失:然后保留Condenser中head的MLM任务,去掉late encoder的MLM任务,保持原来的Condenser结构继续训练coCondenser。微调时依旧去掉head层,按传统的DPR方式进行有监督的训练。
- CoT-MAE
CoT-MAE借鉴了图像领域的MAE的做法。用深层网络做encoder,用浅层网络做decoder,以此来促使encoder学习较好的文本表征。下图比较清晰的说明了CoT-MAE的结构及训练方式。首先,在一个document中采样两个片段分别作为Ta和Tb,采样的方式有3种:1)选择相邻的两个文本片段;2)选择有重叠句子的两个文本片段;3)随机选择两个不相邻的片段。得到Ta和Tb之后,作者对其分别进行随机掩码,然后将其中的一个送入encoder,另一个送入decoder,这里encoder用bert初始化,decoder是随机初始化的2层transformer结构,经过encoder编码的掩码文本接MLM任务,然后取cls作为上下文向量(context embedding)与另一个掩码文本一起送入decoder,decoder上再接MLM任务,还原被掩码的字符。由于Ta和Tb可以互换,就得到了对偶的MLM损失,就可以进入预训练阶段。在微调时,去掉decoder,仍按传统的DPR方式进行。另外值得注意的是,作者通过实验验证了encoder和decoder的掩码概率分别是30%和45%时,效果最佳。
训练方式的优化
训练方式的优化主要包括数据增强和负例挖掘。
- ANCE
ANCE是一种很经典的负样本采样方式,它是在训练过程中不断根据当前更新的DPR模型对全文档库进行重新编码,然后选取与query相似度很高但不是正样本的doc作为负例。初始训练时,可以用BM25负例作warm up。具体流程图如下:在训练过程中,作者通过异步编码文档库,更新向量索引,加快训练速度。
- RocketQA
RocketQA实际上综合了各种训练方法与技巧,以工程的角度堆叠了DPR模型的效果。具体而言RocketQA有以下几个改进:
a)多GPU的In-Batch负例融合,利用多GPU的优势,扩大负例的个数,单query的负例样本数可扩展至数千至上万个;
b)负样本的去噪采样,由于标注的原因可能存在与相关的doc被标记为不相关,针对这种情况,需要对负样本进行去噪处理。首先训练一个cross-encoder来估计query与其负样本的相关程度,通过阈值过滤得分高的负样本,因为这些样本可能是正例,剩下的可以作为负样本使用;
c)数据增广,利用第二步得到的cross-encoder在新的数据上进行标注,扩充数据集。 - PAIR
PAIR的优化点主要在以下方面:
A)引入passage-centric contrastive loss,传统的DPR是以query为中心,提高query与正例的相似度,降低其与负例的相似度,即query-centric contrastive loss:最终的loss为两者的线性加和,其中Lp的权重为0.1,Lq的权重为0.9
B)数据去噪与增广,这一过程主要是结合了RocketQA中的第2、3步,同样利用一个训练好的cross-encoder进行数据的再标注;
C)两阶段训练流程,由于passage-centric是一个辅助任务,用于优化向量表征,与下游任务并不是直接相关,因此只在预训练过程使用,在微调时,仅使用query-centric loss。 - GPL
GPL本身并不是DPR模型的继续优化,而是针对领域内标注数据量不足或没有的情况下,优化的一套训练流程,它的思路也很清晰,如下图所示:
A)利用一个训练好的生成模型针对每篇段落生成3个问题,这样可以构建query-passage训练数据对;
B)利用DPR进行常规负例采样;
C)利用一个训练好的cross-encoder对batch内的pair对(包括q-p+、q-p-)进行相关性打分,然后计算正例pair对与负例pair对的得分差距,再用DPR模型计算正例对与负例对的得分差距,最后MarginMSE损失优化DPR模型。MarginMSE损失函数如下:其中平方项中的字母分别表示DPR及cross-encoder的正例对与负例对的得分差距。
- AR2
AR2对retrieval和ranker进行了联合训练优化,同时引入了GAN式的训练方式,以期同时获得更好的retrieval和ranker。具体而言,给定一个初始的retrieval和ranker(可以是初步训练好的),这里的retrieval和ranker类似于GAN中的generator和discriminator。retrieval采样相似度高的负例去欺骗ranker,ranker需要从retrieval的采样负例和真实正例的混合样本中识别出真实正例。在训练时,两者交替迭代更新参数。
蒸馏
有不少利用cross-encoder对DPR进行蒸馏的论文,这里介绍两篇集大成的、代表性比较强的论文,均来自于百度。
- RocketQA-V2
RocketQA-V2是以RocketQA的模型权重为基础,引入了两个改进点:动态联合蒸馏(Dynamic Listwise Distillation)和混合数据增强(Hybrid Data Augmentation)。
A)动态联合蒸馏是用ranker的输出指导retrieval训练,同时ranker同步训练。该方法首先对输入的query和候选段落集(包含一个正例和多个负例)分别进行retrieval的相似度得分计算以及reranker的相关性得分计算,再对这个段落集的相似度得分与相关性得分分别进行softmax归一化,最后最小化两者的KL散度,让retrieval更好的模拟ranker。另外再给ranker加上一个有监督的cross-entropy损失函数,这样在训练过程中,ranker从监督数据中学习一个list中query与passage的相关性分布,并将该分布传递至retrieval,两者同步更新,联合训练,以达到更好的训练效果。
B)混合数据增强是在RocketQA去噪增强的方法上作了进一步提升。具体可以看下图:先利用retrieval对每个query召回出一批候选段落集,针对该段落集采取两种采样策略:随机采样和去噪采样。随机采样和正常的batch数据采样是一致的;去噪采样是利用ranker对段落集进行相关性打分,去掉段落集中得分很低的负例,这样选出的负例更难,同时把得分很高的样例作为正例,扩充数据。文中没有提到一点,但我认为有矛盾的地方:如果随机采样得到的负例被ranker打了很高的分该怎么办?个人认为应该先用ranker打分,先标记处扩充的正例,然后随机采样在剩下的负例中选择,这样才能避免数据冲突的问题。
- ERNIE-Search
Ernie-search这篇论文算是把蒸馏做到头了,它用了非常多的约束只为了尽可能的从cross-encoder上获取更多的交互信息来指导dual encoder的学习,这些方法被归纳成两个方面:interaction distillation和cascade distillation。
A)interaction distillation是以colbert为模型结构,在训练过程中通过后交互得到的相关性分数指导cls单编码向量相似度的训练,结构如下图所示:这样做的好处是,query和passage只需经过一次模型就可以得到单向量的相似度(cls内积)以及后交互的得分(token-wise max similarity)。得分经过归一化后,可以输入到三个损失函数中:单向量编码的cross-entropy loss,后交互的cross-entropy loss中,以及单向量得分与后交互得分分布的KL散度,前两个为有监督的损失函数,后一个为蒸馏损失。
B)Cascade Distillation。由于cross-encoder含有丰富的交互信息,如果可以利用cross-encoder的知识进行蒸馏,效果理论上会更好,因此cascade distillation将cross-encoder的信息蒸馏到colbert,然后再通过interaction distillation将colbert的信息蒸馏到dual encoder,避免直接从cross-encoder到dual-encoder因架构差异导致的蒸馏损失。在级联蒸馏的过程中,类似于interaction distillation,会产生三个损失函数:cross-encoder本身的有监督的cross-entropy loss,cross-encoder到colbert的KL散度,cross-encoder到dual encoder的KL散度。另外,为了进一步提取cross-encoder中的token-wise attention信息,作者取cross-encoder最后一层的多头注意力系数,并对colbert的token向量进行两两内积,模仿token之间的attention系数,之后将用KL散度拉近这两者的分布。级联蒸馏的整体框架如下图所示:最后在训练时,作者先融合了多种方法,如coCondenser、PAIR训练dual encoder,再用上述的方法对其进行蒸馏,得到更好的retrieval模型。
Multi Vectors
多向量表征的优化主要集中在两个方向:1)通过多视角学习得到更好的doc多向量表征;2)优化后交互方法。
多视角学习
- ME-BERT
ME-Bert首次从理论和实验两个角度论证了当document的长度越长时,单个向量的固定维度(bert为768)难以有效的表征doc的语义信息。想要获得更好的效果,必须扩大表征的维度或者增加表征向量的个数。由于增加个数对检索性能的影响要小于扩大维度,因此作者最终选择以多向量的表征方式来编码单个doc。具体实现起来也很简单,作者选取了每个doc前8个token的向量作为最终的doc表征,在训练过程中,计算query向量与这8个向量的相似度并取最大值作为最终得分,用cross-entropy损失去优化模型参数。当然也做了一些随机负例与难负例的采样。 - MVR
由于ME-BERT只选取doc的前几个token的向量作为整个doc的多粒度表征,而这些token在预训练时本身有细粒度的语义信息,可能会与doc的全局表征冲突或者不能很好的捕获到doc后半程的语句信息,所以本文的作者提出MVR的结构,旨在引入新的token—“[VIE]”从头表征doc的不同视角的语义信息。具体来说,在query前拼接一个[VIE]用来表征query,在doc前拼接n个[VIE](n=8)来表征doc,训练时引入global-local损失,其中global contrastive loss用于样本间正负例的区分,即计算query的[VIE]与doc的n个[VIE]的相似度,选取最大相似度作为得分,进行NCE loss优化,数学形式如下:local uniformity loss用于拉开doc中n个[VIE]向量之间的,其数学形式如下:最终的loss为两个loss的线性加权,λ为0.1。训练时注意温度也比较重要,温度越小,softmax的分布越尖锐。训练早期温度大,使每个view都是潜在的该问题视角下的doc表征,等训练一段时间后,有了分布的雏形,可以降低温度,集中优化难以区分的视角。个人觉得该方法可以配合问题生成模型,如对一个doc生成不同的问题,丰富问题类型,产生更多视角,从而使模型获得更好的效果。
后交互优化
- ColBert
Colbert是经典的后交互优化方式,其结构也十分简单,一张图即可说明:query与doc分别经过双编码器得到各自的token向量,然后计算query中每个token向量与doc中token向量的相似度并取最大得分作为该token的分数,所有的query的token分数相加得到该query与该doc的最终得分。这种后交互的手段十分简单,先求最大再求和。在训练过程中,作者还用了一些小操作,比如分别拼接[D]、[Q]到doc和query的序列上、用[mask]填充短的query样例、对token向量进行降维以压缩空间等等。
- ColBert-V2
V2版本在V1版本的基础上主要做了以下改进:
A)以V1模型权重为基础进行再优化;
B)负例由V1模型挑选,增加负例难度;
C)引入cross-encoder进行蒸馏学习,具体学习方式类似于RocketQA-V2;
D)向量量化,具体来说是通过聚类设定向量中心C(向量中心的数目正比于向量总数的平方根),那么每个向量v可以由其最邻近的向量中心Ct及残差r表示,v=Ct+r,然后对r作量化处理,用1或2个bit表示一个维度,得到r’,在检索时,先检索到最邻近的向量中心Ct,再加上r’近似还原原始向量v。量化后可以大大缩小磁盘存储空间,同时提升了检索速度。 - COIL
COIL利用传统的关键词匹配索引进一步加速了后交互,降低了检索延时。具体来说,query中的每个token如果在doc中出现,则计算token_q和token_d的相似度并取最大值,如果未出现则不计算得分;另外为了弥补vocabulary mismatch的问题,在计算query与doc的[CLS]的相似度,最后与token的相似度加和得到整体的得分。
此外还有一些其他的后交互方法,如poly-encoder,此处限于篇幅大小不作过多赘述,有兴趣可自行搜索查阅。
最后放一张效果对比图,涵盖了上文提到的大部分模型,截至目前效果最好的是集各种方法之大成的ERNIE-Search。
总结&一些想法
DPR检索本质上也是向量表征下的一个直接子任务,无非是在一个向量空间中尽可能的把相关的query-doc映射同一位置,不相关的给拉远,从根本上来说与文本相似度任务是一致的,只是输入数据的模式或特征不同而已。目前DPR更多的是聚焦在训练流程的优化,比如如何获取更好的知识蒸馏、如何更好的获取负例,其实感觉目光还可以看的再远一些,从底层的表征去入手,如何更好的表征query与doc这两种输入模式(一个短句类型,一个多句且含义丰富类型),如何引入自监督训练作表征增强(类似SimCSE)等等,说不定也能有一些新的发现。
请多多关注知乎「刘聪NLP」,有问题的朋友也欢迎加我微信「logCong」私聊,交个朋友吧,一起学习,一起进步。我们的口号是“生命不止,学习不停”。
往期推荐: