位置编码——让大模型分清东西南北

位置编码——让大模型分清东西南北

最后更新:


2154 字 约 11 分钟

1.绪言

通过前面的文章,我们已经过了一遍从Token切分到向量化,再到投影 Q,KVQ, K V 从而计算注意力分数的流程

但是我们又会突然发现一个问题:我们似乎从来没有在意过Token的位置

回顾整个过程,我们只使用了每个Token的向量表示,并没有把它在原序列中的位置告诉模型,而对于人类的语言而言,词语相同而位置不同,所表示的含义可能完全不同

比如“AbelTomato喜欢zyt”和“zyt喜欢AbelTomato”就是完全不同的语义,这是主宾的交换所带来的语义变化,如果Transformer不知道Token的先后顺序,它又该如何区分这两个句子?

而这也是我们今天这篇将要解决的,让Transformer感知位置


2.Self-Attention不识顺序

为什么Self-Attention会无法辨别Token之间的顺序?我们来回顾整个计算的过程

首先 Q,KVQ, K V 都是每个Token向量经过相同的线性层变换得到的,这一步自然没有什么顺序上的关系

然后观察 qiq_{i} 和 kik_{i} 点积这一步,也可以发现,如果两个Token之间发生位置交换,最终的结果也只是 scoreiscore_{i} 的位置发生了交换

对于Token xix_{i},其输出表征其实可以表示为一个简单的加权和:

oi=α1v1+α2v2+...+αnvno_{i} = \alpha_{1} v_{1} + \alpha_{2} v_{2} + ... + \alpha_{n} v_{n}

其中的 αj\alpha_{j} 就是 qiq_{i} 与 kjk_{j} 点积得到,然后缩放做了归一化,这其中Token的顺序变化显然不会引起输出表征的变化,进而模型理解语义也不会发生变化

可以发现,如果只对输入的Token进行重新排列,由于在计算过程中,没有Token下标 ii 的直接参与,Self-Attention的输出也会随之进行相同的排列,而不会仅仅因为位置改变就理解出新的顺序含义,这个就叫做置换等变性


3.加入位置编码

为了破坏这种置换不变性,我们需要对每个Token向量加上对应的位置编码

假设经过Embedding处理后,得到的向量为 e1,e2,...,ene_{1}, e_{2}, ... , e_{n},我们现在加上位置编码向量,得到 e1+p1,e2+p2,...,en+pne_{1} + p_{1}, e_{2} + p_{2}, ..., e_{n} + p_{n},从而得到最终的Token向量 xi=ei+pix_{i} = e_{i} + p_{i}

这个时候再进行Token之间顺序的交换,就会出现 ei+pie_{i} + p_{i} 和 ej+pje_{j} + p_{j} 变成 ei+pje_{i} + p_{j} 和 ej+pie_{j} + p_{i} 的情况,这样一来,最后的结果就显然不同了


4.Sinusoidal

Sinusoidal位置编码就是Transformer架构中使用的经典位置编码,它的计算公式就是

PE(pos,2i)=sin⁡(pos100002id)PE_{(pos, 2i)} = \sin (\frac{pos}{10000^{\frac{2i}{d}}}) PE(pos,2i+1)=cos⁡(pos100002id)PE_{(pos, 2i + 1)} = \cos (\frac{pos}{10000^{\frac{2i}{d}}})

其中 pospos 是Token的位置,其中 ii 是维度,对于偶数的维度,使用 sin⁡\sin 编码,对于奇数维度,使用 cos⁡\cos 编码

我们已经知道,通过Embedding的处理,每个Token所得到的是一个长度为 dd 的向量 ee,既然要在这上面直接相加,那么位置编码的向量长度也需要是 dd

我们先固定Token的位置为 pospos,看位置编码向量的第一维:

PE(pos,0)=sin⁡(pos)PE_{(pos, 0)} = \sin (pos)

所以对于位置编码的第一维,每隔大概6.2个Token,这个维度的编码值就会绕完一圈

再看如果还是偶数,下一个维度,假设 d=512d = 512

PE(pos,2)=sin⁡(pos1.029)PE_{(pos, 2)} = \sin (\frac{pos}{1.029})

显然我们可以看出,当维度增大时,绕一圈所需的Token数量增加,周期变长,频率变低

不同维度拥有不同的周期,意味着它们观察位置的尺度也就不同,低维度上的正弦和余弦变化快,适合区分距离较近的Token;高维度上的函数变化慢,适合表示更大范围的位置变化

将这些不同频率的波组合起来,每个位置就能得到一个独特的位置编码向量,这也是Sinusoidal编码的原理

那么为什么要同时使用 sin⁡\sin 和 cos⁡\cos 呢?只用 sin⁡\sin 不行吗?事实上之前确实存在这样的一种位置编码,它只通过 sin⁡\sin 进行编码,但是有一个缺点就是它无法实现通过线性变换从一个位置的编码到达另一个位置的编码

而Sinusoidal方法,根据三角函数公式,有

sin⁡(pos+k)=sin⁡(pos)cos⁡(k)+cos⁡(pos)sin⁡(k)\sin(pos + k) = \sin(pos) \cos(k) + \cos(pos) \sin(k) cos⁡(pos+k)=cos⁡(pos)cos⁡(k)−sin⁡(pos)sin⁡(k)\cos(pos + k) = \cos(pos) \cos(k) - \sin(pos) \sin(k)

如果说,把同一个频率的两个维度写成一个向量形式

[sin⁡(pos)cos⁡(pos)]\begin{bmatrix} \sin(pos) \\ \cos(pos) \end{bmatrix}

那么显然,向后移动 kk 个位置的编码可以写成

[sin⁡(pos+k)cos⁡(pos+k)]=[cos⁡(k)sin⁡(k)−sin⁡(k)cos⁡(k)][sin⁡(pos)cos⁡(pos)]\begin{bmatrix} \sin(pos+k) \\ \cos(pos+k) \end{bmatrix} = \begin{bmatrix} \cos(k) & \sin(k) \\ -\sin(k) & \cos(k) \end{bmatrix} \begin{bmatrix} \sin(pos) \\ \cos(pos) \end{bmatrix}

也就是说,对于一个固定的位置间隔 kk,模型可以通过一个只与 kk 相关的线性变换,从位置 pospos 的编码得到位置 pos+kpos + k 的位置编码

Sinusoidal位置编码不需要参与训练,可以直接在使用之前根据公式计算出来,因此它是非学习型的位置编码


5.可学习型绝对位置编码

除了直接使用固定的Sinusoidal位置编码,我们也可以把每个位置的编码当成模型的参数,让模型自己学习

假设模型支持的最大序列长度为 LL,向量维度为 dd,那么可以定义一个大小为 L×dL \times d 的位置编码矩阵 PP

P∈RL×dP \in \mathbb{R}^{L \times d}

其中第 pospos 行就是位置 pospos 对应的位置向量 pposp_{pos},它与普通Embedding矩阵很相似,只不过普通Embedding根据Token编号查找向量,而位置Embedding根据Token所在的位置查找向量

最后仍然是采用一个相加的形式:

xpos=epos+pposx_{pos} = e_{pos} + p_{pos}

这种方法的优点是模型可以根据训练数据,自行学习什么样的位置表示最有用;缺点则是位置编码受到最大序列长度 LL 的限制,如果实际推理时的位置超过了这个长度,就没有对应的位置编码向量可以用

固定的Sinusoidal位置编码和可学习位置编码都属于绝对位置编码,因为它们都是描述的当前Token处于第几个位置

但是实际上,我们去看人类语言,更多的是相对位置而不是绝对位置,就比如说我爱你,看的是我在你前面,而不是我是第一个字,你是第三个字


6.从绝对位置到相对位置

绝对位置编码把位置信息加入Token表示之中,然后再计算注意力

qi=(ei+pi)WQq_i=(e_i+p_i)W_Q kj=(ej+pj)WKk_j=(e_j+p_j)W_K

模型则需要在这些混合后的向量中,间接学习位置 ii 与位置 jj 之间的关系

相对位置编码则不同,它更加直接,在计算注意力时显式地引入两个Token之间的距离 i−ji - j

通过这种方式,模型就更加容易学习像是相邻Token之间通常具有较强的局部关系、修饰词往往与附近的中心词相关等规律


7.RoPE:旋转位置编码

RoPE是当今LLM常见的位置编码方式,它使用的就是相对位置信息,全称为Rotary Position Embedding

与直接把位置向量加到Token Embedding的方式不同,RoPE主要作用于Query和Key

它把向量中每两个相邻维度看作一个二维平面,然后根据Token的位置,将这组二维向量旋转一定的角度

对于一个二维向量

[x1x2]\begin{bmatrix} x_1 \\ x_2 \end{bmatrix}

在位置 mm 上进行旋转之后,可以写成

Rm[x1x2]=[cos⁡(mθ)−sin⁡(mθ)sin⁡(mθ)cos⁡(mθ)][x1x2]R_m \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} = \begin{bmatrix} \cos(m\theta) & -\sin(m\theta) \\ \sin(m\theta) & \cos(m\theta) \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \end{bmatrix}

在不同维度对上使用不同的旋转频率 θ\theta,这一点也与Sinusoidal位置编码非常相似

假设位置 mm 上的Query经过旋转得到 RmqmR_{m} q_{m},位置 nn 上的Key经过旋转得到 RnknR_{n} k_{n},两者点积

(Rmqm)T(Rnkn)(R_mq_m)^T(R_nk_n)

又由于旋转矩阵满足

RmTRn=Rn−mR_m^TR_n=R_{n-m}

因此有

(Rmqm)T(Rnkn)=qmTRn−mkn(R_mq_m)^T(R_nk_n) = q_m^TR_{n-m}k_n

可以看到,最终注意力分数中的位置信息只与 n−mn-m 有关,也就是两个Token之间的相对位置,而不再只依赖它们各自的绝对位置

这就是RoPE的重要特点:通过旋转Query和Key,把相对位置信息自然地融入注意力分数之中


8.小结

Self-Attention本身不会主动理解Token的先后顺序。更准确地说,在没有位置编码时,它对输入序列具有置换等变性,即输入如何重新排列,输出就会跟着发生相同的排列

为了让Transformer感知顺序,我们需要额外引入位置信息

经典的Sinusoidal位置编码使用不同频率的正弦和余弦函数,为每个位置生成固定向量

可学习位置编码则把不同位置的表示交给模型自己学习,它们都主要从绝对位置出发

而相对位置编码以及RoPE进一步把重点放在Token之间的距离上。尤其是RoPE,它通过旋转Query和Key,使注意力分数自然包含相对位置信息,因此被广泛应用在现代大语言模型中

评论

评论会在审核后展示

正在加载人机验证...

查看原图