来源:网络
随着大型语言模型的发展,以ChatGPT为首,涌现了诸如ChatPDF、BingGPT、NotionAI等多种多样的应用。公众大量地将目光聚焦于生成模型的进展之快,却少有关注支撑许多大型语言模型应用落地的必不可少的Embedding模型。本文将主要介绍为什么Embedding模型在大语言模型中十分重要、当前主流的Embedding训练方法,以及我们关于Embedding模型初步探索的一些思考。
在机器学习和自然语言处理中,Embedding模型是指将高维度的数据(例如文字、图片、视频)映射到低维度空间的过程。简单来说,embedding向量就是一个N维的实值向量,它将输入的数据表示成一个连续的数值空间中的点。本文主要关注文本embedding。
Embedding重要的原因在于它可以表示单词或者语句的语义。实值向量的embedding可以表示单词的语义,主要是因为这些embedding向量是根据单词在语言上下文中的出现模式进行学习的。例如,如果一个单词在一些上下文中经常与另一个单词一起出现,那么这两个单词的嵌入向量在向量空间中就会有相似的位置。这意味着它们有相似的含义和语义。
Embedding的概念可以追溯到20世纪中叶,Harris提出了分布式语义理论。到20世纪80年代,人们开始尝试用神经网络来学习单词的embedding表示。自2010年以来,随着深度学习技术的发展,先后出现了以Word2Vec、GloVe、FastText为代表的静态向量Embedding和使用ELMo、GPT、BERT为代表生成上下文相关的动态向量embedding,后者可以更好地捕捉单词的语义和上下文信息。
如前文所述,也是被我们熟知的,embedding向量包含语义信息,含义越相近的单词,embedding向量在空间中的位置也越相近。实值向量embedding可以通过从大量的数据中学习单词的语义和上下文信息,从而可以进行向量运算和在不同自然语言处理任务中共享和迁移。
然而,这是Embedding之前的价值。在大语言模型时代,Embedding又有什么新的价值呢?
这要从类ChatGPT模型的缺陷说起。尽管它们能力强大,但目前依然存在以下几点问题:
对此,OpenAI发布了一篇文档,说明如何基于embedding使用两步搜索的方式来解决GPT无法处理长文本和最新数据的问题。两步搜索,即先搜索文本库以查找相关的文本部分,再将检索到的文本部分添加到类ChatGPT模型的输入中,获取回复。
以一个代表性的应用来说明,当我们想让大模型根据我们给定的pdf文档进行问题回复时,就可以对超长pdf进行分块,获取每个分块内容的embedding,并使用向量数据库存储。接下来,当你提出问题“xxx在文档中是如何实现的?”时,就可以使用你的问题embedding,去数据库中检索得到与问题embedding相似度最高的pdf内容块embedding。最终把检索得到的pdf内容块和问题一起输入模型,来解决新知识和超长文本输入的问题。
因此,尽管当前的讨论热度不高,但embedding模型的探索对于大语言模型的落地是必不可少的。
前面提到,OpenAI早已提出了基于Embedding的搜索方案来解决长文本输入和最新数据的问题。自然而然,OpenAI也有一套未公开训练细节的Embedding方案:text-embedding-ada-002。这是OpenAI的二代Embedding模型,仅使用了一个模型就能同时完成三种下游任务:文本搜索,文本相似度和代码搜索。相较于一代模型分成了五个模型来完成上述三种任务,二代模型简化为了单一模型,且在中文和英文任务上都表现出较好的性能。
在本章中,我们将梳理一些主流的Embedding训练方法。近年来,Sentence Embedding的相关工作大多基于BERT-like models。从基于Decoder结构的模型中获取Embedding,只有少数的研究和公开代码。OpenAI所发表的Embedding论文的训练细节也不甚清楚。因此,在本章中,我们主要梳理基于BERT-like models的Sentence Embedding的一些代表性方法。
在BERT前时代,一般采用word2vec训练出的word embedding结合pooling策略进行句向量表征。在BERT时代,人们借助预训练语言模型的固有优势,先是采用BERT模型的[CLS]向量作为句向量表征,而后Sentence-BERT又巧妙地使用孪生网络模型的框架来获取句向量,后续又相继出现BERT-Flow、BERT-Whitening、SimCSE、R-Drop、ESimCSE等工作。其中,被大家较为熟知的就是BERT-whitening和SimCSE,之后便有大量的工作以对比学习为主线思路,在构造正负样本对的数据层面和训练层面进行了改进。本章节主要对该类方法进行一个简要概括。
由于近期的Sentence Embedding工作多围绕对比学习展开,我们首先来回忆一下对比学习的基础。
对比学习背景
对比学习就是「以拉近相似数据,拉远不相似数据为目标,有效地学习数据表征」。给定一个pair对样本集合, 其中和为相似样本,优化目标一般采用通过in-batch negetives交叉熵损失函数,如下:
其中,和为和的句向量表示,N为训练过程中batch的大小,为向量和余弦相似度,为温度超参。
经典方法
近年来,自SimCSE横空出世后,句嵌入领域也引起了一小波研究热潮。在本小节,我们主要对SimCSE相近时期的三篇工作(SimCSE、ESimCSE、CoSENT)进行了相对详细的梳理,并简单总结了后续部分代表工作。
SimCSE
SimCSE算是句嵌入领域最出圈的工作之一了。
它分为两个版本:
以上就是SimCSE的核心思想,简单有效,同时很有启发意义,引领了句嵌入技术后续一波研究热潮。
ESimCSE
ESimCSE分别从正负样本构建的角度对SimCSE进行了改进。
( (1)正例:代表我们目标的类别。 (2)负例:代表我们不关心的那个类别。)
(1)正例对的构建方法:
由于SimCSE是通过调节dropout率构建的正例对,长度是一样大的,负例则长度不等,这会使得模型倾向于判断相同或相似长度的句子在表达上更相近。
为了缓解这个问题,ESimCSE选择在句子中随机重复一些单词,这可以在改变句子长度的同时,而不改变其语义。
(2)负例对的构建方法:
在对比学习中,理论上负对越多,对之间的比较就越好。ESimCSE也遵从了这一思想,但并没有直接强硬开大batch size,而是维护了一个队列,重用前面紧接的mini-batch的编码嵌入来扩展负对,并使用了动量编码器。具体做法是:由于排队句子嵌入来自前面的mini-batch,可以取其参数的移动平均来保持动量更新模型,并利用动量模型生成排队句子嵌入。当使用动量编码器时,关闭dropout,来缩小训练和预测之间的差距。 编码器的参数和动量更新编码器的参数进行更新,按以下公式计算:
为动量系数参数。注意,只有参数通过反向传播更新。这里我们引入来为队列生成句子嵌入,因为动量更新可以使比进化得更平稳。因此,尽管队列中的嵌入是由不同的编码器编码的(在训练期间的不同“步骤”中),但这些编码器之间的差异可以很小。
CoSENT
早期的Sentence-BERT存在训练、预测不一致和调优困难的问题。但如果直接优化预测目标cos值,效果往往又特别差。难道直接优化cos值的方案就没有出头之日了吗?
有幸的是,答案是不会。苏剑林老师提出了一种CoSENT方案,一个优化cos值的损失函数:
记为所有正样本对集合,为所有负样本对集合,那么我们希望对于任意的正样本对和负样本对,都有
其中,是它们各自的句向量。说白了,我们只希望正样本对的相似度大于负样本对的相似度,至于大多少,模型自己决定就好。事实上语义相似度常见的评价指标spearman也是一样,它只依赖于预测结果的相对顺序,而不依赖于具体的值。
针对这类需求,可以用到Circle Loss理论里边的公式作为解决方案:
简单来说,就是如果最终希望实现,那么就往log里边加入一项。对应我们这里的场景,我们可以得到损失函数:
其中是一个超参数。上述公式本质上是一个为排序设计的损失函数,同样适用于多分类的数据,写成更通用的形式:
也就是说,只要我们认为样本对(i,j)的真实相似度应该大于(k,l)的真实相似度,就可以往log里边加入;换句话说,只要我们能够为样本对设计顺序,就可以使用CoSENT方案。
对于NLI数据而言,它有“蕴含”、“中立”、“矛盾”三种标签,我们自然可以认为两个“蕴含”的句子相似度大于两个“中立”的句子,而两个“中立”的句子相似度大于两个“矛盾”的句子,这样基于这三种标签就可以为NLI的句子对排序了。而有了这个排序后,NLI数据也可以用CoSENT来训练了。类似地,对于STS-B这种本身就是打分的数据,就更适用于CoSENT了,因为打分标签本身就是排序信息。
后续部分工作概括
PromptBERT
PromptBERT是句嵌入领域继SimCSE又一篇经典之作。
这篇工作的核心就是想用Prompt来产生句子表示。作者认为,原生BERT表现不好主要是因为词语频率、大小写、subword等token导致的bias,而BERT本身各层Transformer都没有纠正这个问题。通过利用prompt,可以更有效地使用BERT各层中的知识,并且用[MASK]来表示embedding的话,可以避免像以前一样做各种token的平均,从而避免了token引入的偏差。
这篇工作方法的核心思路也比较简单,分为两步:
Instrcutor Embedding
根据OpenAI的论文《Text and Code Embeddings by Contrastive Pre-Training》的说法,文本相似度和语义检索是两个不同的任务,训练目标可能存在一定冲突。随着训练进行,如果模型可能在语义搜索任务上的表现越好,在句子相似度任务上的表现可能就越差。同时,现有的Embedding模型面对新任务和新领域时,性能通常表现不佳。
而我们理想的Embedding显然应该同时具备多种能力。怎么能让Embedding模型同时适应多个任务,并且在新领域上有泛化性呢?
Instrcutor Embedding设计了一种基于指令微调的文本嵌入新方法:在文本输入之前拼接解释用例的指令(包含任务和领域信息)。Instrctor Embedding在训练期间为330个文本嵌入数据集手工编写了任务指令,并在 70 个嵌入评估任务(其中 64 个任务在训练过程中未见)上评估了 INSTRUCTOR,范围从分类和信息检索到语义文本相似性和文本生成评估,整体达到了一个较好的性能。
上一章节梳理了基于BERT-like models的Sentence Embedding的代表工作。其实,对于使用双向注意力机制的BERT-like models擅长做内容理解类的任务似乎是很合理的。但OpenAI Embedding模型较好的效果和OpenAI 对于Decoder-Only架构模型的坚持程度,以及近半年大模型的迅速发展,让我们不禁好奇,Decoder-only的大模型有没有可能在Embedding任务上也给我们一次惊喜?
对此我们进行了一些探索类的尝试。在摸索的过程中,我们最希望能搞清两个问题:
最终,经过我们对于Decoder-only模型padding方式、pooling方式、不同层各向异性程度的探究,最终得到的结论和当前部分公开结论相对一致。
针对第一个问题,《How Contextual are Contextualized Word Representations? Comparing the Geometry of BERT, ELMo, and GPT-2 Embeddings》论文进行了BERT和GPT不同层效果对比的探究实验,实验效果如下表:
根据上表,可以发现:
针对第二个问题,Instructor Embedding论文也给出了不同参数量模型的效果对比实验,如下表:
根据上表,可以发现:
综上,结合我们的实验,初步结论是:
当然,由于OpenAI并未公布他们Embedding方案的技术细节,或许我们还没有获取使用GPT来做Embedding的正确打开方式。也欢迎感兴趣的同学进一步讨论~
参考文献