RoPE

上一篇:[[Flash Attention]] 下一篇:[[GQA]]

RoPE(Rotary Positional Embedding)vs 绝对位置编码**

绝对位置编码(Absolute Positional Encoding)

Transformer 中原始的位置编码是将固定的正弦和余弦向量加到输入嵌入上:

$\text{PE}{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d}}\right) \ \text{PE}{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d}}\right)$

然后将位置编码加到输入 $x$ 上:

$x’ = x + \text{PE}(pos)$

这种编码方式在原始 transformer 中是不可迁移的,不能泛化到更长的序列。


RoPE(Rotary Positional Embedding)

RoPE 的核心思想是将位置信息通过复数空间中的旋转矩阵注入到 Query 和 Key 中,而不是加到输入上:

对每一对维度 $(x_{2i}, x_{2i+1})$,我们应用一个旋转:

$\begin{bmatrix} x_{2i}’ \ x_{2i+1}’ \end{bmatrix} = \begin{bmatrix} \cos(\theta_{pos}) & -\sin(\theta_{pos}) \ \sin(\theta_{pos}) & \cos(\theta_{pos}) \end{bmatrix} \begin{bmatrix} x_{2i} \ x_{2i+1} \end{bmatrix}$

其中:

$\theta_{pos} = \frac{pos}{10000^{2i/d}}$

RoPE 的优势:

二、绝对位置编码 vs RoPE(4 个 token)

我们设定嵌入维度为 4,每个 token 的初始嵌入为:

Token 位置Token 向量(简化)
pos = 0$[1.0,\ 0.0,\ 1.0,\ 0.0]$
pos = 1$[0.0,\ 1.0,\ 0.0,\ 1.0]$
pos = 2$[1.0,\ 1.0,\ 1.0,\ 1.0]$
pos = 3$[0.5,\ 0.5,\ 0.5,\ 0.5]$

绝对位置编码

位置编码是按维度加上 sin/cos 值,例如(使用 $d=4$):

$$ \text{PE}{(pos, 0)} = \sin(pos / 10000^{0/4}) = \sin(pos) $$ $$ \text{PE}{(pos, 1)} = \cos(pos) $$ $$ \text{PE}_{(pos, 2)} = \sin(pos / 10000^{2/4}) = \sin(pos / 100) $$ $$

\text{PE}_{(pos, 3)} = \cos(pos / 100) $$

我们用近似值展示:

posPE
0[0.0, 1.0, 0.0, 1.0]
1[0.84, 0.54, 0.0099, 0.9999]
2[0.91, -0.41, 0.0199, 0.9998]
3[0.14, -0.99, 0.0298, 0.9995]

最终输入向量:

$$ x_{\text{input}} = x + \text{PE}(pos) $$

这是一种“加法注入位置信息”,缺点是它和词义耦合、不能外推到更长序列。


RoPE 编码

RoPE 的想法是:在每对维度上做一个与位置相关的旋转,而不是直接加。

对于维度 $d = 4$,我们将 token 嵌入视作两个复数向量:

$$ [x_0, x_1], [x_2, x_3] \Rightarrow z_1 = x_0 + ix_1,\ z_2 = x_2 + ix_3 $$

然后乘以位置对应的旋转因子(也表示为复数):

$$ R_{pos} = e^{i\theta_{pos}} = \cos(\theta_{pos}) + i\sin(\theta_{pos}) $$

假设 $\theta_{pos} = 0.1, 0.2, 0.3, 0.4$ 对应 pos = 0,1,2,3

取 pos = 2 为例:

Token = $[1.0, 1.0, 1.0, 1.0] \Rightarrow z_1 = 1+i, z_2 = 1+i$

$$ z_1’ = z_1 \cdot e^{i\cdot0.3} = (1+i)(\cos(0.3) + i\sin(0.3)) \ \approx (1+i)(0.955 + 0.296i) = \underbrace{0.659 + 1.251i}_{\text{旋转后}} $$

对应新的向量:$$ [0.659,\ 1.251,\ \ldots] $$

我在上面的例子中简化了 RoPE 的旋转角度 $\theta_{pos}$,写成了比如 θ = 0.3 这样的近似数值,但没有解释它是怎么来的。现在我们来严谨说明一下:


我们严格地、不做近似地计算出 RoPE 应用于 Key(K)矩阵的结果。下面是你需要的详细步骤:

🧮 RoPE 应用步骤

设嵌入维度 $d = 4$,我们按 2 维一组,做复数旋转:

每组维度 (0,1) 和 (2,3) 分别旋转。我们使用以下公式:

旋转角度定义:

$$ \theta_{pos, i} = \frac{pos}{10000^{2i/d}} = \frac{pos}{10000^{i/(d/2)}} $$

二维旋转公式(实向量)

对向量中每一对分量 $(x_{2i}, x_{2i+1})$,应用旋转:

$$ \begin{bmatrix} x_{2i}’ \ x_{2i+1}' \end{bmatrix}

\begin{bmatrix} \cos(\theta) & -\sin(\theta) \ \sin(\theta) & \cos(\theta) \end{bmatrix} \begin{bmatrix} x_{2i} \ x_{2i+1} \end{bmatrix} $$


🧾 假设的 K 矩阵(4 个位置,每个 token 向量长度 4):

$$ K = \begin{bmatrix} 1.0 & 0.0 & 1.0 & 0.0 \ 0.0 & 1.0 & 0.0 & 1.0 \ 1.0 & 1.0 & 1.0 & 1.0 \ 0.5 & 0.5 & 0.5 & 0.5 \ \end{bmatrix} $$

我们现在为每一行计算 RoPE 编码结果,所有三角函数值保持精确。


📊 RoPE 编码后的 K 值表格

我们将每一行作为一组 token,每一列表示一次旋转计算步骤:

位置 $pos$$\theta_0 = \frac{pos}{10000^0} = pos$$\theta_1 = \frac{pos}{10000^1} = \frac{pos}{10000}$RoPE(0,1): $[x_0’, x_1’]$RoPE(2,3): $[x_2’, x_3’]$
000[1.0, 0.0][1.0, 0.0]
110.0001[$\cos 1$, $\sin 1$][$\cos 0.0001$, $\sin 0.0001$]
[0.5403, 0.8415][1.0, 0.0001]
220.0002[$\cos 2 - \sin 2,\ \sin 2 + \cos 2$][$\cos(0.0002) - \sin(0.0002),\ \sin(0.0002) + \cos(0.0002)$]
[-0.4161, 0.9093][0.99999998, 0.0002]
330.0003[$\cos 3 - \sin 3,\ \sin 3 + \cos 3$][$\cos(0.0003) - \sin(0.0003),\ \sin(0.0003) + \cos(0.0003)$]
[-0.9899, 0.1411][0.999999955, 0.0003]

简要说明每一行计算过程

行 1(位置 0):

$$ \theta_0 = 0,\ \theta_1 = 0 \Rightarrow \text{cos} = 1,\ \text{sin} = 0 $$ 旋转矩阵为单位矩阵 ⇒ 输出和原始一样。

行 2(位置 1):

$$ x_0’ = 0.5403×0 - 0.8415×1 = -0.8415,\quad x_1’ = 0.5403×1 + 0.8415×0 = 0.5403 $$

$$ x_2’ = 0×0.999999995 - 1.0×0.0001 = -0.0001,\quad x_3’ = 0×0.0001 + 1.0×0.999999995 = 1.0 $$

行 3(位置 2):

输入 $[1, 1]$:

$$ x_0’ = -0.4161×1 - 0.9093×1 = -1.3254,\quad x_1’ = 0.9093×1 + (-0.4161)×1 = 0.4932 $$

输入 $[1, 1]$:

$$ x_2’ = 0.99999998×1 - 0.0002×1 = 0.99979998,\quad x_3’ = 0.0002×1 + 0.99999998×1 = 1.00019998 $$

行 4(位置 3):

输入 $[0.5, 0.5]$:

$$ x_0’ = -0.9899×0.5 - 0.1411×0.5 = -0.5655,\quad x_1’ = 0.1411×0.5 + (-0.9899)×0.5 = -0.4244 $$

输入 $[0.5, 0.5]$:

$$ x_2’ = 0.999999955×0.5 - 0.0003×0.5 = 0.49984998,\quad x_3’ = 0.0003×0.5 + 0.999999955×0.5 = 0.50014998 $$

RoPE 对所有位置都这样做,只作用在 Q/K 上,不影响 Value 或嵌入向量本身,因此模型可以自动学习更强的相对位置感知能力。 下面我来澄清 transformer 中的位置编码 和 RoPE 作用的差异


✅ 传统 Transformer(如原始 Attention Is All You Need)

  1. Embedding 流程

  2. Q/K/V 来自线性变换: $$ Q = XW^Q,\quad K = XW^K,\quad V = XW^V $$ 所以位置编码间接地传递到了 Q/K/V

📌 注意:位置编码只在 embedding 层前加一次,影响 Q/K,但不直接作用在 Q/K 上。


✅ RoPE(旋转位置编码)有什么不同?

RoPE 的创新点是:

💡 所以 RoPE 是应用在 Q/K 上的位置编码,而非嵌入层

✅ 总结对比


总结表

项目绝对位置编码RoPE
形式加法(嵌入 + PE)Q/K 上复数旋转
优点简单直观支持长文本、保持相对顺序
缺点不可外推实现略复杂

为了解决这个问题,很多扩展方法被提出,比如:

这些方法可以让模型在不重新训练的前提下处理更长的输入。

上一篇:[[Flash Attention]] 下一篇:[[GQA]]