位置编码:从绝对编码到 RoPE 到 NoPE,外推与内插¶
更新日期:2026-04-14
本文目标:覆盖所有主流位置编码方案,理解每种方案的数学原理、外推能力、工程实现,能根据需求选型和配置。
七、NoPE(No Positional Encoding)¶
7.1 核心观察¶
Causal Attention 的 mask 本身就隐含了位置信息:
- 位置 0 只能看到
[0] - 位置 1 能看到
[0, 1] - 位置 2 能看到
[0, 1, 2] - ……
每个位置的"可见集合"不同 → 模型可以隐式推断位置。
7.2 NoPE 的优缺点¶
7.3 RoPE + NoPE 混合(2025 新方向)¶
论文 "RoPE to NoPE and Back Again" 提出:不同层用不同编码。
class HybridAttentionModel:
def __init__(self, n_layers):
self.layers = []
for i in range(n_layers):
if i % 4 == 0:
# 每 4 层放一个 NoPE 层 → 提供长距离外推能力
self.layers.append(AttentionLayer(use_rope=False))
else:
# 其余层用 RoPE → 精确的位置感知
self.layers.append(AttentionLayer(use_rope=True))
# 效果: 兼得 RoPE 的精度和 NoPE 的外推能力
八、2D-RoPE(多模态位置编码)¶
8.1 用于 Vision Transformer¶
图像的 patch 排列在 2D 网格上,需要二维位置编码。
def apply_2d_rope(x, height, width, theta=10000.0):
d = x.shape[-1]
half_d = d // 2
# 前半维度: 编码行位置 (y)
freqs_y = 1.0 / (theta (arange(0, half_d, 2) / half_d))
# 后半维度: 编码列位置 (x)
freqs_x = 1.0 / (theta (arange(0, half_d, 2) / half_d))
# 每个 patch 的 (row, col) 坐标
rows = arange(height).unsqueeze(1).expand(height, width).flatten()
cols = arange(width).unsqueeze(0).expand(height, width).flatten()
# 分别编码行和列
angles_y = rows.unsqueeze(-1) * freqs_y
angles_x = cols.unsqueeze(-1) * freqs_x
# 拼接: 前半维度旋转 y, 后半维度旋转 x
x[:, :half_d] = rotate(x[:, :half_d], angles_y)
x[:, half_d:] = rotate(x[:, half_d:], angles_x)
return x
# Qwen2-VL 用这种方式 → 自然支持任意分辨率图像
九、CoPE(Contextual Position Encoding)¶
Meta 2024 提出,位置不是固定的,而是依赖内容计算的。
def cope_attention(Q, K, V):
# 传统: 位置是固定的整数 0, 1, 2, ...
# CoPE: 位置由内容决定
# 思路: 用 gate 网络计算每个 token 的"有效距离"
gates = sigmoid(gate_proj(K)) # [B, S, 1] ∈ (0, 1)
# gates ≈ 0: 这个 token "不占位"(如标点、停用词)
# gates ≈ 1: 这个 token "占一个位"(如实词、关键信息)
# 累积位置 = gate 的前缀和
positions = cumsum(gates, dim=1) # [B, S, 1]
# 不再是均匀的 0,1,2,3,...
# 而是类似 0, 0.1, 1.1, 1.2, 2.2, ...
# 用连续位置做 RoPE 或其他编码
Q = apply_rope(Q, positions)
K = apply_rope(K, positions)
...
优势:位置由语义决定,而非固定间隔。对代码(大量空格/缩进)和多语言(不同语言的 token 密度不同)更合理。
十、DoPE(Denoising RoPE,2025)¶
观察到 RoPE 在长序列中引入"位置噪声"→ DoPE 通过去噪改善。
十一、位置编码对 LLM 的影响¶
11.1 对训练的影响¶
11.2 对推理的影响¶
11.3 对 MLA 的特殊影响¶
MLA 中 RoPE 不能走压缩路径:
为什么?
设压缩操作为 C = W_down @ x (线性)
设旋转操作为 R(pos) (依赖位置)
如果先压缩后旋转: R(pos) @ W_down @ x
如果先旋转后压缩: W_down @ R(pos) @ x
这两者不相等! 因为 R(pos) 和 W_down 不交换。
所以 RoPE 部分必须走单独的通道,绕过压缩。
这就是 MLA 中有 d_rope 额外维度的原因。
十二、追问延伸¶
| 问题 | 方向 |
|---|---|
| 训练时 theta 怎么选? | 经验:基础模型用 10000,需要长上下文训练加大到 500K-1M |
| 2D-RoPE 怎么处理视频(时间维度)? | 加第三个维度做 3D-RoPE,或 temporal + spatial 分开 |
| 不同层用不同 theta 可以吗? | 可以,DeepSeek 研究过,但收益有限 |
| RoPE 和 Flash Attention 的兼容性? | 完全兼容:在 FlashAttention kernel 内部应用 RoPE |