位置编码:正弦、RoPE、ALiBi


文档摘要

位置编码:正弦、RoPE、ALiBi 本节摘要:注意力是置换不变(Permutation-Invariant)的。「The cat sat on the mat」和「mat the on sat cat the」在没有位置信号时产出完全相同的结果——打乱 X 的行,输出行只是跟着打乱,注意力内部没有任何东西关心位置。对于词袋模型这不是 bug,但对于语言、代码、音频、视频——任何顺序承载意义的东西——这是致命的。

位置编码:正弦、RoPE、ALiBi

本节摘要:注意力是**置换不变(Permutation-Invariant)**的。「The cat sat on the mat」和「mat the on sat cat the」在没有位置信号时产出完全相同的结果——打乱 X 的行,输出行只是跟着打乱,注意力内部没有任何东西关心位置。对于词袋模型这不是 bug,但对于语言、代码、音频、视频——任何顺序承载意义的东西——这是致命的。修法是把位置信息注入嵌入,三个时代的答案各有各的赌注:正弦编码(Vaswani 2017,把 sin/cos 加进嵌入,简单、外推差)、RoPE 旋转位置编码(Su 2021,按位置旋转 Q 和 K,直接在点积里编码相对位置,2026 年统治一切)、ALiBi 线性偏置注意力(Press 2022,完全跳过嵌入,直接按距离给注意力分数加线性惩罚,长度外推极佳)。本节将带你从零实现三种方案,亲测 RoPE 的相对距离不变性,并梳理 YaRN、NTK-aware、LongRoPE 这些长上下文外推技巧。读完本节,你能说清为什么 RoPE 赢了,以及怎么把 8K 上下文扩到 128K。

学习目标

阅读完本节,你应当能够:

  1. 说明注意力为什么置换不变,以及这对语言/代码/音频这类有序数据为什么致命。
  2. 从零实现绝对正弦编码、RoPE、ALiBi 三种方案。
  3. 验证 RoPE 的相对距离不变性:平移绝对位置不改变点积,只改变相对距离。
  4. 区分 NTK-aware、YaRN、LongRoPE、位置插值等长上下文外推技巧,并知道何时用哪个。

一、问题与直觉

缩放点积注意力 softmax(QKᵀ/√d)V 由两两相似度算出。打乱 X 的行,输出行跟着打乱,注意力内部没有任何东西关心位置。对词袋模型这不是 bug;对语言、代码、音频、视频——任何顺序承载意义的东西——这是致命的。

修法是把位置注入嵌入。三个时代的答案:

  1. 绝对正弦(Absolute Sinusoidal,Vaswani 2017)。 把位置的 sin/cos 加到嵌入上。简单、无可学习参数、超出训练长度外推差。
  2. RoPE——旋转位置编码(Rotary Position Embeddings,Su 2021)。 按与位置成正比的角度旋转 Q 和 K,直接在点积里编码相对位置。2026 年统治一切。
  3. ALiBi——线性偏置注意力(Attention with Linear Biases,Press 2022)。 完全跳过嵌入,直接按距离给注意力分数加每头的线性惩罚。长度外推极佳。

到 2026 年,几乎所有前沿开源模型都用 RoPE:Llama 2/3/4、Qwen 2/3、Mistral、Mixtral、DeepSeek-V3、Kimi。少数长上下文模型用 ALiBi 或其现代变体。绝对正弦已成历史。

方案 A:绝对正弦

预计算一个固定矩阵 PE,形状 (max_len, d_model):

PE[pos, 2i] = sin(pos / 10000^(2i / d_model)) PE[pos, 2i+1] = cos(pos / 10000^(2i / d_model))

然后 X' = X + PE[:N],再过注意力。每一维是不同频率的正弦波,模型从相位模式里读出位置。超出 max_len 就失效:模型在训练里只见过 0~2047 的位置,你给它 2048 它就懵了。

方案 B:RoPE——为什么这么巧妙

RoPE 旋转 Q 和 K(不是嵌入)。对一对维度 (2i, 2i+1):

[q'_2i ] [ cos(pos·θ_i) -sin(pos·θ_i) ] [q_2i ] [q'_2i+1] = [ sin(pos·θ_i) cos(pos·θ_i) ] [q_2i+1] θ_i = base^(-2i / d_head), base 默认 10000

对位置 pos_k 上的键施加同样的旋转。点积 q'_m · k'_n 只取决于 (m - n)——也就是说,注意力分数只取决于相对距离,即使旋转本身是用绝对位置编号的。这是个漂亮的技巧。

RoPE 还能扩展:缩放 base(NTK-aware、YaRN、LongRoPE)就能不重训外推到更长上下文。Llama 3 就这么把 8K 扩到 128K。

💡 关键性质:对任意常数偏移 k,RoPE(q, m+k) · RoPE(k_vec, n+k) == RoPE(q, m) · RoPE(k_vec, n)(浮点误差内)。平移绝对位置不改点积,只有相对距离起作用。这个性质是 RoPE 全部价值的基石。

方案 C:ALiBi

跳过嵌入技巧,直接偏置注意力分数:

attn_score[i, j] = (q_i · k_j) / √d - m_h · |i - j|

m_h 是每个头专属的斜率(如 1/2^(8·h/H))。近的 token 被放大,远的被惩罚。无训练成本。论文显示其长度外推超过正弦,在原始训练长度上匹敌 RoPE。

2026 年怎么选

变体 外推能力 训练成本 用于
绝对正弦 免费 原 Transformer、早期 BERT
可学习绝对 微小 GPT-2、GPT-3
RoPE 配合缩放后好 免费 Llama 2/3/4、Qwen 2/3、Mistral、DeepSeek-V3、Kimi
RoPE + YaRN 极佳 微调阶段 Qwen2-1M、Llama 3.1 128K
ALiBi 极佳 免费 BLOOM、MPT、Baichuan

RoPE 赢,因为它不改架构就能插进注意力、编码相对位置,且 base 超参给了长上下文微调一个干净的旋钮。

二、从零实现

Step 1:正弦编码

完整代码见原课程 phases/07-transformers-deep-dive/04-positional-encoding/code/main.py。4 行核心:

def sinusoidal(N, d): pe = [[0.0] * d for _ in range(N)] for pos in range(N): for i in range(d // 2): theta = pos / (10000 ** (2 * i / d)) pe[pos][2 * i] = math.sin(theta) pe[pos][2 * i + 1] = math.cos(theta) return pe

PE[:N] 加到嵌入矩阵上,再进第一个注意力层。

Step 2:RoPE 施加到 Q、K

RoPE 原地操作 Q 和 K,对每对维度旋转:

def apply_rope(x, pos, base=10000): d, out = len(x), list(x) for i in range(d // 2): theta = pos / (base ** (2 * i / d)) c, s = math.cos(theta), math.sin(theta) a, b = x[2 * i], x[2 * i + 1] out[2 * i] = a * c - b * s out[2 * i + 1] = a * s + b * c return out

关键:对位置 m 上的 Q 和位置 n 上的 K 施加同一个函数。点积在每个维度对上拾起一个 cos((m-n)·θ_i) 因子——注意力白捡相对位置。

Step 3:ALiBi 斜率与偏置

def alibi_bias(n_heads, seq_len): slopes = [2 ** (-8 * (h + 1) / n_heads) for h in range(n_heads)] bias = [] for m in slopes: bias.append([[-m * abs(i - j) for j in range(seq_len)] for i in range(seq_len)]) return bias # 在 softmax 前加到注意力分数上

bias[h] 加到第 h 个头的 (seq_len, seq_len) 注意力分数矩阵,再 softmax。

Step 4:验证 RoPE 的相对距离性质

取两个随机向量 a, b,分别旋转 (pos_a, pos_b)(pos_a + k, pos_b + k),两个点积必须在浮点误差内相等。这个不变性正是 RoPE 的全部意义——绝对偏移无关,只有相对间距起作用。

三、框架对比:PyTorch 与 HuggingFace 的 RoPE 工具

PyTorch 2.5+ 在 torch.nn.functional 里提供 RoPE 工具;大多数生产代码用 flash_attnxformers,RoPE 在注意力 kernel 内部施加:

from transformers import AutoModel model = AutoModel.from_pretrained("meta-llama/Llama-3.2-3B") # model.config.rope_scaling → {"type": "yarn", "factor": 32.0, # "original_max_position_embeddings": 8192}

2026 年的长上下文技巧:

  • NTK-aware 插值。 从 4K 扩到 16K+ 时,把 base 重缩放为 base · (scale_factor)^(d/(d-2)),保护高频维度不被挤扁。
  • YaRN。 更聪明的插值,保留长上下文的注意力熵。Llama 3.1 128K 用的就是它。
  • LongRoPE。 微软 2024 的方法,用进化搜索为每个维度选不同的缩放因子。Phi-3-Long 用的就是它。
  • 位置插值 + 微调。 直接把位置按扩展因子压缩,微调 1~5B token。出奇地有效。

⚠️ 设计警示:别在生产里手写 RoPE 而不读 HuggingFace 的 modeling_rope_utils.py——它实现了 default、linear、dynamic、YaRN、LongRoPE、Llama-3 全套缩放方案,边界情况(奇数维度、混合精度)都处理过了。自造容易在长上下文踩坑。

四、可复用产物

原课程产出 outputs/skill-positional-encoding-picker.md:一个选择器 Skill,给定目标上下文长度、外推需求、训练预算,推荐编码策略(正弦 / RoPE / RoPE+YaRN / ALiBi)。

五、练习

  1. (Easy) 把正弦 PE 矩阵(max_len=512, d=128)画成热力图,确认「条纹随维度增大而变宽」的模式。
  2. (Medium) 实现 NTK-aware RoPE 缩放。在长度 256 上训一个微型 LM,在长度 1024 上测试有/无缩放的困惑度。
  3. (Hard) 在同一个注意力模块里同时实现 ALiBi 和 RoPE。在长度 512 的复制任务上训一个 4 层 Transformer,测试时外推到 2048,比较退化程度。

本节要点回顾

  1. 注意力置换不变:softmax(QKᵀ/√d)V 由两两相似度算出,打乱行只让输出行跟着乱——顺序无感知,对有序数据致命。
  2. 正弦编码:把 sin/cos 加进嵌入,无可学习参数,但超出 max_len 就失效——已成历史。
  3. RoPE 按位置旋转 Q 和 K:点积 q'_m · k'_n 只取决于 m-n,白捡相对位置;2026 年统治一切(Llama、Qwen、Mistral、DeepSeek)。
  4. RoPE 的相对距离不变性:平移绝对偏移不改点积,这是它的全部价值基石。
  5. ALiBi 跳过嵌入:直接 分数 - m_h·|i-j|,近 token 放大远 token 惩罚,长度外推极佳(BLOOM、MPT)。
  6. base 是 RoPE 的旋钮:增大 base 在推理时延长上下文,无需重训。
  7. 长上下文外推四件套:NTK-aware(护高频)、YaRN(保注意力熵,Llama 3.1 128K)、LongRoPE(进化搜索,Phi-3-Long)、位置插值+微调(出奇有效)。
  8. RoPE 赢的原因:不改架构、编码相对位置、base 给长上下文微调干净旋钮。

下一节,我们将把前几节的积木拼成完整的 Transformer——编码器和解码器,加上残差连接、层归一化与前馈网络。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U