前言
ChatGPT的出现鼓舞了NLP的科研人员和工作者,大模型的涌现让AI在即将退潮时又掀起了层层巨浪。大家似乎看到了黎明的曙光,刹那间百“模”大战打响,各大高校、科研机构、企业纷纷“自研”大模型,好不热闹。说到底,这个自研大多来自于开源模型,对垂直领域的数据进行清洗加数据增强,再用前沿的调优算法(LoRA、Adapter Tuning、Prefix Tuning、Prompt Tuning等)来进行调优,然后得到该领域的大模型。
以此种方式,在海量数据的加持下,确实可以在领域内获得不错的表现能力。但此种方式也并非长久之计,因为领域内的数据总是在更新,每次数据更新迭代之后再进行微调似乎并不理想。说到底,现在模型似乎并不具备像人一样,拥有一直学习的能力。现在看上去就是把大部分知识在短时间内都塞到模型中,而那些没有见过的知识,便很难推理出来。那么从0到1训练大模型的成本是难以接受的,微调大模型的方式或许还能接受,但是通过检索已有知识库,再让大模型(接口)分析数据,并进行问答,或许是一个较优的选择。
背景介绍
Sentence Bert (双塔模型)
传统信息检索工具ES基于Term召回的方式在语义接近但Term Difference比较大的情况下表现不佳。SBert(Sentence Bert)为架构的训练方式提升了句子和句子之间的召回准确率。如下图,左边是对句子进行进行一层Bert输出,经过Pooling得到对应A、B句的向量u、v,再通过concatenate u,v, |u-v| 再乘以一个可训练的权重经过softmax的到最后的结果(公式如下)。右边是推理的过程,用模型进行推理得到A、B向量, u、v再进行余弦相似度计算,通过设定一定的阈值求出最优的结果。
Sentence Bert (又称双塔模型) 这种框架有两种实现,Bi-encoder 和 Dual-encoder。
Bi-encoder 首先将Query和Candidate输入到共享的Transformer编码器中,将其分别编码成向量表示,然后通过计算两个向量之间的相似度得分,来判断Query和Candidate的匹配程度。典型的有近期Moka AI发布的M3E模型,在s2s(sentence to sentence)和s2p(sentence to passage)任务上表现不俗,超过了之前比较优秀的text2vec模型 (large的模型可以看这里),具体可以看一下hugging face的介绍。
Dual-encoder模型的基本架构是将Query和Candidate分别输入不同的Transformer编码器中,分别编码成向量表示,然后计算Query和Candidate的相似度得分,来判断Query和Candidate的匹配程度。这种适用于两种句子维度不一样的匹配任务,类似于query匹配文档,query匹配答案等。
在Bi-encoder模型中,Query和Candidate共享了同一个编码器,因此它们在表示空间中具有相同的维度和分布。而Dual-encoder模型则使用了两个独立的编码器,因此它们在表示空间中具有不同的维度和分布。这种差异可能对模型的表现产生一定的影响。同时,由于Dual-encoder模型中的两个编码器具有独立的参数空间和状态空间,因此Dual-encoder模型可以对Query和Candidate的特征进行更灵活的处理和提取。然而,由于需要用到两个编码器,Dual-encoder模型的训练和推理成本通常比Bi-encoder模型高。
CoSENT
通过语言模型提取特征,再计算余弦相似度进行分类。这样的做法存在训练和预测不一致的问题,如果直接优化目标cos值,效果往往特别差。苏神提出的CoSENT一种新的训练方式,就是对比正负样本的余弦值相对差距。想要了解的同学可以去官博看一下。
Cross Encoder
上述的文本匹配方式Bi-Encoder的方式为特征式(Representation-based)匹配,而另外一种为交互式(Interaction-based)。交互式匹配方案如下右图,将两段文本拼接在一起当成单个文本进行分类,交互式由于使得两个文本能够进行充分的比较,所以它准确性通常较好,但在检索场景中使用效率低下,因为需要现场推理向量,而特征式可以提前将所有的Candidates进行计算并缓存,在检索过程中只需要对Query进行向量推理,然后匹配所有的Candidates就行了,但相对而言,特征式交互程度较浅,效果通常比交互式要差。
Multi-stage Retrieval
上面提到的方案都是简单的单召回方式,类似与LangChain-ChatGLM即从海量的文档向量库对当前的query的向量进行向量相似度计算,找出最接近的文档,然后通过Prompt Template进行渲染构造Prompt输送给大模型,最后接受大模型生成的答案。
这种单阶段召回的方式是最为基础的,后面调研了MS MARCO这个数据集的Leaderboard发现了一些比较有见解的方案,现在也一起总结到本文中。
Paddle-pipelines
百度的Paddle-pipelines主要是通过两阶段进行排序,首先将文档集合离线转变为向量存储在向量索引库,一阶段利用进行向量匹配召回Top N,二阶段用高精度的交叉模型候选Top K进行排序,最后召回答案。这样可以提升模型的准确率。
百度在离线阶段使用的是Dual-Encoder方式,训了两个模型,一个是query-encoder, 一个是passage-encoder; 二阶段使用的cross-encoder精排,对于头部的召回可以提升不少,详情可以参考github上给出的指标。
RocketQA
百度使用的模型是RocketQA系列,具体的原理如下:
由于Dense passage retrieval下的训练和推理之间的差异,即训练过程中只是选取了部分的样本作为负例,而推理过程中则是对所有的样本进行比较。同时,在进行训练的过程中negative samples往往存在了大量的false negative samples,即标注为非答案文本的文段也是可以作为答案的。
针对上面这两个问题,文章提出了三个优化策略Cross-batch negatives, Denoised Hard Negatives, Data Augmentation.
Cross-batch negatives主要做的就是将m台上的GPU机器上的n个samples都进行embeddings计算,然后下发到每一个GPU机器上,那么每一个训练样本都有m*n-1个负样本,对比之前的in-batch negatives的n-1个负样本,这样极大地增加了负例样本的学习。
Denoised Hard Negatives,先train一个dual encoder来召回negatives, 然后再训练一个cross encoder来去除false negatives,这样让模型学习到负样本尽可能是对的,相当于是做了一次数据清洗。
Data Augmentation就是用已经训练好的cross encoder对一些未标注数据进行标注,类似于semi-supervised learning,来增大数据量。
这种方式在测评数据集上的表现不俗,但是对于机器的要求比较高,就比如第一步的Cross-batch negatives来说,这需要尽可能地增加机器的数目,同时对于单个GPU机器来说,增加了大批量的negatives,对于GPU的显存来说是一个很大的挑战。后面的train dual encoder的方式也是一个多阶段的训练,相对来说训练的成本比较高。
coCondenser
后面看到了MS MARCO的Document Retrieval Top 1方案--coCondenser。作者做的事情简单但有效,即他认为最后一层的【CLS】的向量并没有有效的聚合整个输入的所有信息,于是提出一个新的训练架构--Condenser,Condenser一共由六层的Transformer blocks组成,一共是三组,early backbone encoder、late backbone encoder以及head,最下面的为输入层,头部拼接了一个special token 【CLS】。
同时,跳连early layers,可以消除了编码局部信息和输入文本句法结构的负担,将CLS重点放在输入文本的全局含义上,Condenser 被迫学习将信息聚合到 CLS 中,然后 CLS 将参与 LM 预测。利用 MLM 产生的丰富有效的训练信号,Condenser 学习利用强大的 Transformer 架构来生成密集的 CLS 表示。我们假设通常用于训练token表示的 LM 目标现在放在密集的 CLS 表示上,学习到的 LM 获得了更好的抗噪声鲁棒性。
【CLS】虽然可以通过head进行非线性表征,但是这些向量的内积依然是不具备语义信息的。作者提出加入对比的loss来提升语义表达。这种方式在introduction部分提到了,就是抽取文档中的片段,这些片段形成了一个训练批次集,将 表示为 ,loss的计算公式如下图。
这里的核心思想就是同一篇文章里的片段的分布应该是尽可能相似的,而不同文章的片段应该有不同的空间表达。最后的loss就是masked loss➕span LM losss。
最后和RocketQA的效果进行了对比,从表格中我们可以看出,RocketQA的batch size和本文使用的batch size的差距还是很明显的,但是从结果上来看coCondenser再加入Hard negatives之后,在MS-MARCO上的表现要优于RocketQA。
HLATR
HLATR是当前Passage Retrieval的Top 1方案,核心思想是认为一阶段的召回和二阶段的排序的结果可以进行藕合来提升整体的性能。
这里作者提到两个模型虽然都是进行排序,但是模型的关注的点不一样,表征式的模型(retriever)偏向于粗颗粒度特征,交互式的模型(interaction)偏向于query和document之间的信息交互。同时作者做了一个简单的weighted combination,就是给予召回和排序这两个阶段不同的权重,对于整体的召回效果也是有提升的。
文章的思路其实比较简单,就是通过对一阶段召回的顺序的位置编码和二阶段输出的logits的向量,来做非线性组合,相当于是融合吧。
这里的d1dz是一阶段召回的个数,然后v1vz是二阶段对应的logits向量,通过对位置编码进行加和在通过Layer Norm,再通过transformer层进行注意力机制交互。
最后再对结果进行一个全连接层输出一个分数,排序。
这里用的是Contrastive Loss。
从实验结果上看,作者针对不同的Retrieval和二阶段进行了对比,Retrieval的话是选用了Sparse-BM25,Dense的话用的是coConderser和ANCE,公开的checkpoint。结果如下,WCR指的是Weighted Combination of two-stage Ranking models。从整体上看,WCR的方式会比二阶段的Reranking好一些,而相比下来HLATR的效果是最好的。
之后作者对于HLATR的架构进行了探究,即将多层的transformers替换成2-layer的MLP(多层感知机)这样的效果只是下降了0.2pp,但还是从另外一个角度说明了transformers模型比MLP发现不同文档中的互信息中表现的更好(个人觉得整体而言transformers)。 而将loss换成了binary cross-entropy loss之后整体性能下降了0.9pp,说明以对比学习为目标的文本排序任务会更加适合,究其原因还是因为排序任务是一个数据不平衡的优化问题,对于输入序列来说,负样本远比正样本要大得多,而对比学习在数据不平衡的情况下会更有优势。
整体上来说之前的一阶段召回和二阶段排序都是文档之间相互独立的,并不直接进行对比,而只是通过向量之间的相似度,或者说是输出的分数进行一个排序。当时从人的直观来看,对于相关的排序,往往建立在对于query的理解,还有对所有doc的综合考虑来做的,而孤立doc偏离了似乎偏离了这一想法。作者用HLATR第三层排序以位置编码的形式引入了召回特征,以及文档特征矩阵引入了排序特征,最后通过transformers或者MLP进行交互,相当于是进行了doc之间的信息融合,最后给出了一个分数。
LLM4Retrieval
这里利用Paddle-pipelines搭建了一个文档检索环境,一阶段使用的分别是rocketqa-zh-base-query-encoder&rocketqa-zh-base-para-encoder召回个数为100,二阶段用的是rocketqa-base-cross-encoder,排序之后展示最终的Top2。数据集使用的是医疗科普知识阅读理解数据集。
这里我们先输入“如何预防老年痴呆”作为我们的query,召回的具体信息我放在文章最下面了,之后我们将使用不同的prompt来构建我们真实的query,来让大模型作答。(由于字数超限,所以删除了原文段的部分文字,不影响做答。)
zero-shot
简单粗暴,直接把信息丢给ChatGPT进行整合。语法用的是 jinja 写的,可以支持多种语言渲染。
参考信息
{% for info in context %}
{{loop.index}}. {{info}}
{% endfor%}
Instruction
请参考上面的参考信息,回答下面的问题。
问题
{{query}}
回答
GPT答案如下,看起来有点生硬了,没有加入身份信息看起来就是正常的科普文。
下面试试看加入身份信息。
参考信息
{% for info in context %}
{{loop.index}}. {{info}}
{% endfor%}
Instruction
你是一名经验丰富的皮肤科医生,现在你要求回答下面的问题,你需要基于你多年的从医经验并参考上面的信息,你的回复应尽可能详细,并给出原因。
问题
病人: {{query}}
回答
医生:
GPT答案如下,整体上看来回答要比之前丰富,而且细节上也更完整,看起来更像是人在交流。
Few-shot
Few-shot的概念就是在zero-shot的基础上给模型一些示例,有点教模型如何使用参考信息的感觉。
Chain Of Thought
Chain of thought (CoT) 是基于few-shot的改进,指的是从一个问题演化到另一个问题,或者是从一个普遍思想或论据演变出更有深度的思考或论据的过程,即用逻辑连贯的方式进行思维。在example中提供对问题的思考方式、观察结果以及如何解决问题的细节,能够丰富模型的最终生成答案,从而将相关点连接起来,结合创造新的思想来推动思考。
时效性
大模型强依赖于训练数据,实时性的信息和新知识相关的问题是无法准确回答的,那么这个时候可以在通过爬虫的方式,找到问题相关信息并通过一个额外的阅读理解(摘要)模型来提取关键信息。然后作为参考信息来做为真实输入的一部分,让模型具备时效性信息答复能力。
结语
对于大模型在信息检索上的应用现在还在探索阶段,只是停留在阅读理解的阶段是不尽人意的,希望之后LLM能够具备过目不忘能力,能够实时更新模型权重以回答时效性问题,新的知识。
谢谢您的耐心观看,喜欢的话帮忙支持点赞 ❤️ ➕ 收藏 📁。
参考
- 风飏:让天下没有难Tuning的大模型-PEFT技术简介
- 吃果冻不吐果冻皮:红杉资本发布大语言模型应用开发的技术栈预测
- Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks
- moka-ai/m3e-base · Hugging Face
- GanymedeNil/text2vec-large-chinese · Hugging Face
- shibing624/text2vec-base-chinese · Hugging Face
- CoSENT(一):比Sentence-BERT更有效的句向量方案 - 科学空间|Scientific Spaces
- CoSENT(二):特征式匹配与交互式匹配有多大差距? - 科学空间|Scientific Spaces
- GitHub - imClumsyPanda/langchain-ChatGLM: langchain-ChatGLM, local knowledge based ChatGLM with langchain | 基于本地知识库的 ChatGLM 问答
- MS MARCO
- Maple小七:神经搜索落地曙光——百度RocketQA工具包初体验
- Condenser: a Pre-training Architecture for Dense Retrieval
- https://arxiv.org/pdf/2205.10569.pdf
- https://github.com/PaddlePaddle/PaddleNLP/tree/develop/pipelines/benchmarks
- 山野闲人:信息检索:论文精读【1】coCondenser
- 山野闲人:信息检索:论文精读【2】RocketQA
- 山野闲人:信息检索:论文精读【3】Dense Passage Retrieval
- 山野闲人:信息检索:论文精读【4】HLATR: Enhance Multi-stage Text Retrieval with Hybrid List Aware Transformer Reranking
- 医疗科普知识阅读理解数据集 - 飞桨AI Studio
- Jinja - Jinja Documentation (3.1.x)
- CoT - 搜索结果 - 知乎
参考信息
- 老年痴呆症,又叫阿尔次海默病。老年痴呆,一般是指大脑中产生记忆和进行推理的脑功能出现功能衰退的现象。这会严重影响到老年人群的日常生活能力,使他们无法正常参加一些活动。更严重的是,老年痴呆人群无法自己正常生活,会发生尿失禁导致死亡的现象。随着年龄的老龄化越来越严重,我们应该开始重视老年人群的保健方面。老年痴呆症对老年人的健康有很大的危害,所以老人们应该及时预防老年痴呆症。怎样可以有效预防老年痴呆啊?下面让我们来一起看看吧!在吃饭前多多用脑。我们每个人一天基本是吃三餐饭,如果老年人能在这三餐饭之间多多动一下脑筋,让大脑时刻保持活跃的状态,就可以很有效的预防老年痴呆症。根据美国老年痴呆症协会研究发现,如果老年人能够进行大脑的训练,就可以防止得老年痴呆症。要多吃水果蔬菜。根据研究报告显示,多吃水果蔬菜可以降低大脑衰老的速度。一个著名研究项目曾经对几十名老人进行了六年的跟踪,得出的结果是,如果老年人每天吃五份以上的水果蔬菜,大脑的认知能力下降的速度会比其他的低40%。多吃坚果和粗粮,要少吃高热量的食物。粗粮坚果中含有丰富的维生素E,而且可以让身体吸收足够的欧米伽3脂肪酸,它对我们大脑的健康有很大的帮助。跟许多养生的道理都一样,预防老年痴呆症,也对我们身体各个地方有很大的好处。吃完饭后做一件事。大多数的人都喜欢吃完饭后看电视,其实这只会让我们越来越笨。有专家研究发现,如果电视看得越久,特别是在吃完饭后,就会让我们的脑细胞越来越僵化,会导致我们的思维能力越来越慢。所以在吃完饭后也要多多活活跃我们的大脑。上面所说的就是一些可以预防老年痴呆症的方法。现在我们的生活越来越舒适,导致很多人有很多不好的生活习惯,到了老年就很容易患上老年痴呆症。所以我们要养成良好的生活习惯,有效预防老年痴呆症。
- 概述帕金森病又叫做老年痴呆症。帕金森病是由老年性疾病,因为它的发病年龄平均在60岁以上。一般40岁以下发病的帕金森病症是比较少见的。为了防止出现这种情况,下面我给大家介绍一下帕金森症如何治。帕金森症如何治第一:普通患有帕金森的患者,疾病的病症都是先从单侧开端发病的,然后病症就会逐步涉及到对侧肢体,药物治疗的效果也逐步降低,反作用越来越明显。到中晚期会影响到吞咽发声,晚上翻身艰难,失眠等。严重的患者到晚期会由于肌肉挛缩、关节强直而卧床。第二:患有帕金森的患者随着病程时间的延长,所以患者的病情也就越来越重,而一旦病情加重就会使患者的家庭面临越来越繁重的人力和经济担负,病人从开端的偶然需求人照顾逐渐开展到需求一个以至两个特地的人来照顾病人的根本生活。第三:患有帕金森的患者,在患病后会呈现肢体的震颤、行动的不便的等病症,由于这些病症,患者怕同事或朋友见笑,所以就不盲目将本人封锁起来,远离了原先熟习的生活、工作圈。整天待在家中。这样,疾病在停顿,病症在加重,心情也随之变得异常不好,很多帕金森患者存在不同水平的抑郁、焦虑病症。注意事项目前治疗帕金森建议患者可以采取物理加中医的治疗方法,通过把传统中医学与现代西方脑细胞科技完美结合,治疗方针制定康复效果最佳的治疗方案。