LLM —— Position Embedding
👋 RoPE已成为当前LLM中最主流的位置编码方案,从 LLaMA、PaLM、GPT-NeoX 到 Baichuan、Qwen 等主流开源模型,以及许多商用LLM的核心架构,都广泛采用了 RoPE。要了解为什么RoPE能成为LLM中主流的位置编码,我们需要先了解为什么要有位置编码以及目前主流的位置编码原理。
Transformer 的自注意力机制本质上是置换不变 (Permutation Invariant) 的,无法区分序列中元素的顺序关系,导致模型退化为“词袋模型”。位置编码即将绝对或相对位置信息编码并整合到模型中,使模型能够理解序列的顺序结构。
位置编码的主要类型
绝对位置编码 (Absolute Position Embedding)
绝对位置编码为序列中每个位置的词元分配一个唯一的、基于其绝对位置的embedding向量。使用词元embedding融合,位置 $t$ (从 0 到 $T_{max}$)的绝对位置编码公式为:$x_t = v_t + p_t$ ($v_t$: 词元embedding, $p_t$: 位置embedding)。经典的绝对位置编码有:
- 正余弦编码 (Sinusoidal PE - 原始 Transformer): 这种编码方式的优点是确定性,无需学习,理论上可外推到训练时未见过的序列长度,但效果通常不佳,固定的函数形式可能无法最优捕获位置信息。维度 $i$ ($H$ 为embedding维度) 的值计算:
1
2
3
4p_{t, i} = {
sin(t / 10000^{(i-1)/H}) if i is even
cos(t / 10000^{(i-2)/H}) if i is odd
} - 可学习embedding (Learnable Embeddings - 如 BERT): $p_t$ 作为模型参数随机初始化并通过训练学习。这种编码方式的优点是灵活性高,可能捕获任务特定的位置模式。但是难以外推到显著长于训练序列的长度;增加参数量。
相对位置编码 (Relative Position Embedding)
建模 $Q$ 和 $K$ 之间的相对位置偏移 $(i - j)$,而非各自的绝对位置。通常用于修改注意力分数 $A_{ij}$ 的计算,而非直接加到词元embedding上。相对位置编码比绝对位置编码更好的外推 (Extrapolation) 能力,即处理显著长于训练序列的能力。代表方法有:
- Transformer-XL: 对原始注意力计算 $A_{ij} = x_i W^Q W^{K^T} x_j^T$ 进行分解,引入相对位置embedding $r_{i-j}$ 和全局可学习参数 $u$, $v$,用 $r_{i-j}$ 替换与绝对位置 $j$ ($p_j$) 相关的项,用 $u$, $v$ 替换与绝对位置 $i$ ($p_i$) 相关的项。
$$
A_{ij} = x_i W^Q W^{K^T} x_j^T + x_i W^Q W^{K^T} r_{i-j}^T + u W^{K^T} x_j^T + v W^{K^T} r_{i-j}^T
$$ - T5 (简化形式): 引入基于偏移 $(i - j)$ 的可学习标量$r_{i-j}$ 直接加到注意力分数上:
$$
A_{ij} = x_i W^Q W^{K^T} x_j^T + r_{i-j}
$$
旋转位置编码 (Rotary Position Embedding, RoPE)
利用基于绝对位置 $t$ 的旋转矩阵 $R_{\theta, t}$ 来编码位置信息,其巧妙之处在于 $R_{\theta, i} R_{\theta, j}^T = R_{\theta, i-j}$,从而在计算 $A_{ij}$ 时自然融入相对位置 $(i-j)$ 信息。具体实现:
- 旋转矩阵定义: 将 $H$ 维向量视为 $H/2$ 个 2D 子空间。对位置 $t$,子空间 $k$ 的旋转矩阵如下,整个 $R_{\theta, t}$ 是这些 2x2 块组成的块对角矩阵。$$[cos(tθ_k), -sin(tθ_k)]$$$$[sin(tθ_k), \space \space cos(tθ_k)]$$
- 基: $θ_k = b^{-2(k-1)/H}$ (通常 $b = 10000$)。
- 波长: $λ_k = 2π / θ_k = 2π b^{2(k-1)/H}$,表示在该子空间完成完整旋转 $2π$ 所需的距离。
- 计算过程:
- 计算 $Q$ 向量 $q_i = x_i W^Q$ 和 $K$ 向量 $k_j = x_j W^K$
- 应用旋转:$q_i’ = q_i R_{\theta, i}$, $k_j’ = k_j R_{\theta, j}$
- 计算注意力分数:$A_{ij} = (q_i’)(k_j’)^T = (x_i W^Q R_{\theta, i})(x_j W^K R_{\theta, j})^T = x_i W^Q R_{\theta, i-j} W^{K^T} x_j^T$
- 代码实现 (LLaMA 风格):
1
2
3
4
5
6
7
8
9
10def rotate_half(x): # 将向量后半部分取负并与前半部分交换
x1, x2 = x[..., :x.shape[-1]//2], x[..., x.shape[-1]//2:]
return torch.cat((-x2, x1), dim=-1)
def apply_rotary_pos_emb(q, k, cos, sin, position_ids):
cos = cos[position_ids].unsqueeze(1) # 按位置取 cos 值
sin = sin[position_ids].unsqueeze(1) # 按位置取 sin 值
q_embed = q * cos + rotate_half(q) * sin # 应用旋转 (q)
k_embed = k * cos + rotate_half(k) * sin # 应用旋转 (k)
return q_embed, k_embed
ALiBi (Attention with Linear Biases)
一种特殊的、无参数的相对位置编码,通过添加一个与相对距离 $(i-j)$ 成比例的线性惩罚项到注意力分数上,增强模型外推能力。ALiBi没有引入额外可训练参数,且能有效建模远超训练上下文窗口的序列,简单高效。计算公式如下:
$$
A_{ij} = x_i W^Q W^{K^T} x_j^T - m |i - j|
$$
- $m$ 是每个注意力头独有的、预先设定的惩罚系数。
- $|i - j|$ 是 $Q$ 位置 $i$ 和 $K$ 位置 $j$ 的绝对距离。
为什么LLM中常用的位置编码是RoPE?
RoPE能成为LLM主流位置编码,源于以下4个优点可以契合LLM的需求:
1. 显式编码相对位置信息,且具备数学完备性
- RoPE 通过旋转矩阵将绝对位置信息编码到 Q 和 K 中。其精妙之处在于旋转操作的数学性质:$R_i * R_j^T = R_{i-j}$。
- 优势:
- 注意力分数 $A_{ij}$ 的计算显式依赖于相对位置偏移 $(i-j)$ ($R_{i-j}$)。模型无需间接学习相对位置关系,效率更高。
- 旋转操作是线性变换且保持向量范数不变 $||R_i * v|| = ||v||$,不会破坏原始语义信息的分布特性,保证了数值稳定性。
2. 长期衰减性,契合语言建模的局部性
- RoPE 将向量划分为 $H/2$ 个 2D 子空间。每个子空间 $k$ 有一个波长 $λ_k = 2π * b^{2(k-1)/H}$。通过频率差异让模型自动学习不同距离的依赖模式。
- 低频子空间 ($k$ 小):$λ_k$ 极大(如数万/百万词元),旋转角度变化缓慢,需要极长距离才能完成一周旋转,负责捕捉长程依赖。
- 高频子空间 ($k$ 大):$λ_k$ 极小(如几十/几百词元),旋转角度变化快,微小距离即导致角度剧变,负责捕捉局部依赖。
- 优势:
- 模拟注意力偏好: 高频子空间在距离增大时,旋转角度快速变化导致 $Q_i$ 和 $K_j$ 的点积值指数级衰减。这完美契合了语言建模中“邻近词元更重要”的归纳偏好(Inductive Bias)。
- 避免人为强加限制: 不同于 ALiBi 的线性惩罚或窗口限制,RoPE 的衰减是数据驱动、自适应的,不同子空间/头自动学习不同的衰减模式。
3. 计算高效,零额外开销
- RoPE 的实现本质是对 Q/K 向量进行线性变换(逐元素乘 cos 和 sin 并重组)。关键代码仅需数行。
- 优势:
- 无额外参数: 仅需预计算 $cos/sin$ 表,不引入任何可训练参数,节省显存。
- 融合计算: 旋转操作可与 $Q/K$ 的线性投影 $(W^Q, W^K)$ 融合计算,或在 Attention 计算前轻量级注入,几乎不增加计算量。
- 硬件友好: 纯向量化操作(乘加),在 GPU/NPU 上高效并行。
4. 外推潜力与可扩展性
- 未经修改的 RoPE 在超出预训练长度时,高频子空间的旋转角度会远超 $2π$,导致未训练过的三角函数值出现,性能崩溃。因为 RoPE 的数学基础清晰,衍生出了多种高效且轻量的扩展技术(详细介绍见下节)。
- 优势: 这些扩展方法通常只需修改前向计算,不改变模型结构或参数量,易于集成到现有LLM系统中。
为何其他编码方案未成为主流?
- 绝对位置embedding (Sinusoidal/Learnable): 外推能力差,难以建模相对位置。
- T5-style 相对位置偏置: 引入大量参数 $r_{i-j}$,且外推能力有限。
- ALiBi: 无需训练的外推之王,但线性惩罚过于强硬,可能损害模型在中短距离上的表现精度,尤其需要精细位置感的任务如代码生成。更适合纯解码/极端长文本场景。
总结
特性 | RoPE | 绝对PE | T5相对 | ALiBi |
---|---|---|---|---|
显式相对位置编码 | ✅ | ❌ | ✅ | ✅ |
长期衰减性 | ✅ (自适应) | ❌ | ❌ | ✅ (线性) |
计算/参数量开销 | ≈0 | 低 | 高 | ≈0 |
短上下文精度 | ✅ | ✅ | ✅ | ✅ |
长上下文外推能力 | ✅ (需扩展) | ❌ | ❌ | ✅ |
扩展便利性 | ✅ | ❌ | ❌ | ✅ |
扩展位置编码 (针对 RoPE)以适用长上下文建模
当需要将预训练模型原始上下文窗口 $T_{max}$ 扩展到更长窗口 $T^*_{max}$ 时,通常有两种方法:扩展位置编码和调整上下文窗口。在扩展位置编码中, RoPE 的核心是将位置 $t$ 映射为旋转角度 $t * θ_i$ (其中 $θ_i$ 由底数 $b$ 和维度 $i$ 决定)。但是 RoPE 由于高频子空间(关键子空间)问题外推能力弱:
- 在 $H$ 维向量的 $H/2$ 个子空间中,低频子空间(对应小的 $i$)的波长 $λ_k$ 很长,例如 $λ_1$ 可能远大于预训练长度 $T_{max}$。这意味着模型在预训练时从未见过这些子空间完成一个完整周期 $2π$ 的旋转,只见过非常小的角度片段(如 $0-0.1π$)。当处理远超 $T_{max}$ 的序列时,对于这些高频子空间,旋转角度 $t * θ_i$ 会变得非常大,远超 $2π$ 或训练时见过的最大角度,导致注意力分数 $A_{ij}$ 计算出现分布外(OOD)问题,模型性能崩溃。
一种策略是不修改RoPE,直接在相应的长文本数据$T^*_{max}$上对模型微调,保持 $f(t, i) = t * θ_i$。然而超长位置 $t$ 的旋转角度 $t * θ_i$ 远超训练所见 $T_{max} * θ_i$,导致注意力值异常,收敛慢,需要大量数据。改进RoPE方法可统一形式化为修改旋转角度 $f(t, i) = t * θ_i \space => \space f’(t, i) = g(t) * h(i)$,其中 $g(t)$ 修改距离 $t$,$h(i)$ 修改基 $θ_i$。
位置索引修改 (Modifying Position Index $g(t)$)
修改位置索引来限制旋转角度不超过原始最大训练值 $T_{max} * θ_i$。位置索引的修改方法包括:
- 位置内插 (Position Interpolation - PI): 对所有位置索引进行缩放 $g(t) = (T_{max} / T^*_{max}) * t$。这种方法进行微调的训练代价较小,但是较短文本场景时会对模型产生负面影响。
- 位置截断 (Positional Truncation): 这种方法无需微调即可应用于更长上下文,保持短文本能力,但是需要二次计算注意力矩阵,增加计算开销。设定一个窗口 $w$ ($w <= T_{max}$)。
1
2
3
4
5g(t) = {
t, if |t| <= w, // 近距离保留
sign(t) * w, if |t| > w (ReRoPE), // 远距离截断到 w
sign(t) * (w + (T_max - w) * (|t| - w) / (T'_max - w)), if |t| > w (LeakyReRoPE) // 远距离线性插值
}
基修改 (Modifying Base $h(i)$)
针对高频子空间波长 $λ_i > T_{max}$ 未见过完整旋转的问题,通过增大底数 $b$ 或直接修改 $θ_i$ 来减小其基 $θ_i$,从而增大波长 $λ_i$,使得在目标长度 $T^*_{max}$ 上旋转角度 $T^*_{max} * h(i)$ 不超过 $2π$ 或接近预训练见过的角度范围。即调整波长 $λ_i > T_{max}$ 的子空间(未经历完整旋转周期训练)的旋转角度分布。主要方法包括:
- 底数调整 (Base Scaling / NTK-aware Scaling): 增大底数 $b$ 来缩小基 $θ_i$ (因为 $θ_i ∝ b^{-2(i-1)/H}$)。新基 $h(i) = (α * b)^{-2(i-1)/H}$。可无需微调 ($α$ 足够大) 或结合少量微调提升长文本能力。使用极大 $b$ (如 $1e8$) 微调效果更好。缩放因子 $α$ 选择:
- 静态 NTK-RoPE: $α = (T^*_{max} / T_{max})^{(H/(H-2))}$ (近似)。
- 动态 NTK-RoPE: $α = max(1, T / T_{max})$ (根据当前输入序列长度 $T$ 动态调整)。
- 基截断 (Base Truncation): 设定阈值 $a$, $c$ ($a < c$),防止远距离位置产生异常大的、未训练过的旋转角度。这种方法可能提升外推性能,但削弱了部分子空间对不同距离的区分能力,可能损害模型性能。
1
2
3
4
5h(i) = {
θ_i, if θ_i >= c, // 高频子空间保持
β (固定小值), if a < θ_i < c, // 中频子空间截断
0, if θ_i <= a // 低频子空间置零
}
本文主要参考中国人民大学《大语言模型》一书第5.2和5.4章节。关于RoPE更详细介绍可以看: