从0训练LLM · 现代大模型体系 阅读 + 实验 ≈ 40 分钟 页内实验 ×3
C2 位置:模型怎么知道顺序 第 4 课

RoPE 到底旋转了什么?

RoPE 旋转了什么
把位置向量「加」到输入上,注意力分数里混着看绝对位置的交叉项;RoPE 改成按位置「转」Q 和 K,转完再点积,绝对位置被约掉,只剩 n − m。Qwen3.8 每个头 256 维里只转 64 维。
❓

本课一问:RoPE 的名字里有「旋转」。它转的是什么?为什么「转」一下,注意力就能直接感受到两个 token 相隔多远?

这一课先不碰:超长上下文的扩展(第 5 课);Q、K、V 各自从哪来、多头与 GQA(C3)。这一课只需要知道一件事:注意力给一对 token 打分,用的是 q·k 点积。

从已有出发

三条线索已经摆在桌上:

目标因此很明确:让注意力分数 qm·kn 带上位置,而且只带上 n − m。

从已有出发 · 累计数据流 点已学环节看形状与参数
解码层

点上面的「位置 RoPE」,能看到它在 Qwen3.8 里的真实形状;读完这一课,那几行字每一个都能解释。

先自己设计:把位置向量加在输入上

第 2、3 课的做法是把位置向量加到 token 向量上。为了看清打分里发生了什么,先把它直接加在 q、k 上,再点积。一对 token 相隔 3 个位置(m = 5、n = 2),然后把整句往后挪:

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案位置向量加在 q、k 上,再点积
整体平移(m、n 同时加)

看这组 8 维的 q、k(教学构造)
数字口径:q、k 是种子固定的 8 维教学构造(不是模型学到的);位置向量用 Vaswani 2017 的 sinusoidal 公式(d = 8、base = 10,000);RoPE 列按相邻两维一对、θi = 10,000−2i/8 旋转。全部在浏览器里现算。

真实的 Transformer 里,位置向量加在 x 上,再乘 WQ、WK。展开 (xm+pm)WQWKᵀ(xn+pn)ᵀ,同样是四项:内容×内容、内容×位置、位置×内容、位置×位置,中间两项仍然看绝对位置。我们项目的单元测试里有同样的对照(tests/test_core.py 的 test_additive_sinusoidal_is_not_relative):把 sinusoidal 加到 q、k 上,点积随整体平移而改变。

改进:不「加」,改成「转」

先回到 2 维,看最干净的情形。下面是旧版课程的 RoPE 演示,原样迁移:

下面是两个普通的 2 维向量(教学构造):q(提问的一方,在位置 m)和 k(被查的一方,在位置 n)。 RoPE 不给它们「加」任何东西,只是按各自的位置把它们转一个角度:位置 m 转 m × 20°,位置 n 转 n × 20°。 拖两个滑杆,盯住右边那个「旋转后点积」。

实线 = 转过之后的向量 · 虚线 = 还没转的原始向量 · 灰弧 = 两者当前夹角
Query 位置 m3
Key 位置 n1
操作记录 —— 只要 m − n 那一列不变,最后一列就一个数都不变

为什么点积只剩下 m − n(一行推导)
(R(mθ)q) · (R(nθ)k) = qᵀ R(mθ)ᵀ R(nθ) k = qᵀ R(−mθ) R(nθ) k = qᵀ R((n−m)θ) k

关键是旋转矩阵是正交矩阵:R(φ)ᵀ = R(−φ),而且两次旋转可以相加:R(α)R(β) = R(α+β)。 于是 m 和 n 只能以 n − m 的形式留下来,绝对位置在点积里被约掉了。 这正是苏剑林推出 RoPE 的方式——先立下「内积后只剩相对位置」这个方程,解出来就是旋转矩阵。

🎯

试四件事:① 先只拖 m,看「旋转后点积」一路变;再把 m、n 拖到相等,它精确地回到「旋转前点积」——相对位置 0 等于什么都没发生;② 连点几次「整体平移 +1」,绝对位置从 3、1 推到 7、5,操作记录里「旋转后点积」那一列一个数字都不动,这就是「只依赖 m − n」的现场证据;③ 紧接着点「只把 m +1」做对照,位置差一变,点积立刻跟着变;④ 顺手核对:中间那块「真实算术」是用 2×2 旋转矩阵逐个数字乘出来的,和解说里 cos 公式给出的值完全一致,这不是巧合,是旋转矩阵正交性的必然结果。

把「为什么只剩 m − n」逐项拆开:

RoPE 的核心恒等式 · RoFormer(Su et al. 2021)§3.4
ᵀ = qᵀk = qᵀk
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
苏剑林推出 RoPE 的方式正好反过来:先立下「内积之后只剩相对位置」这个方程,再解它,解出来就是旋转矩阵。

这条恒等式是严格推出来的,不依赖任何实验 。

从 2 维到真实维度:多个转速

真实的 q、k 不是 2 维。RoPE 把要旋转的维度两两一组切成若干个 2D 平面,每组各转各的,转速不同:第 i 组在位置 m 转 m·θi,θi = base−2i/d。每一组都单独满足上面的恒等式,各组点积加起来,整体仍然只依赖 m − n。这和第 3 课 sinusoidal 的频率公式同源,区别在于它乘在 q、k 上,不加在输入上。

锚点模型 Qwen3.8 的真实配置(anchor-model.json):每个注意力头 256 维,partial_rotary_factor = 0.25,所以只有 64 维旋转,分成 32 组;base(rope_theta)= 10,000,000。现算每组转一圈要多少个 token:

第 i 组转速 θi(弧度/token)转一圈要多少 token
i = 0(最快)16.28
i = 163.162e-419,869
i = 31(最慢)1.655e-737,969,062(约 3797 万)
位置 m 0
每个频率对在位置 m 转到的角度(每个小圈是一对 2 维;虚线圈 = 周期超过该模型上下文长度的那几对)
每个频率对转一圈需要多少个 token(对数刻度)

🎯

试三件事:① 把位置拖到 100:前几组已经转了十几圈,最后几组几乎没动——快的组分辨近处,慢的组分辨远处;② 切到 Qwen3-8B 和 DeepSeek LLM 67B,比较它们的 base 和最慢一组的周期;③ 看虚线圈:Qwen3.8 有几组在它的原生上下文 262,144 之内一圈都转不完?记住这个数,第 5 课要用。

⚠

常见误解之一:「每个维度都在旋转。」

Qwen3.8 的每个头 256 维里,只有 64 维旋转,另外 192 维完全不转。这 192 维上的打分只看内容,不带任何位置。只转一部分维度(部分旋转)不是 Qwen 的发明,GPT-J、GPT-NeoX 早就只转 25%;转多少是实验选出来的 。

常见误解之二(旧版课程的错误):「低频组要几千个 token 才转完一圈。」

实际远不止。Qwen3.8 最慢一组约 37,969,062 个 token 才转一圈;即使用最早的 base = 10,000、128 维(DeepSeek LLM 67B 的配置),最慢一组也要 54,410 个 token。

把这一步放回真实张量里。下图是 Qwen3.8 一个全注意力层里 Q 的旋转(K 做完全相同的事,只是 4 个头):

Qwen3.8 全注意力层:Q 按位置旋转(config 真实维度;可切小规模)
Q′ = RoPE(Qrot, m) ‖ Qpass
输入输出中间结果
边长按对数比例缩放,块边上的数字是真实值;同一维度符号的边在全图等长。
维度含义 真实规模 小规模
T 序列长度(「小明打了小王」在 Qwen3.8 里是 3 个 token) 3 3
Hq Q 头数(num_attention_heads) 24 2
Hkv KV 头数(num_key_value_heads) 4 1
dh 每头维度(head_dim) 256 8
dr 旋转的维数 = head_dim × partial_rotary_factor 64 2
dp 不旋转的维数 192 6
维度全部取自 anchor-model.json(Qwen3.8-27B 官方 config)。旋转没有参数;V 不在旋转路径上。
⚠

常见误解之三:「RoPE 给 embedding 加了一个位置。」

RoPE 不碰 embedding,也不在输入端做任何事。它发生在每一个全注意力层内部:q_proj、k_proj 算出 Q、K 之后,按位置旋转 Q 和 K,再打分。V 不旋转。Qwen3.8 的 64 层里只有 16 层是全注意力层,RoPE 只在这 16 层起作用;另外 48 层是线性注意力,不用 RoPE(C11 揭晓)。

🔍 真实代码里怎么两两配对?(相邻配对 vs rotate_half)

「两两一组」有两种写法。RoFormer 原文和我们项目的 minillm 把相邻的第 2i、2i+1 维配成一对;HF transformers 里 Llama、Qwen 一系的实现用 rotate_half,把第 i 维和第 i + d/2 维配成一对。GLM-5.3 的 config 里专门有一个字段标明它用哪种:rope_interleave = true(frontier-models.json)。两种写法只差一个固定的维度重排:把这个重排吸收进 WQ、WK 的列顺序,注意力分数完全相同 。它在理论上无关紧要,在工程上是真坑:把一种写法训出来的权重直接塞进另一种实现,不重排就全错。HF 的 Llama 权重转换脚本就是在对 Q、K 权重做这个重排。

🔍 Qwen3.8 config 里的 mrope_section [11, 11, 10] 是什么?

M-RoPE:把 32 个频率对分成三段,分别给时间、图像高、图像宽三种位置用,这是 Qwen2-VL 起为多模态加的(R2 §1.4)。纯文本输入时三种位置编号相同,三段转的是同一个 m,等价于普通的 1D RoPE,本课讲的全部成立。

最后算一笔账:RoPE 的旋转角全由位置和 θ 算出,0 个参数。对照第 2 课,如果 Qwen3.8 用可学习位置覆盖同样的 262,144 个位置,光位置表就要 1,342,177,280 个参数。

位置编码的演进,你在这里

位置编码的演进:每一代都被上一代的某个真数字逼出来
  1. 起点 不加任何位置信息 Vaswani 2017 §3.5 的前提
    解决了注意力对所有 token 一视同仁,一次矩阵乘并行算完。
    卡在交换「小明打了小王」为「小王打了小明」,每个 token 的输出向量逐位相同,差值 = 0(第 1 课在浏览器里实算)。
  2. 朴素 ① 把编号直接加进向量 最容易想到的做法
    解决了每个位置一个不同的数,简单直接。
    卡在编号没有上限:在位置 37,内容只剩位置信号的 2.7%(内容 RMS = 1 时;按项目初始化尺度只剩 0.054%)。
  3. 第一代 可学习的绝对位置向量 GPT-2 等
    解决了位置也查表,和词向量一样训练出来。
    卡在表有多少行就只能处理多少个位置:GPT-2 的位置表 1,024 行 × 768 维 = 786,432 个参数,位置 1,024 没有对应的行。
  4. 第一代 · 公式版 Sinusoidal 正弦位置编码 Vaswani 2017
    解决了不背位置,用多组 sin/cos 现算,任意位置都算得出来;两个位置编码的点积只依赖距离。
    卡在「算得出」不等于「会用」:原文表 3 里它和可学习位置几乎一样(dev PPL 4.92 vs 4.92,BLEU 25.8 vs 25.7);而且加在输入上,整句平移后注意力分数会变。
  5. 第二代 相对位置(在注意力里按距离加项) Shaw 2018、T5 等
    解决了直接告诉注意力「相隔多远」,语言规律在文章各处一样。
    卡在要改注意力的计算,为每个距离单独加一项,距离还被截断在 [rmin, rmax] 之内(RoFormer §2.3 的综述)。
  6. 第三代 RoPE 旋转位置编码 Su et al. 2021 你在这里
    解决了按位置旋转 Q、K,转完再点积,绝对位置被约掉,只剩 n − m;不加参数。
    卡在能算到任意长,却只在训练见过的角度内可靠:Qwen3 原生 32,768,64 个频率对里有 24 对一圈都没转满;Qwen3.8 原生 262,144,32 对里有 10 对。
  7. 解决了把新位置折算回见过的范围:Qwen3 32,768 → YaRN ×4 = 131,072;Qwen3.8 262,144 → ×4 ≈ 1M。
    卡在窗口 ≠ 有效长度:Qwen3.8-Flash-Next 技术报告自报,8 针 MRCR 在 128K 为 97.14,到 1M 只剩 20.71(全注意力版本)。
  8. 2026 分歧 部分 RoPE,还是干脆不要(NoPE) 2025–2026
    解决了Qwen3.8 只转 25% 的维度;Kimi K3、GLM-5.3-Flash 的全局注意力层不用任何位置编码,顺序交给线性注意力层。
    卡在Qwen 报告:全注意力层去掉 RoPE,预训练看不出差别,后训练后「停不下来」的比例明显升高——所以它保留了 RoPE。两条路线都做到了百万级上下文,没有唯一正解。
数字口径:GPT-2、Qwen3、Qwen3.8 的数字由 frontier-models.json / anchor-model.json 的官方 config 在构建时现算;表 3 数字出自 Vaswani 2017(本地 PDF);MRCR 数字出自 Qwen3.8-Flash-Next 技术报告表 3(官方自报,未经第三方复现);Qwen 的 NoPE 结论同一报告,只有定性描述。

证据三问

问本课的回答
① 它解决什么问题?让注意力分数直接依赖相对位置 n − m,位置不再和内容混在一起,而且不加任何参数
② 数学上为什么可能有效?RmᵀRn = Rn−m,点积里只剩相对位置 ;另外可以证明,多频率下打分的上界随距离衰减(第 5 课画出来),但「衰减是好事」只是动机
③ 实验上为什么最后选了它?RoFormer 自己的实验:WMT14 英德翻译 BLEU 27.3 → 27.5;中文长文本 CAIL2019-SCM 上,1024 长度的测试准确率 69.79%,高于 512 长度的 68.29%;EleutherAI 在 125M、1.4B 模型上报告比可学习绝对位置收敛更快

一句话

📌

RoPE 不给向量加位置,而是按位置把 Q 和 K 转一个角度;转完再点积,绝对位置被约掉,只剩位置差 n − m。

🚦

先停在这里:记住「转 Q、K,点积里只剩 n − m;Qwen3.8 只转 64 维」,就可以进 C3。
再深一层:展开上面两个 Dig(配对写法、M-RoPE),再去读苏剑林那篇。

下一个缺口

RoPE 是不是把绝对位置丢了?(岔路)→ 主线:能算出位置,是不是就能读懂长文?

你的提问

这一课来自一次真实的学习对话。学到这里,提问是:

「使用这种旋转的位置编码,似乎只保留了相对位置,缺少了绝对位置,这样效果是 ok 的吗。是实验证明的吗。还是有理论?」

这个问题值得单独一课:岔路课:RoPE 丢了绝对位置吗?LLM 的设计是证明出来的吗?