Embedding
嵌入(Embedding)的目的是将分词器(Tokenizer)处理后的词转化为向量矩阵,也就是词向量。本节介绍一些传统的嵌入方法,和近些年提出的方法。
静态编码
静态编码的特点是每个单词只能得到一个固定的词向量表示。
独热编码(One-Hot Encoding)
将单词表示为一个长度为
缺点:独热编码无法表示单词之间语义的相似度,因为不同词之间的相似度都是一样的;独热编码很稀疏,会浪费空间。
Word2Vec
包括Skip-Gram(SG)和CBOW两种模型。SG模型需要根据目标词来预测上下文的词(即目标词左右的词,称为Context);而CBOW相反,需要根据Context来预测目标词,准确来说,是使用规定窗口范围内的Context的平均(或求和)来预测目标词。

SG模型

CBOW模型
二者存在以下区别:
训练速度不同。从训练集的样本数量来说,CBOW的样本数量比SG样本数量少得多。假设有
个目标词,窗口大小为 (目标词左右取 个Context Word),那么SG的样本数量接近 ,而CBOW的样本数量近似为 。训练效果不同。SG适用于相对少量的训练数据,对于稀有词的效果更好(可以得到表征能力很好的嵌入向量)。CBOW比SG的训练速度快了几倍,并且因为CBOW中对Context取平均,模型会预测更经常出现的单词,常用词的表征效果要比SG好一点。

Word2Vec的缺点和解决方法:
针对高频但意义不大的停用词(Stop Word,例如"the")充斥训练样本,可以通过设置在训练原始文本中遇到的每一个单词,它们按照一定概率保留,保留的概率与单词的频率成反相关。
在Word2Vec预测的时候,输出的是预测目标词的概率,也就是说每一次预测最后的Softmax层都要基于全部的词表进行计算,这无疑会带来很大的时间开销。为了加快训练速度,提出了层次Softmax(Hierarchical Softmax)和负采样(Negative Sampling)。
- 层次Softmax:使用树的层级结构替代扁平化的标准Softmax,在计算
时,只需要计算一条路径上所有节点的概率值。树的结构是根据类别的频数构造的霍夫曼树。 - 负采样:每次随机选择
个出现概率高的负样本(Negative Word,即预测错误的词)和正样本(Positive Word,预测正确的词)进行计算, 一般为2-20。
FastText
Word2Vec将每个单词作为最小单位,为每个单词生成一个向量,这忽略了单词内部的形态特征(如"apple"和"apples")。
介绍FastText之前,先介绍n-gram。基本思想是将文本内容按照字节顺序进行大小为
对于低频词生成的词向量效果会更好。因为它们的n-gram可以和其它词共享。
对于训练词库之外的单词,仍然可以构建它们的词向量。我们可以叠加它们的字符级n-gram向量。
FastText和CBOW一样,也包含输入层、隐含层、输出层,输入都是多个经向量表示的单词,输出都是一个特定的目标词,隐含层都是对多个词向量的叠加平均。不同的是,FastText的输入是上下文单词和n-gram的嵌入向量,CBOW只有上下文单词。FastText使用了层次Softmax。
FastText除了用来训练词向量,还可以用来做文本分类。
GloVe
根据语料库构建一个共现矩阵,矩阵中的每一个元素
其中
GloVe对比Word2Vec:
Word2Vec是局部语料库训练的,其特征提取是基于滑窗的;而GloVe的滑窗是为了构建共现矩阵,是基于全局语料的。因此GloVe需要事先统计共现概率;而Word2Vec可以进行在线学习,GloVe则需要统计固定语料信息。并且GloVe训练时收敛更快。
Word2Vec是无监督学习,同样由于不需要人工标注;GloVe通常被认为是无监督学习,但实际上GloVe还是有标签的,即共现次数
。Word2Vec损失函数实质上是带权重的交叉熵,权重固定;GloVe的损失函数是最小平方损失函数,权重可以做映射变换。
GloVe可扩展性好,对于很小或很大的语料库都可以有效地训练;另外,对于限制嵌入维度更低的情况,GloVe也表现很好。
动态编码
静态编码的每个单词都只能学出一个词向量,但在NLP工作中,单词在不同上下文中更可能有不同的意义。这就需要动态编码,也就是一个单词可以学出多个词向量。以下方法预训练阶段是无监督的,下游任务一般是有监督的。
ELMo
ELMO采用典型的两阶段过程:第一个阶段是利用语言模型进行预训练;第二个阶段是在做下游任务时,从预训练网络中提取对应单词的网络各层的词嵌入作为新特征补充到下游任务中。

预训练采用双层双向LSTM,训练任务是根据上下文预测目标单词。左端的前向双层LSTM代表正方向编码器,输入的是从左到右顺序的除了预测单词外的上文(Context-before);右端的逆向双层LSTM代表反方向编码器,输入的是从右到左的逆序的句子下文(Context-after);每个编码器的深度都是两层LSTM叠加。采用这样的网络,可以得到三个嵌入向量,分别是最底层单词的嵌入向量、句法特征的嵌入向量和语义特征的嵌入向量。
第二个阶段,比如下游任务是问答任务(QA),将用户查询(Query)和回复的三个嵌入向量加权整合,作为补充的新特征给下游任务,然后再进行下游任务的训练。ELMO给下游提供的是每个单词的特征形式,所以这一类预训练的方法被称为"基于特征的预训练(Feature-based Pre-Training)"。
缺点:LSTM的特征提取能力弱于Transformer;ELMO采取双向拼接这种融合特征的能力可能比BERT一体化的融合特征方式弱。
GPT

也是采用两阶段训练。区别是采用了Transformer,特征提取能力强于LSTM;并且预训练是单向训练,即只用上文不用下文。在微调阶段,GPT的损失函数要考虑语言模型的损失(即Decoder利用前

在序列前后增加两个特殊Token——"START"和"EXTRACT",分别表示开始和结束;而如果输入是两个序列,那么在它们中间增加一个特殊的Token"DELIM"。比如蕴含任务(Entailment),输入是前提(Premise)和假设(Hypothesis),输出是3个分类标签中的一个。如果是相似度计算,因为对称性,我们把它们交换顺序,然后输入两个Transformer。如果是多选题,比如给定一个问题和
BERT
BERT采用与GPT一样的训练方式,区别是采用双向语言模型,用MLM和NSP任务预训练。
MLM(Masked Language Model):随机Mask掉15%的单词,让语言模型去预测这个单词。为了弥补预训练和下游任务的差距(下游任务没有Mask),这些Mask的单词有10%的概率替换成随机的一个词,10%的概率替换成它本身,这样就能强迫模型在编码当前时刻的时候不能太依赖于当前的词,而要考虑它的上下文,甚至对上下文进行"纠错"。
NSP(Next Sentence Prediction):输入是A和B两个句子,判断B是否是A后面的句子。
BERT模型的输入包含三部分:词嵌入、位置编码嵌入和Segment嵌入(为了将多个句子区分,属于第一个句子的用0,第二个句子用1)。

BERT对不同的下游任务也有格式转换方法:

对比ELMO、GPT和BERT:
模型架构:ELMO采用LSTM,GPT和BERT采用Transformer。GPT利用Transformer的Decoder部分,BERT利用Encoder部分。
单向双向:ELMO和BERT都是双向语言模型,GPT是单向的,只能看到前边部分。ELMO实际上是两个单向语言模型(方向相反)的拼接,这种融合特征的能力比BERT一体化融合特征方式弱。
下游任务:ELMO采用Feature-based的方式,抽取预训练模型的隐藏状态作为下游任务的额外特征,与下游任务的嵌入向量结合起来,能适用于所有下游任务。GPT和BERT都是微调方式,预训练模型直接作为下游任务的网络架构,下游任务需要做格式转换以适应预训练模型的输入格式。
常用编码方法
嵌入模型常见架构
在RAG框架中,常见的两种用于文档检索的嵌入模型是双编码器(Bi-Encoder)和稀疏嵌入模型(Sparse Embedding Models)。
双编码器(Bi-Encoder)
双编码器的基本思想是使用两个相同的编码器来分别处理查询(Query)和文档(Document,或候选文档),然后将它们嵌入到相同的向量空间中。在检索阶段,Query和Document会被转化为固定长度的向量表示,然后通过计算Query向量和Document向量之间的相似度来进行匹配。
工作方式:Query和Document分别通过两个相同的编码器处理,每个编码器将输入转化为一个嵌入向量。这两个嵌入向量在同一个向量空间中表示它们的语义信息,之后根据相似度(例如余弦相似度)来判断查询与文档之间的相关性。
优点:这种方法的优势在于它具有较高的计算效率,因为查询和文档的编码是独立进行的,适合用于大规模数据集。通常,使用双编码器进行检索时,检索过程会非常快速。

稀疏嵌入模型(Sparse Embedding Model)
稀疏嵌入模型则是一种不同于稠密嵌入(Dense Embedding)的模型,通常基于传统的词袋模型(如TF-IDF)或稀疏编码技术。这些模型生成的嵌入是稀疏的,意味着嵌入向量中大多数元素的值是零,仅有少量非零元素。
工作方式:在稀疏嵌入模型中,文本的表示通常不是通过稠密的向量(如BERT生成的嵌入向量)来表示,而是通过一种稀疏表示,其中很多维度的值为零,只在少数维度上有较高的值。这种稀疏表示通常是通过词频或其他特征的权重计算得到的,常见的实现包括基于词频的向量化方法(如TF-IDF、BM25)和一些稀疏编码方法(如LDA等)。
优点:稀疏嵌入模型往往计算效率较高,并且可以避免高维稠密向量所带来的计算开销,特别是在大型文档库的检索中。此外,稀疏表示有时能捕捉到更加显著的词汇特征,适用于特定的检索任务,如关键词匹配等。
BGE v1
BGE,全称BAAI General Embedding,是智源研究院提出的开源通用向量模型,在过去短短一年时间内,在HuggingFace上总下载量已超数亿次,是目前下载量最多的国产AI系列模型。
论文:C-Pack: Packed Resources For General Chinese Embeddings
BGE训练的3个阶段:
(1)预训练:用WuDao纯文本语料训练,利用了RetroMAE,重建污染的编码向量;
(2)弱监督学习:用C-MTP无标签数据集训练,对比学习从负样本学习中如何区分出成对的文本;
(3)有监督微调:用C-MTP有监督数据集训练,由于标签数据是多任务的,所以加入了指令微调实现多任务下的微调。
BGE v1由6个模型组成,每种语言有'large'、'base'和'small'三款不同规模的模型。用户可根据需求平衡挑选更大能力更强的模型,或更小速度更快的模型。

后面又出了v1.5版本,主要缓解了相似度分布问题,并提升无指令情况下的检索能力。
下面分别对训练的每个阶段做详细的分析:
一、预训练
预训练阶段用的是2022年EMNLP上提出的RetroMAE。RetroMAE由两个主要部分组成:Encoder和Decoder。首先,输入文本经过掩码处理后被送入Encoder部分,由BERT组成(12层Transformer的Encoder构成)。Encoder使用BERT结构来处理输入并获取最终的[CLS]标记对应的隐藏层表示,这个表示作为整个句子的向量(绿色小方块)。然后,Decoder接收两个输入:一是经过掩码的句子,二是从Encoder中提取的[CLS]隐藏层表示,作为句子向量。Decoder部分是一个单层的Transformer,用于根据掩码输入和句子向量进行重建。
在训练过程中,模型的损失函数由两部分组成:一是Encoder的MLM(Masked Language Modeling)损失,负责通过掩码预测来学习语言的语法和语义;二是Decoder的重建损失,负责根据掩码的输入和Encoder的句子向量来恢复原始句子。整个模型的优化目标是同时最小化这两种损失。

工作流程如下:

通过三步构建了一个逐步细化的自监督学习框架:
首先通过Encoder获取句子的嵌入表示
然后通过Decoder利用该句子表示来重建掩码部分
最后通过增强编码阶段进一步利用上下文信息和句子嵌入进行全局恢复。
为了进一步提升性能,作者对Decoder进行了优化。具体来说,作者认为每个掩码Token基于相同的上下文进行重建过于单一,因此引入了双流自注意力(Two-Stream Self-Attention)和位置关注掩码(Position-Specific Attention Mask)。简单来说,Q(查询)和KV(键值)分别处理不同的上下文信息,去掉Cross-Attention,直接将Encoder中的句子编码融入Self-Attention中。在Transformer的Decoder中,通过Cross-Attention模块将Source Sentence的信息融入Target Sentence中,而在Enhanced Decoder中,通过改变Q、K和V,改变信息融合的方式(详情见上图的Part (c)部分):在Enhanced Decoder中,Q、K、V为:
在Enhanced Decoder中,除了第一行,每个Token都可以看见第一个元素和随机采样的词,对角线位置也是一定会被Mask掉的,最后得到每个Token的Context Vector。在计算注意力时,通过Mask机制使得每个掩码Token能够使用不同部分的上下文。这样做的目的是增加模型的复杂度,并提升其泛化能力。如下图所示:

Q:为什么编码器和解码器是非对称的?
A: 从论文创新的角度来看,这种设计是经过深思熟虑的。传统上,BERT主要用于MLM(掩码语言模型)和NSP(下一句预测)任务,通过获取[CLS]向量或最后一层隐藏层的输出,能捕捉一定的语义信息,作为语义嵌入用于文本检索等任务。自监督学习除了MLM,还包括对比学习和自编码器等方法,但对比学习的应用较多,并且对负采样有较高要求。现在,RetroMAE的创新点在于将自编码器的思想引入BERT,利用自编码器作为特征表征学习的方式,进而提升模型的性能。
BERT本身作为一个强大的编码器,而通过加一个解码器,采用自编码的方式去牵引原本的BERT模型,使得特征表征能更好地学习和优化,相当于为原有的BERT任务添加了一个新的学习目标——即"重建掩码输入"。这本质上是一个多任务学习的问题,其中一个任务是学习有效的语义嵌入,另一个任务则是通过解码器恢复原始输入,从而强化特征表征的学习。
从掩码率和模型的尺寸上,我们可以看到对解码器的要求非常严格,解码器的设计较为紧凑。通过这种方式,RetroMAE强迫编码器学习更高质量的特征表征,因为解码器的学习任务相对复杂,它要求编码器提供更精准的表示来进行有效的重建。因此,整个模型设计是为了迫使编码器在学习过程中更加注重语义表征的精度。
总的来说,RetroMAE将编码器和解码器设计为非对称结构,正是为了通过多任务学习的方式,提升模型的表征学习能力。需要注意的是,最终的嵌入(如BGE)主要来自于Encoder的[CLS]标记的最后隐藏层表示。
二、弱监督学习
在对比学习中,我们的目标是通过无标签数据集让模型学习区分正负样本的能力。具体来说,给定一个正文本对
其中:
表示正样本对 和 的相似度,通常使用点积或余弦相似度来计算。 是温度参数,控制平滑程度。 和 分别是正样本 和 的嵌入向量。
从抽象的角度来看,这个损失函数与Softmax类似,正文本对的相似度占所有文本对相似度之和的比例越大,损失越小。温度参数
难负样本采样
在对比学习中,负样本采样的质量对模型性能至关重要。特别是难负样本的采样非常重要,因为如果所有负样本都很容易区分,那么模型的损失会很小,梯度也会很小,导致模型收敛慢,且在复杂语义场景下,学习到的表示可能无法有效地区分正样本和难负样本。
然而,在本研究中,作者并未专门设计难负样本采样方法,而是采用了Batch内负采样(In-batch Negative Sampling)。具体来说,假设一个Batch中有
为了增加难负样本被包含的概率,作者使用了一个较大的Batch Size,设定为19,200,这样可以增加Batch中包含难负样本的可能性。通过这种Batch内负采样方式,模型能够在每个Batch中同时学习正样本和负样本,且由于Batch Size较大,能够确保难负样本得到有效利用,从而提升模型的区分能力并加速收敛。
三、有监督微调
由于标签数据含有不同有监督任务的数据,所以加入了指令微调实现多任务下的微调。具体做法是在Query前加入指令做微调,比如:指令"search relevant passages for the query" + Query。此外,除了Batch内负采样,还采用ANN-style采样策略从给定任务的原始语料中挖掘难负样本。具体来说,ANN索引(近似最近邻索引)被用来找到与正样本相似度较高但仍属于负样本的文档,从而进一步增加负样本的难度,帮助模型更好地区分正负样本,提升训练效果。
Conan-Embedding
最近在C_MTEB霸榜的嵌入模型,该工作来自腾讯。
论文:Conan-embedding: General Text Embedding with More and Better Negative Samples
训练过程主要分为两个阶段:弱监督预训练和有监督微调。

一、弱监督预训练
在预训练阶段,收集了7.5亿的文本对,参考了InternLM2.5中描述的标准数据过滤方法,通过以下四步进行过滤:
通过文档提取和语言识别进行格式化处理。
在基于规则的阶段,文本会经过规范化和启发式过滤。
通过MinHash方法进行去重;在安全过滤阶段,执行域名阻止、毒性分类和色情内容分类。
在质量过滤阶段,文本会经过广告分类和流畅度分类,以确保输出文本的高质量。
通过过滤,筛选了约4.5亿对数据,留存率约60%。
然后使用bge-large-zh-v1.5对数据进行评分,过滤掉得分低于0.4的低质量数据,最终筛选出4亿对数据。
预训练的方法和BGE类似,采用InfoNCE Loss,将Batch内的其他文本对作为负样本进行训练。
二、有监督微调
在这个阶段针对不同的下游任务进行微调,将训练数据分为检索任务(Retrieval,非对称型)和语义文本相似性任务(STS,对称型)两种任务类型。其中检索任务使用InfoNCE Loss,STS任务使用CoSENT Loss。
这个阶段还使用了两种优化技巧:动态难负例挖掘训练、跨GPU的Batch均衡训练。
动态难负例挖掘训练(Dynamic Hard Negative Mining,Dynamic-HNM)
嵌入模型的训练通常依赖对比学习,其关键在于正负例的选择质量。难负例(Hard Negatives)是与Query有一定相关性但与正例的区分较难的负例,能有效提高模型的对比损失效率。
传统的负例挖掘多在数据预处理阶段完成,这意味着负例是固定的。随着训练的进行,模型的权重更新可能导致这些固定负例对模型来说变得不再困难,从而降低训练效率。
为解决上述问题,Dynamic-HNM在训练过程中动态调整负例,主要步骤如下:
基于Teacher模型初始化难负例:
- 使用预训练Teacher模型为Query选择初始负例,这些负例需满足"有一定相关性但区分度低"的条件。
动态更新机制:
在每次权重更新后,记录当前负例与Query的相似性得分(例如Cosine相似度)。
每隔一定迭代步数(如100步),根据以下规则检测负例是否需要替换:
- 若负例与Query的相似性得分的1.15倍小于初始得分,且绝对值低于0.8,则判定该负例"不再困难"。
替换规则:使用最新的模型权重重新挖掘负例。
负例替换方案:
- 每次替换使用区间中的案例(如第
到 个案例),确保负例质量与多样性。其中 表示第次替换, 表示每次使用的难负例数。
- 每次替换使用区间中的案例(如第
低成本实现:
- 通过简单的Score更新与筛选逻辑,动态挖掘的成本仅相当于一个训练Step的计算代价。
下图展示了Dynamic-HNM和Standard-HNM的正负例相似性得分随训练步数的变化曲线:
Standard-HNM:负例得分在早期下降后趋于震荡,表明模型已"学会"这些负例。
Dynamic-HNM:在负例学习完成后自动替换新负例,使负例得分继续下降。

跨GPU的Batch均衡训练(Cross-GPU Batch Balancing,CBB)
这个优化点主要是通过优化任务训练流程和样本利用率,从而提高训练稳定性和模型性能。
将训练数据分为两种任务类型:
检索任务:通过对比学习优化Query和正/负样本的表示关系。使用InfoNCE Loss。
STS任务:语义文本相似性任务,通过监督学习训练模型,使其能够量化句子对之间的语义相似性。使用CoSENT Loss。
传统的做法通常是在顺序随机任务训练中,每个训练Step只处理一个任务(如iter0处理STS任务,iter1处理检索任务)。这种任务分配方式存在以下问题:
单任务优化方向不一致:单次优化方向可能与嵌入模型的全局优化目标偏离,导致梯度震荡和收敛困难。
负样本利用不足:检索任务中,负样本数量受单GPU计算能力限制,无法充分挖掘更多难负例。
针对这两个问题,CBB策略主要从以下两方面优化:
跨任务均衡
每个训练Step同时引入所有任务的Loss,确保优化方向与全局目标更一致。在单次Forward-Loss-Backward-Update中,计算所有任务的Loss并合并。
例如:检索任务从多个GPU中收集负样本,计算对比损失;STS任务在另一个GPU上计算STS任务的Loss。最后将所有Loss汇总,计算全局梯度并更新模型权重。
跨GPU负例共享
多个GPU共享相同的Query和正样本(确保一致性),但每个GPU有不同的负样本。例如:4个GPU分别处理不同的负样本集,并计算对应的对比Loss,汇总后整合所有负样本信息,提高训练效率和样本利用率。
Loss函数如下:
其中:
:Query和样本之间的相似性评分函数,通常为余弦相似度。 :温度缩放参数,控制对高相似性样本的敏感度。 :Query 和正样本共享的GPU数量。 :权重因子,控制两个任务在总Loss中的占比(经验值为0.8)。
下图展示了CBB策略的具体流程,包括:
多个GPU如何分配负样本。
各任务如何在单次迭代中计算Loss并合并。

如何选择合适的嵌入模型
语言支持和性能:大部分开源向量模型只支持单一或者有限的文本语言,所以需要确保嵌入模型支持的语言种类。多语言模型如OpenAI Embedding和bge-m3等模型能够处理多种语言。bge-m3支持100多种语言,适合多语言需求的场景。另外,某些模型在主要语言(如中文)中的表现较好,但在处理较少使用的语言时可能会表现不佳。因此,需要评估模型在所有必需语言中的准确性,以确保一致的性能。
处理长文本的能力:切分的文本片段后续需要通过嵌入模型进行向量化,所以必须考虑向量模型对输入文本块的Token长度限制,超出这个限制则会导致模型对文本进行截断,从而丢失信息,影响下游任务的性能。不同的嵌入模型对文本块长度的支持能力不同。比如,BERT及其变体通常支持最多512个Token,处理长文本时则需要将文本分成更小的块,意味着需要更加精细化的分块策略。而Jina AI的嵌入模型和bge-m3模型则支持8K的Token输入,适合处理长文本块。
模型在特定领域的表现:通用嵌入模型在特定垂直领域(如医学、法律和金融等)可能不如专用模型有效。这些领域通常需要专门训练嵌入模型来捕捉特定的专业术语和语境。为特定业务需求优化的嵌入模型能够显著提升检索和生成的质量。例如,通过结合向量检索和重排序(Reranking)技术,可以进一步优化结果。
存储和内存等资源需求:高维向量需要更多的存储空间,这可能会带来长期成本。例如,较高维度的模型如text-embedding-ada-002需要更多的存储资源。另外,较大的模型可能会占用更多内存,因此不适合内存有限的设备。
模型响应时间:嵌入模型的处理速度在实时应用中尤为关键。例如,intfloat/e5-base-v2模型在处理速度上表现优异,但需要在GPU上运行以达到最佳性能。在选择模型时,需要评估其在嵌入和检索过程中的延迟。例如,OpenAI的嵌入模型在许多基准测试中显示出较高的性能和较低的延迟。
通用的嵌入模型通常是在大规模、多样化的数据集上训练的,可能不完全适合特定领域的任务,比如医学、法律等专业领域,它们无法很好地理解一些专有词汇。如果模型在业务数据集上表现不能满足预期,可以通过微调,让模型学习到特定领域的词汇和概念,使其在特定应用场景中表现更佳。