![多模态大模型:算法、应用与微调](https://wfqqreader-1252317822.image.myqcloud.com/cover/939/51709939/b_51709939.jpg)
1.2.1 位置编码
在Transformer模型中,直接将词元通过嵌入层后的向量输入到编码器中会有一些问题。我们需要知道的是,Transformer模型内计算注意力权重的操作是并行的,没有类似RNN的循环结构,因此并没有捕捉顺序序列的能力。也就是说,无论句子中单词的顺序怎么安排,Transformer模型最终都会得到类似的结果。为了解决这个问题,Transformer在处理输入序列时引入了位置嵌入(Position Embedding,也称为位置编码)来提供单词之间的顺序信息,这是一种将单词的位置信息嵌入输入词向量中的方法。它使用一系列额外的向量来表示单词之间的距离,从而提供了顺序信息。如图1-9所示,在Transformer模型中,位置编码的向量会与输入的词向量相加,从而可以综合考虑单词的语义信息和位置信息。
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0029-02.jpg?sign=1739269393-vby2mD1ImR3GvCT62Yu9CBKjSyz9vrMs-0-8afe004fef33133a9ec8120a7d85c01f)
图1-9 Transformer模型中的位置编码与词向量融合示意
位置编码的设计十分讲究,暂时抛开Transformer模型不谈,单单就位置编码方式来说,大体有两种选择:绝对位置编码和相对位置编码。
1.绝对位置编码
绝对位置编码相对来说比较简单:对于第k个输入向量xk,直接与位置向量pk拼接成xk+pk,其中pk是只依赖于索引k的。即便绝对位置编码比较简单,也出现了很多变种。
(1)训练位置编码
训练位置编码是一种最简单的位置编码方式,就是完全不定义任何规则,直接定义一个位置编码向量,然后在模型训练的过程中进行学习,也就是说,直接将这个位置编码当作一个可以学习的参数。BERT和GPT等模型所采用的就是这种位置编码方式。假如输入文本的最大长度是512,而编码的特征维度是768,那么就可以创建一个512×768的矩阵作为位置向量,然后让它随着训练过程逐渐更新。
python
self.pos_embedding=nn.Parameter(torch.randn(512, 768))
这种训练式的绝对位置编码的缺点就是没有外推性,也就是说,如果在训练的时候定义的最大句子长度是512,那么模型在推理时最多只能处理长度为512的句子,更长就处理不了了。
(2)三角函数位置编码
Transformer模型中所采用的是三角函数式的绝对位置编码,也称为Sinusoidal位置编码。假设输入序列的长度为N,编码向量的特征维度是dmodel,也就是说一句话对应的特征向量矩阵的维度是(N,dmodel)。接下来我们将矩阵按列分别进行编码,偶数列采用正弦函数编码,奇数列采用余弦函数编码。然后定义两个编码函数为
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0030-01.jpg?sign=1739269393-nVZ5QjfSbabIhW9trkNC0Ug934CcHS09-0-b779c230c8d80cfb7b456b47f1d1e76c)
其中pos是词元的位置数,i的取值范围则是从0到。
之所以采用三角函数进行位置编码,是因为它具有明显的规律性,以此期望它具有一定的外推能力,还有一个原因是三角函数的两角和公式为
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0030-03.jpg?sign=1739269393-WB6cX9oHKIEe8PHDN9HyLNcELDh7bKxZ-0-d65a8105a8e6ea3a5c19a844a415b6c9)
这说明α+β位置的向量可以表示成α位置的向量和β位置的向量的组合,也就是说后面的编码向量可以由前面的编码向量线性表示,这其实从侧面提供了模型单词之间的绝对位置。
相应的Python代码如下。
python
def get_position_angle_vector(position):
return [position/np.power(10000, 2 * (hid_j//2)/d_hid) for hid_j in range(d_hid)]
sinusoidal_table=np.array([get_position_angle_vector(i) for i in range(n_position)])
sinusoidal_table[:, 0::2]=np.sin(sinusoidal_table[:, 0::2]) #偶数列进行sin操作
sinusoidal_table[:, 1::2]=np.cos(sinusoidal_table[:, 1::2]) #奇数列进行cos操作
(3)递归位置编码
从理论上来说,RNN模型本身就具备学习位置信息的能力,因此可以通过递归结构训练一个可以捕捉序列位置关系的模型。如果在词向量输入之后先添加一个RNN层,随后使用Transformer模型,理论上就不需要再添加位置编码了。同样,我们也可以利用RNN模型来学习绝对位置编码,从初始向量p0开始,通过递归方式来生成各个位置的编码向量。
理论上说,基于递归模型的位置编码具备较好的外推能力,并且灵活性比三角函数式的位置编码更好。然而,递归位置编码的并行性不好,可能会导致模型训练变慢。
2.相对位置编码
注意力机制在计算时,实际上只需要考虑当前位置元素与被计算注意力分数的位置元素的相对距离,而不需要严格知道当前元素在输入序列中的绝对位置,因此相对位置编码的灵活性更大,可扩展性也更好。
(1)经典相对位置编码
因为是在计算注意力分数时丢失的位置信息,所以最直接的想法就是在这一层再加回来。于是,提出Transformer模型的原班人马发表了“Self-Attention with Relative Position Representations”(https://arxiv.org/abs/1803.02155),在计算注意力分数和加权平均时各加入了一个可学习的参数,用来表示元素之间的相对位置,并且这个相对位置编码参数可以在多头之间共享。
在计算注意力分数时,首先要计算:
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0031-02.jpg?sign=1739269393-FDWmOo8hKKGZE7IVNUOhVVewvffHua3r-0-90457b18ebbebd7a968886e00c98c3fc)
其中xi和xj分别表示两个位置的特征向量,pi和pj则表示两个位置的编码向量,接下来要计算注意力分数,即
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0031-03.jpg?sign=1739269393-QlduLAsyv3RBrEmuq48HrSbAn6zg27fE-0-3844332e505a07b71ab38c840a279bf8)
在这一步,将第一项的位置编码,pi去掉,然后将展开式中第二项的位置编码替换为二元位置向量
,变成
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0031-06.jpg?sign=1739269393-YD4mQKlub2VR97cbiETXNtCUD9hVBbYq-0-b59680171445da48459d13814c2bb9b1)
最后进行加权平均,即
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0032-01.jpg?sign=1739269393-FLRpLnEhHLqMPslNU28q9di6pM9VRc31-0-81735f1e8cdcdf409afc16c786cb0542)
同样将pjWV替换为二元位置向量,变成
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0032-03.jpg?sign=1739269393-9f9njzoHzrhset9jJtrR6JaOnGDJUgpm-0-f0ce3883d9eace2b0eb485a69257f6cd)
如果要用和
来表示和的相对位置,那么它们应该只与i和j之间的差值k有关,因此定义
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0032-06.jpg?sign=1739269393-weEiM4sWadRZLtAfEPTAZEvZYTzmYKBl-0-b9be86424ba12a4bcfb736529f453f42)
通过这种方式,即使只有固定长度的位置编码向量,也能够表达出任意长度的相对位置关系。
(2)T5相对位置编码
T5是一个通用的文本到文本的模型,适用于大多数NLP任务,它用了一种比较简单的相对位置编码方法。对计算注意力分数的式子进行全展开,得
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0032-07.jpg?sign=1739269393-Uv2WleVjhlOSTEwVs0jAXbLkczyon1L8-0-9946605d6e43ee78d185410decd56613)
因为x表示的是输入向量,p表示的是位置向量,所以上式可以分别理解为“输入-输入”“输入-位置”“位置-输入”“位置-位置”4项注意力分数。但是,输入向量与位置向量理论上应该是相互独立的,不应该计算注意力分数,因此可以删除中间两项。而对于最后一项,我们认为它只是一个用来表示相对位置的标量,只依赖(i,j),那就可以通过一个标量直接将其表示出来,这样注意力分数就可以简化为
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0032-08.jpg?sign=1739269393-gkDk3FlyHtCx8Iy6hwTZ01IGRlstNlHE-0-4c8b9598a8288c1cb66e4c4f522b48b7)
在代码层面,只要在简化的注意力矩阵上加入一个偏置项即可。
还有一点是,对于T5相对位置编码对(i,j),先对相对位置i-j做了分桶处理,然后才做截断处理,如表1-6所示,将i-j相对位置映射到f(i-j)。
表1-6 T5相对位置编码映射关系
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0032-09.jpg?sign=1739269393-gdwfNiZzdM333vW2p2WAAiLJ7pnO8Llu-0-82dbc44f6f08b99bdc95661e1f13bec3)
3.融合位置编码
绝对位置编码以其实现简单、计算速度快的优点受到欢迎,而相对位置编码则因为直观地体现了相对位置信号,往往能带来更好的实际性能。不过,如果我们能以绝对位置编码的方式实现相对位置编码,即采用融合位置编码,就能在保持简单和快速的同时享受更好的性能。旋转位置编码(Rotary Position Embedding,RoPE)就是为了实现这个目标而提出的一种融合位置编码方式,它将相对位置信息集成到了线性注意力层中,虽然按照定义应该属于相对位置编码,但是在性能上超越了绝对位置编码和经典的相对位置编码,并且它其实是以绝对位置编码的方式实现了相对位置编码。RoPE由苏剑林最早应用于自研的RoFormer模型,发表于论文“RoFormer: Enhanced Transformer with Rotary Position Embedding”(https://arxiv.org/abs/2104.09864)中。
RoPE主要是对注意力层中的查询(query, q)向量和键(key, k)向量注入了绝对位置信息,然后用更新后的两个向量做内积,由此引入相对位置信息。其中,q和k的形状都是(L,E),L是序列长度,E是嵌入维度。在计算注意力分数时,需要先计算q和k的内积,在这一步,RoPE设计了两个函数和
,用于给q和k添加绝对位置信息,即假设
和
运算会给q和k添加绝对位置信息。注意力机制的核心运算就是内积,所以我们希望内积的结果带有相对位置信息,而query向量qm和key向量kn之间的内积运算可以用一个函数g表示,g的输入是单词嵌入q、k和它们之间的相对位置m-n,即
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0033-05.jpg?sign=1739269393-396n7Zhp4NecXnSMx2xyYGZ1FikZQmbQ-0-1ce88a154cf11053fe69c1ff376ec4e6)
那么,我们要做的就是求出该恒等式的一个尽可能简单的解。所以,RoPE编码简单讲就是先通过函数f进行了绝对位置编码,又通过注意力机制的内积运算引入了相对位置编码。
在这里补充一点,RoPE的工作是建立在复数理论之上的,因此我们需要先介绍一些复数的相关知识。复数的本质其实就是旋转,如图1-10所示,试想在一个数轴上,1×(-1)其实表示的就是将(1,0)向量逆时针旋转180°。那么,有没有一个数能让1×i×i=-1呢,也就是将向量逆时针旋转两次90°?这就是对虚数单位i的直观理解。更进一步,欧拉恒等式其实表示的是将一个数持续旋转弧度,而它将指向相反的方向。
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0033-07.jpg?sign=1739269393-RK6ApT5u7Ns1O5srh58QKgCuoIbtkORn-0-2736ae6e97a981d7c92261a93cf7dea7)
图1-10 复数表示旋转的直观理解
复数可以用极坐标来表示,其中有两个参数:模和角度。模表示复数在复平面上的距离,而角度表示与正实轴之间的夹角。如果将二维向量看作复数的话,那么复数a和b就可以表示成和
,而它们的内积公式为
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0033-10.jpg?sign=1739269393-4p8poS7nec8d49zqWJksfWVymFSzfxJn-0-ec714ad3488ff038f1a30d04169271a8)
其中|a|与ra、|b|与rb分别是复数a和b的模,θa、θb分别是复数a和b的角度,表示两个向量的夹角的余弦值。
那么,在计算注意力分数时,我们可以先假设词嵌入向量的维度是二维,即E=2,而二维向量又可以写成极坐标的形式,这样就可以利用二维平面上向量的几何性质提出一个满足前面关系的函数:
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0033-11.jpg?sign=1739269393-U27ISbniPSLYPacJGqoHyPmwFDxUsNsp-0-6aa42ec0337a289d9a91798094cfdab0)
其中和分别表示模和角度。根据式(1-1)和内积公式,可以推导出
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-01.jpg?sign=1739269393-GogKWKlrsBMYflZqsCn1x6xOogcza5qz-0-82bfd065d2f31f946eebfefbaac6a456)
我们的目标是找到函数f的一个可行解,因此可以给f添加一些初始条件,简化求解过程,可以设和
。那么当m=n时,由式(1-2)可以得到
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-04.jpg?sign=1739269393-vu2GOhGlI1wJthID545REK3svTpDxPVl-0-0e2f8d17a63603900331d9408b007d5c)
由于计算内积g时实部只和m-n的相对值有关,所以
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-05.jpg?sign=1739269393-hxbF8CBByxKoljCp2m18Z6Wi3ZZX3nPH-0-f8926433d4943c4115c7f1e0982392ee)
因此,我们可以进一步简单假设:
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-06.jpg?sign=1739269393-FSgQtpRXSE2tWCBROITs1ObLTyyaVo1u-0-669c06da771c32d67128ca286a0041d9)
同理,当m=n时,由式(1-3)可以得到
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-07.jpg?sign=1739269393-DUV2o7SIliIfv5tSLNF2kUabWuTJUUre-0-e83e0ab270d39daa67c549541810ebc5)
整理得
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-08.jpg?sign=1739269393-g1buSrAKuXUvlt8NzzOxKN9hMOmoFqtl-0-5789de6e3fca8e18ccb5a962d695f149)
所以是一个只与m相关而与q无关的函数,定义为φ(m),即
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-10.jpg?sign=1739269393-jmv0H1X26JnwEeCNUQWjhnf25QCmgroc-0-aeaccc4c32b1e739c3e630b57a2d41ec)
可以发现
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-11.jpg?sign=1739269393-2TEp2GNcOloIGY84NiPWVnmoxdgPl3gb-0-69dbebb4b2f73d4cb9c0380178bd4f34)
也就是说,φ(m)-φ(m-1)的值也只与m相关而与q无关,这说明φ(m)是一个关于m的等差数列,那么可以进一步简单假设φ(m)=mθ,这里的θ是一个非0常数。根据式(1-4),我们可以得到
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-12.jpg?sign=1739269393-9T43gTx9EGsfT3zESASzelxRSakFBqDb-0-4574928bf48438cdfa5f079db7230e8e)
综上所述,有
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-13.jpg?sign=1739269393-2FAzpCb2amSPHnKVVmulHecjFEMOc6I3-0-2bf0c7aea46a6078dcffc64ea68deee2)
也就是说,我们找到了一个f的可行解。前面我们提到过,复数的本质其实是旋转,因此RoPE才被称为旋转位置编码。既然是旋转,那还可以将其写成矩阵的形式:
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0034-14.jpg?sign=1739269393-bnokHFeMVZ8rjK9vOF2zD2cl8ozzAZ3Y-0-8e36ff0e6177a2bce3e768ed313a04c8)
当然这还是在嵌入维度E=0的情况。当E>2时,一般来说嵌入维度会是一个偶数,那么可以直接将二维矩阵进行拼接,即
![](https://epubservercos.yuewen.com/0E5F9C/30516230407062906/epubprivate/OEBPS/Images/0035-01.jpg?sign=1739269393-Fmh8UoL1ofGY7tQcmPP8LxNpeBxWPzMR-0-9cf124276f6ceed24aa4b9ebdf44e364)
到此为止,RoPE位置编码的原理我们介绍完了,它巧妙地借助复数的表达形式,在注意力机制之前加入了绝对位置信息,而在注意力计算的过程中,又引入了相对位置信息。另外,RoPE相对于绝对位置编码和经典的相对位置编码来说还具有外推性。若外推性不好,则当大模型在训练和预测的输入长度不一致时,模型的泛化能力可能会下降。例如,一个模型在训练时只处理长度为512个token的位置向量,那么在预测时,如果输入文本超过512个token,模型可能会处理不好,从而影响其处理长文本或多轮对话等任务的效果。RoPE良好的外推性也使得它成为目前在大模型位置编码中应用最广的方式之一,已经被广泛应用在我们后面会介绍的Llama和GLM等模型中。