https://zhuanlan.zhihu.com/p/651380539
https://github.com/ninehills/blog/issues/97
在问答和对话的场景下,通常可以通过检索和生成两种方式得到一个回复。检索式回复是在外部知识库中检索出满意的回复,较为可靠和可控,但回复缺乏多样性;而生成式回复则依赖于强大的语言模型中储存的内部知识,不可控,解释性差,但能生成更丰富的回复。把检索和生成结合起来,Facebook AI research 联合 UCL 和纽约大学于 2020 年提出:外部知识检索加持下的生成模型,Retrieval-Augmented Generation (RAG) 检索增强生成。
检索增强方法来克服大型语言模型(Large Language Models, llm)的局限性,比如幻觉问题(胡言乱语)和知识有限问题(常用于补充最新知识、公司内部知识)。检索增强方法背后的思想是维护一个外部知识库,在提问时检索外部数据,并将其提供给LLM,以增强其生成准确和相关答案的能力。
RAG 由两部分组成:
在第一部分 Retriver 中,RAG 通过两个不同的 BERT 把 外部知识 和 query 嵌入为稠密向量,做内积得到内积最大的 k 个文档。将 query 和 k个文档 拼接起来组成 k 个输入,作为第二部分的输入。
Generator 中有两种使用文档的方式。
第一种称为 RAG-Sequence model:使用同一个文档生成每个词,先确定一个文档
z
i
z_i
zi ,然后计算
p
(
y
∣
x
,
z
i
)
p(y|x,z_i)
p(y∣x,zi);
第二种称为 RAG-Token model:使用不同的文档生成每个词,对于第 i 个位置,候选词的概率等于所有文档的条件概率之和,即计算候选词对文档的边际概率。
BART 是一个基于完整的 transformer 预训练模型,使用去噪作为预训练任务。作者选用 BART-large 作为 RAG 的生成器。
在训练过程中,只有负责嵌入 query 的 BERT 和负责生成的 BART 参与微调更新参数,负责嵌入外部知识的 BERT 不用更新参数。在测试过程中,RAG-Token model 在计算当前词的概率时,前面位置候选词的概率已经完成计算了。因此,RAG-Token model 如同朴素的生成模型一样使用 beam search 解码。而 RAG-Sequence model 要遍历完所有文档才能得到每个位置候选词的概率。因此需要对每个文档使用 beam search 解码,然后再整合。
各种数据加载、解析过程中,如何尽可能保留原始数据的逻辑和语义关系是一个需要注意的问题。可以多尝试不同的加载与解析方式,对比不同的py库。也可预定于好prompt便于LLM理解。
一个好的prompt可以通过补充相关材料实现:背景知识、互联网检索结果、RAG检索结果、in-context QA实例。
举例来说,如果chunk_size设为1024,chunk_overlap设为128,则对一个长度为2560的文本序列,会切分成3个chunk:
chunk 1: 第1-1024个token
chunk 2: 第897-1920个token (与chunk 1重叠128个)
chunk 3: 第1793-2560个token (与chunk 2重叠128个)
这样的切分方式既满足了最大长度限制,也保证了相邻chunk间语义的衔接。适当的chunk大小和重叠可以提升大语言模型处理长文本的流畅性和连贯性。
如何对原始文本进行切分(如何选择 chunk size),影响很大,需要根据业务具体需求判断:
无法检索到有效的chunk (模型问题,切分问题) ; chunk 内部有无效信息 (先进行摘要,相关性过滤)。
提升方法:
检索结果的过滤:后处理,其实就是一个重排的过程
告诉模型 原始query 和 metadata 中类型的集合,让模型帮助我们得到子集合,从而进行筛选。
Re-rank 的问题 :需要真实业务 domain 的数据来微调;这里可以 尝试使用 LLM 来 rerank (给LLM写好prompt)。
答案合成策略:
Default 版本:
迭代式 refine 版本:一条 一条 chunk 输入,不断让模型修改更新原答案
Prompt → Sub-query , 不断拆分成子问题 → 直到可以回复
Atlas: Few-shot Learning with Retrieval Augmented Language Models
Atlas :用检索增强的语言模型进行few-shot学习
Atlas 拥有两个子模型,一个检索器与一个语言模型。当面对一个任务时,Atlas 依据输入的问题使用检索器从大量语料中生成出最相关的 top-k 个文档,之后将这些文档与问题 query 一同放入语言模型之中,进而产生出所需的输出。
Atlas 模型的基本训练策略在于,将检索器与语言模型使用同一损失函数共同训练。检索器与语言模型都基于预训练的 Transformer 网络,其中:
,通过encoder分别编码,然后concat在一起输入decoder进行 Cross-Attention,生成最终的回复。 这种 Fusion-in-Decoder 的方法有利于 Atlas 有效的适应文档数量的扩展。利用语言模型提供监督信号
来训练检索器,联合训练 检索器retriever
和 语言模型LM
:如果语言模型在生成输出时发现有用的文档,则检索器目标应鼓励检索者对所述文档进行更高的排名。基于这种想法,论文设计了以下四种不同的损失函数:
Attention Distillation (ADist):在decoder的cross attention模块中计算的文档跟输出之间的得分可以被用来充当每个文档的重要性,对于每个文档,计算它的每个token在语言模型decoder的每层网络,每个attention的head的注意力得分的平均值作为该文档的重要性得分,进而得到多个文档的注意力得分分布
P
A
T
T
N
(
d
k
)
P_{ATTN}(d_k)
PATTN(dk),通过最小化
检索器返回TOP-K的概率分布
P
R
E
T
R
(
d
k
)
P_{RETR}(d_k)
PRETR(dk) 跟 语言模型的注意力得分分布
P
A
T
T
N
(
d
k
)
P_{ATTN}(d_k)
PATTN(dk)之间的KL散度
来优化模型。也就是希望检索返回的得分分布
P
R
E
T
R
(
d
k
)
P_{RETR}(d_k)
PRETR(dk)尽可能的接近
P
A
T
T
N
(
d
k
)
P_{ATTN}(d_k)
PATTN(dk)。这个loss仅用于优化检索器的参数,而不是语言模型。
End-to-end training of Multi-Document Reader and Retriever(EMDR2):这种loss的设计将检索返回的文档
作为隐变量
,q 是给定的query,a 是最终的生成结果,对应的检索器的loss由语言模型得分
跟检索得分
的乘积的对数组成,但是通过固定语言模型的参数,实现只优化检索器的参数
。之前提及的FiD,RAG等检索增强模型的联合训练使用的基本都是这种类型的损失函数。
Perplexity Distillation(PDist):上述1)的改进版,将ADist中的目标分布,由pATTN,改成语言模型的得分经过softmax操作后的概率分布,然后训练目标是最小化pATTN跟改进版的概率分布,进而去优化检索器的参数。
Leave-one-out Perplexity Distillation(LOOP):上述3)的改进版,将对应的语言模型的概率得分改成移除了特定文档后的语言模型得分的负数,训练目标同样是最小化pATTN跟新版语言模型概率分布的KL散度。这种损失函数的计算成本明显高于前面几种。
基于 pretext task 的无监督学习
用于联合预训练 retriever 和 language
model,关于预训练的任务涉及,论文也尝试了一下几种不同的方式。
a) Prefix language modeling
以N个字符为单位将文本分块,将每个块(chunk)的文本切分为长度为N/2的2段子序列
,用第一段子序列
作为query,通过检索模块召回相关的文档,然后去生成结果,生成的目标target是对应的第二段子序列
。
b) Masked language modeling
以N个字符为单位将文本分块,对于每一个分块(chunk),随机抽样若干个平均长度为3的子片段进行mask,直到被mask的长度占文本总长度15%,将被mask后的每个分块作为query输入,通过检索模块去召回相关文档,然后利用语言模型去生成被mask掉的片段。
c) Title to section generation
利用Wikipeida的文章信息,将文章和章节的title作为query输入,通过检索模块去召回相关文档,然后利用语言模型去生成对应章节的详细内容。
Retriever中的语料通过文档编码器,被编码成向量被存储到索引中,在联合训练retriever跟语言模型LM时,retriever的文档编码器更新后,相应的索引就需要被更新,全量更新索引
会耗费非常多的计算资源跟时间。尤其是在finetune阶段,训练样本的数量会远小于文档的索引数,更新索引的时间会增加整体的训练时间。
a) Full index update
训练每经过一定步数后更新全部索引
,这种方式的好处在于全量更新索引能保证retriever中的文档编码器跟索引之间的相关性,同时可以根据实际需要来设置更新的频率。在论文中索引总数是3700万,训练batch size是64,每次召回20个文档,每经过1000步后更新全部索引,更新索引的计算量占模型训练的30%左右。
b) Re-ranking
在训练的每一步,检索模块会召回top-L个文档,返回其中top-K个文档给语言模型,并且更新这个L个文档的索引
,L会大于K,也就是每次更新的索引数量会大于语言模型用到的文档数量。在论文中,每次更新的索引数量是语言模型接受文档数量的10倍,更新索引的计算量占模型训练的10%。
c) Query-side fine-tuning
训练过程retriever模块只更新query的编码器,不更新文档document的编码器,那样就不需要更新索引了
,所以更新索引的计算量占模型训练0%。固定文档编码器的影响在不同任务下不尽相同,在大多数few shot场景下,这种方式不会带来较大的性能影响,有时甚至能提高模型表现。
检索增强的优势
https://www.51cto.com/article/717069.html
https://zhuanlan.zhihu.com/p/595258642
https://zhuanlan.zhihu.com/p/563129454
REPLUG: Retrieval-Augmented Black-Box Language Models
这篇工作所提出的REPLUG模型可以说是“黑盒”式检索增强的代表。在这种新范式下,语言模型是一个黑盒子(它的参数被冻结了,不会被更新优化),检索组件才是可微调的部分。
RERLUG(Retrieve and Plug) 其实就是在语言模型上额外加了一个检索组件,利用检索组件获得一些相关信息,与原始输入一起作为语言模型的新输入,检索组件和语言模型都不需要训练。(个人认为某种程度上检索出来的加到原始输入即用户query上的这些文本有点像prompt)。
RERLUG LST(RERLUG with LM-Supervised Retrieval)可以看作是 RERLUG 的升级版,它利用语言模型产生监督信号,从而去优化检索组件,让检索组件倾向于挑选出能够降低语言模型所生成文本的困惑度。
https://blog.csdn.net/qq_27590277/article/details/129414851