当前位置:首页 > AI文本类

模型怎么知道「我」在句子开头还是结尾?位置编码与RoPE旋转位置编码拆解

1周前 (10-05)AI文本类17

rope-weizhi-cover.jpg

"我喜欢你"和"你喜欢我",用了完全相同的三个字,意思却相反。人靠字的先后顺序读出这层区别,但 Transformer 里的注意力机制,本质上对顺序是"瞎"的——把一句话里的字打乱顺序再输入,在没加任何位置信息之前,每一层的计算结果是同一批向量,只是下标换了位置。

要让模型读懂"先后"这件事,必须显式地往输入里注入位置信息。怎么注入、注入得巧不巧,直接决定了模型能不能把长句子、长文档里的顺序关系抓住。这篇沿着"为什么要位置编码"一路推到 RoPE 旋转位置编码。

注意力对位置不敏感,这是根子

先说结论:不加位置编码,Transformer 对输入的置换是"不变"的。原因在于它的两个核心部件——注意力机制和前馈网络——都只做"每个位置自身的运算 + 位置之间按内容交互的加权",没有任何一个地方用到了"这是第几个位置"这种天然的序。

注意力里的权重是靠词与词之间的内容相似度算出来的;前馈网络对每个位置用同一套参数独立变换。把整句话重新排个序,相似度那批值不会变,只是重新排列而已。模型分不出谁在前谁在后,自然也就无法建模"我喜欢你"里哪个字是主语。

解决的路径只有一条:给每个位置的表示,打上一个和它在序列中位置有关的标记。这个标记怎么设计,是接下来几代方案的差异所在。

正弦位置编码:把位置写成一组波

思路比较直接的一派,是把位置编码当成一个"加在输入向量上的偏置"。Transformer 原论文用的正弦位置编码,就是给第 pos 个位置、第 i 个维度,按正弦或余弦的函数取一个值,然后把这一整套值加到该位置的词向量上。

PE(pos, 2i)   = sin(pos / 10000^(2i/d))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d))

其中 pos 是位置,i 是维度对的下标,d 是向量维度。

选正弦、余弦,而不是随便一个递增序号,是有讲究的。不同频率的波叠加在向量的不同维度上,相邻位置之间会产生规律性的相对偏移,模型理论上能从中读出相对距离。而且这套函数可以外推到训练时没见过的更长的位置,不像一张固定表只能覆盖有限长度。

这类"把位置信息直接加到输入上"的方案,有个共同特点:位置信息是显式加进去的,添加的时机在信息进入注意力之前。它们简单、稳定,被广泛使用,但位置和内容的结合方式比较浅——位置只是"贴"在向量上,没有真正参与到内容之间的交互计算里。

RoPE:不「加」位置,而是把向量「转」过去

旋转位置编码(RoPE,Rotary Position Embedding)换了一种思路。它不做"加法",而是做"乘法"——具体说,是拿一个只和位置有关的旋转矩阵,作用在注意力里的查询向量 q 和键向量 k 上,把它们各自"转"过一个角度。

旋转这个动作,巧妙地绕开了"位置加在输入上"的老路。它的精妙之处在于:当位置 m 的 q,和位置 n 的 k 都被各自旋转之后,再做内积,这个内积的结果只和"相对位置差 m - n"有关,而和它们各自落在第几格无关。

为了看懂"旋转"具体是什么意思,先看二维的情况。一个二维向量 (x, y),把它逆时针旋转 θ 角,可以用一个旋转矩阵来表示:

R(θ) = [ cosθ   -sinθ ]
       [ sinθ    cosθ ]

(x, y) 旋转 θ 后 = (x·cosθ - y·sinθ,  x·sinθ + y·cosθ)

注意力里的 q、k 是 d 维向量,不是二维的。RoPE 的处理是把 d 维拆成 d/2 个"二维对":第 1、2 维是一对,第 3、4 维是一对,以此类推。每个二维对各自在自己的平面里旋转一个角度,这个角度的大小由"位置 pos"和"这个维度对对应的频率"共同决定。

对位置 pos,第 i 个维度对旋转的角度为:

    θ_i = pos / 10000^(2i/d)

即:频率沿维度对逐渐衰减,靠前的维度对转得快,靠后的转得慢。

于是,位置 m 的 q 先按 θ_i(m) 做多对二维旋转,位置 n 的 k 也按 θ_i(n) 旋转,然后两者内积。旋转的可加性保证了:两个向量分别转 m 和 n 的角度,再做内积,等价于只按"差值 (m - n)"做一次相对旋转后再内积。位置信息就这样从"第几格"转成了"隔多远",并且是"乘"进向量里的,而不是"贴"在表面上。

为什么相对位置比固定位置更好用

RoPE 带来的变化,得放到注意力分数里看。注意力分数本质上是 q 和 k 的内积。加了位置后,这个内积变成了:

q_m · k_n  →  q_m R(m) · k_n R(n)  →  结果只依赖 (m - n)

只依赖相对位置,意味着模型学到的是"这两个词隔了多远"这样的通用规律,而不是"第 3 个位置上的词长什么样"这种死记硬背。通用规律是可以迁移的——训练时学到"间隔两格的词该如何关联",在更长的上下文里照样成立。

这也解释了 RoPE 为什么在长文本扩展上更有优势:它天然地把位置信息表达成相对量,配合一些频率调度技巧,就能把训练时的长度外推到更长,而不必重新训练。相比之下,只加固定位置的方案,外推时常常要借助额外的插值或重训。

三种方案放在一起看

方案注入方式位置是固定还是相对长序列扩展
正弦位置编码加到输入向量上固定(但频率结构可推相对)可外推,需调基频
可学习位置编码加到输入向量上固定受训练长度限制,超出需插值
RoPE旋转矩阵乘到 q、k 上相对外推较好,是当前主流

表中"可学习位置编码"是正弦式之外的另一条路线:不是用固定公式算位置,而是把每个位置当成一个可训练的参数,让模型在训练中自己学。它表达灵活,代价是只能覆盖训练时见过的位置范围,遇到更长的输入就得想办法了。

理解 RoPE,抓住「旋转」和「相对」两个词就好

回头看整条线索:注意力本身对顺序无感,所以必须注入位置信息;早期的做法是把它"加"到输入上,简单但位置和内容的结合偏浅;RoPE 改用旋转矩阵把位置"乘"进 q、k,利用旋转的可加性,让注意力分数只依赖相对位置。

这一"乘",带来的不是一个更花哨的公式,而是一个更贴合语言规律的归纳偏置——句子里的两个词如何关联,本来就更多取决于它们离多远,而不是它们各自落在第几格。位置编码的历史,就是一步步把这个直觉变成数学实现的过程。

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。