Skip to content

RoPE

Rotary Position Embedding

RoPE 一般翻译成 旋转位置编码。它是 Transformer 中一种把位置信息注入注意力机制的方法。它最核心的想法不是“给每个位置加一个位置向量”,而是:

让查询向量和键向量随着位置做旋转,从而让注意力分数天然带有相对位置信息。

RoFormer 原论文对它的概括很直接:RoPE 用一个旋转矩阵编码绝对位置,同时在自注意力的内积里显式引入相对位置依赖。后来,Llama 2 等大语言模型也采用了 rotary positional embeddings。(RoFormer, Llama 2)

RoPE = 把位置变成“角度”,再把查询和键按这个角度旋转。

为什么需要位置编码

Transformer 的自注意力本身对顺序并不敏感。假设只有一组 token 向量,注意力只看到两两之间的相似度,而看不到“谁在前、谁在后”。

所以如果不给模型额外的位置线索,下面两句话在 bag-of-vectors 的意义上会很像:

  • “猫追狗”
  • “狗追猫”

它们词汇几乎一样,但顺序完全不同,语义也完全不同。

因此,Transformer 需要某种方式把“位置信息”注入进去。

传统位置编码的一个问题

最经典的做法是把位置编码直接加到 token 表示上,也就是所谓的绝对位置编码:

xmxm+pm

这里 xm 是第 m 个 token 的表示,pm 是第 m 个位置的位置向量。

这种做法当然有效,但它有两个常见问题:

第一,它是 加法式 的。位置和内容在进入注意力前就被混在一起了。
第二,它更容易表达“这个 token 在第几个位置”,但不够自然地表达“两个 token 之间相距多远”。

RoFormer 原论文正是从这里出发,提出了一种 乘法式 的位置编码:不是把位置向量加到表示里,而是直接对查询和键做位置相关的旋转。

RoPE 的核心想法

RoPE 的基本做法是:

  • 先照常从输入表示得到查询 q 和键 k
  • 再根据位置,把它们分别旋转一个角度;
  • 最后再做点积。

也就是说,RoPE 改的不是值向量,也不是 softmax 本身,而是 注意力分数里的查询和键

最重要的地方在于:

经过旋转以后,查询和键的点积会只依赖它们的相对位置差。

先看二维情形

先假设向量只有 2 维。给定一个二维向量

q=(q1q2)

如果它处在位置 m,RoPE 会把它旋转角度 mθ

R(mθ)=(cos(mθ)sin(mθ)sin(mθ)cos(mθ))

于是旋转后的查询写成:

q~m=R(mθ)q

同理,位置 n 上的键向量 k 也会被旋转:

k~n=R(nθ)k

为什么这样就有相对位置信息

注意力里真正用到的是点积:

q~mk~n

把定义代进去:

q~mk~n=(R(mθ)q)(R(nθ)k)

因为旋转矩阵是正交矩阵,有

R(mθ)=R(mθ)

所以:

q~mk~n=qR(mθ)R(nθ)k=qR((nm)θ)k

旋转后的点积不再分别依赖位置 mn,而是只依赖它们的差 nm

这正是“相对位置”想要的性质。

推广到高维

真实模型里的向量当然不止 2 维。RoPE 的推广方式很简单:

把整个维度切成很多个二维小块,每两个维度组成一对,各自做旋转。

如果隐藏维度是 d,那么可以把它拆成 d/2 个二维子空间。第 i 对维度使用自己的旋转频率 θi,于是位置 m 的整体旋转矩阵是一个分块对角矩阵:

RΘ,md=diag(R(mθ1),R(mθ2),,R(mθd/2))

RoFormer 原论文使用的频率是:

θi=100002(i1)/d,i=1,2,,d/2

很多代码实现会从 0 开始索引,于是也常写成

θi=100002i/d

本质上是同一个东西。

在注意力里怎么用

设第 m 个位置的输入表示是 xm。先做常规线性变换:

qm=Wqxm,km=Wkxm

然后再施加 RoPE:

q~m=RΘ,mdqmk~n=RΘ,ndkn

于是注意力分数变成:

q~mk~n=qm(RΘ,md)RΘ,ndkn=qmRΘ,nmdkn

所以 RoPE 的关键不是“某个位置有某个固定向量”,而是:

位置被编码进了查询和键的相对相位关系里。

为什么说它同时编码了绝对位置和相对位置

可以这样理解:

  • 对单个 token 来说,它在位置 m 上,就会被旋转到角度 mθ,这体现了 绝对位置
  • 对两个 token 的注意力分数来说,真正起作用的是 nm,这体现了 相对位置

所以 RoPE 是“每个 token 各自按绝对位置旋转”,但“最终注意力只依赖相对位置差”。这正是论文说的“encodes the absolute position with a rotation matrix and meanwhile incorporates the explicit relative position dependency”。

为什么不同维度要用不同频率

如果所有二维子空间都用同一个角速度,那么位置变化只会体现在一个单一尺度上,表达能力会很弱。

RoPE 让不同维度对使用不同的 θi,相当于:

  • 有的维度转得快,更敏感于短距离变化;
  • 有的维度转得慢,更适合表示长距离结构。

这和经典正弦位置编码里“不同频率共同表示位置”的思想非常接近,只不过 RoPE 不是把正弦余弦直接加到表示上,而是把它们做成旋转。RoFormer 论文也明确指出,RoPE 与原始 Transformer 的正弦位置编码在频率设计上有联系,但它采用的是乘法式注入。

一个很常见的实现写法

在代码里,RoPE 经常不会真的显式构造大旋转矩阵,而是写成更高效的形式。

如果把向量按偶数位和奇数位两两配对,那么可以定义一个“半旋转”操作:

rotate_half(x)=(x2,x1,x4,x3,)

然后位置 m 的 RoPE 可以写成:

RoPE(x,m)=xcosΘm+rotate_half(x)sinΘm

这里 是逐元素乘法,cosΘmsinΘm 是按位置预先算好的正弦余弦表。

这就是很多 Llama 风格实现里常见的写法:本质上仍然是二维旋转,只是实现上更省事。

RoPE 相比绝对位置编码的好处

第一,位置进入了注意力本身

绝对位置编码通常是先把位置向量加到输入表示上,再由线性层投影到查询和键。

RoPE 则是直接对查询和键做旋转,因此位置是直接进入注意力打分的。

第二,更自然地表达相对位置

RoPE 的点积天然只依赖位置差,因此对“两个 token 相隔多远”这件事表达得更直接。

第三,不依赖一个可学习的位置表

如果位置编码是一张 learned embedding table,那么训练时没见过的位置就没有现成参数。RoPE 本身由确定性的三角函数定义,因此没有这类“位置表长度”上的硬限制。RoFormer 论文把这一点概括为 sequence length flexibility。

不过这里要注意:

“没有硬性的参数表限制”不等于“可以无限长度无损外推”。

很多模型虽然使用 RoPE,但在超出训练上下文很远时仍然会退化,这也是后来出现 YaRN 这类上下文扩展方法的原因。YaRN 的核心就是在 RoPE 基础上更高效地扩展上下文窗口。

RoPE 和正弦位置编码的区别

原始 Transformer 的正弦位置编码通常写成:

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

然后把它直接加到 token 表示上。

而 RoPE 的关键区别是:

  • 正弦位置编码:加到表示上
  • RoPE:把表示旋转后再参与注意力

所以两者虽然都用了正弦 / 余弦频率,但注入方式完全不同。

RoPE 和 ALiBi 的区别

两者都常用于长上下文模型,但思路不同。

ALiBi 的做法是:在注意力分数上直接加一个与相对距离成线性的偏置。
RoPE 的做法是:对查询和键做旋转,再通过点积隐式体现相对位置。

简单说:

  • ALiBi 是 在分数上加偏置
  • RoPE 是 在向量上做旋转

它们都能表达相对位置信息,但机制不同。

为什么很多大语言模型喜欢用 RoPE

RoPE 之所以流行,有几个很现实的原因。

第一,它简单。实现时只需要对查询和键做一个固定形式的变换。
第二,它不需要单独维护大位置表。
第三,它在实践中对长上下文比较友好,因此被很多大语言模型采用。

Llama 2 论文明确写到,其架构使用了 rotary positional embeddings,并把上下文长度扩展到了 4096。

RoPE 的一个常见误区

一个常见说法是:

RoPE 天然就能无限外推。

这句话不严谨。

更准确的说法应该是:

  • RoPE 相比 learned absolute embedding,更不受“训练过的固定位置表长度”束缚;
  • 但模型是否真的能稳定处理更长上下文,仍然取决于训练分布、频率设置、缩放方法以及推理时的位置范围;
  • 因此才会有位置插值、NTK-aware scaling、YaRN 等上下文扩展方法继续研究如何在 RoPE 基础上扩展上下文。

总结

二维旋转:

q~m=R(mθ)q

高维推广:

q~m=RΘ,mdqm,k~n=RΘ,ndkn

相对位置性质:

q~mk~n=qmRΘ,nmdkn

经过旋转后,注意力分数自然只依赖相对位置差。

RoPE 的核心思想,是把位置看成旋转角度,并把这种旋转直接施加到查询和键上。这样一来,每个 token 都按自己的绝对位置被旋转,而两个 token 之间的注意力分数又只依赖它们的相对位置差。

与把位置向量直接加到表示上的方法相比,RoPE 以一种乘法式、几何化的方式把位置信息嵌入到注意力机制中。这也是为什么它在理论上优雅、实现上简单,并在 RoFormer 之后被 Llama 2 等大语言模型广泛采用。