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

没训练过的位置,能不能用公式算出来?

用公式算位置
用多组不同转速的 sin/cos 现算位置向量,任意位置都算得出,两个位置的点积只取决于它们相隔多远。可是「算得出」不等于「模型会用」。
❓

本课一问:可学习的位置表背不下没见过的位置。能不能不「背」,而是给一条公式,任何位置代进去都能算出一个位置向量?

这一课先不碰:RoPE(第 4 课,它和本课的公式是亲戚,但用法完全不同)、超长上下文的扩展方法(第 5 课)。

从已有出发

第 2 课留下两条教训:位置信号的尺度不能无限增长(直接加编号会淹没内容);位置表只认表里有的行(GPT-2 只有 1,024 行)。所以新方案要同时满足三件事:任意位置都能给出一个向量;数值有界,和词向量量级相当;不同位置的向量互不相同。

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

先自己设计:从「查表」换成「现算」

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案学一张位置表(第 2 课的做法)
位置 p01…1,0231,024100,000
GPT-2 的位置表 P[p]✓ 有✓ 有…✓ 有✗ 查无此行✗ 查无此行

改进:多组不同转速的 sin / cos

公式本身不长,每一项都有用意。逐项点开:

正弦位置编码 · Vaswani et al. 2017 §3.5
= sin( · ), , ωi =
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
下面的组件取 d = 16(8 组),真实的原始 Transformer 是 d = 512(256 组),公式完全相同。
位置 p 3
8 根指针:第 i 根的角度 = p × ωi,ωi = 10,000−2i/16
位置 p 的编码:16 个数(每根指针贡献 sin、cos 两个)
一句话里两两位置的点积 PE(a)·PE(b)
PE(p)·PE(p + k) 随距离 k 的变化
数字口径:公式出自 Vaswani et al. 2017 §3.5,d = 16、base = 10,000,全部在浏览器里现算;项目 minillm 的 sinusoidal_table 用的是同一公式(sin 在偶数维、cos 在奇数维)。
🎯

试三件事:① 点「▶ 播放」,看 8 根指针的速度差多少:最快的一根每 6.28 个 token 转一圈,最慢的一根要 19,869 个 token;② 点预设 1,024 和 100,000,位置表查不到的位置,公式照样给出 16 个数,而且都在 [−1, 1] 之内;③ 在热力图下点「整句往后平移 +10」,绝对位置全变了,颜色一格不变——两个位置编码的点积只取决于它们相隔多远。

对话样本用了一个类比:「像钟表的秒针、分针、时针,几根针的组合表示时间。」它可以当入口,但要说清对应关系和不成立的地方:

两条可以证明的性质

有界、可算:任何 p 都能代进公式,每个分量都在 [−1, 1] 之间。

点积只依赖距离:用 sin a·sin b + cos a·cos b = cos(a − b),

PE(p)·PE(p+k) = Σi [sin(pωi)sin((p+k)ωi) + cos(pωi)cos((p+k)ωi)] = Σi cos(kωi)

右边没有 p,只有 k 。换句话说,两个位置编码之间的关系只由「相隔多远」决定。

原论文还多说了一句:对固定的 k,PE(p+k) 可以写成 PE(p) 的线性函数——每一组都是转一个固定角度 k·ωi。作者据此希望模型能容易地学会「按相对位置去关注」,也希望它能外推到比训练更长的序列 。注意这两个「希望」:它们是理论动机,不是结论。

另一个观察:语言更在乎「相隔多远」

「小明打了小王」前面如果多出一个 token,三个词的绝对位置都 +1,可「小明」和「小王」之间仍然隔着 2 个位置,语义关系一点没变。同样的主谓宾结构,出现在文章第 10 个 token 还是第 1,000 个 token,规律是一样的。

这引出了相对位置的思路:不告诉模型「我是第几个」,而是在注意力打分时直接加一项「我们相隔多远」。Shaw 等人 2018 年的做法是为每个相对距离学一个向量,距离超出范围就截断;T5 用的是按距离分桶的偏置(RoFormer 论文 §2.3 对这些方案有综述)。它们的共同代价是要改注意力的计算,为距离单独加项。第 4 课的 RoPE 做的是同一件事,却不加任何参数。

它在哪失败:算得出 ≠ 会用

公式能算出位置 100,000 的向量,不代表模型见到它时知道怎么办。两份证据:

原论文自己的对照。把公式版换成可学习的位置向量,开发集 PPL 4.92 对 4.92、BLEU 25.8 对 25.7,几乎没有差别 。在训练长度之内,两者一样好;选公式版的理由是「可能外推」,但论文没有去测。

我们自己模型上的实测。同一数据、同一步数,训练长度 128:

项目实测 · sinusoidal 在训练长度内外

🪤

我们踩的坑:sinusoidal 这一组在训练长度之内就明显更差。原因在实现:我们的 embedding 按 std = 0.02 初始化,而 sin/cos 的每个分量在 ±1 之间(均方根 1/√2 ≈ 0.71),两者直接相加,开局时内容只有位置信号的约 0.02 ÷ 0.71 ≈ 2.8%——正是第 2 课「位置淹没内容」的真实版本。原论文在相加之前先把 embedding 乘以 √dmodel(§3.4),我们的 dmodel = 256,就是乘 16。上图的虚线就是只改这一处的对照组(单个种子):差距的大头来自这一步。补上之后,它在我们的小模型上仍然落后于另外三组,越过训练长度也照样变坏——原论文是 6 层翻译模型训 10 万步,我们是 3.7M 参数训 400 步,实验条件不同,结论不能直接搬。

再按位置拆开看:512 长的序列里,训练长度之后的位置 loss 怎么变。

项目实测 · 公式算得出的位置,模型用不用得上

位置 128 之后,公式照样给出位置向量,loss 却明显变差:这些位置向量模型一次也没见过。「能算出来」只解决了「有没有向量」,没解决「模型会不会用」。

⚠

常见误解:「sinusoidal 就是 RoPE。」

两者的频率公式确实同源(都是 base−2i/d),用法却完全不同。sinusoidal 在第一层之前加到输入向量上,只加一次;之后内容和位置混在同一组数里,连 V 也带着位置。RoPE 在每一层注意力内部,乘(旋转)在 Q 和 K 上,V 不动。下一课会看到,正是「加」还是「转」这一步,决定了注意力分数里的相对位置干不干净。

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

位置编码的演进:每一代都被上一代的某个真数字逼出来
  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 结论同一报告,只有定性描述。

证据三问

问本课的回答
① 它解决什么问题?任意位置都能给出一个有界的位置向量,不用背表
② 数学上为什么可能有效?位置编码之间的点积只依赖距离 ;平移是每组转一个固定角度,所以作者希望模型容易学会相对位置、并且能外推
③ 实验上为什么选了它?原论文里它和可学习位置一样好(表 3),选它是为了「可能外推」;可外推这一点没被验证,我们的小模型上也没有外推好

一句话

📌

位置可以用多组不同转速的 sin/cos 现算,任意长度都算得出,两个位置的点积只看距离;但「算得出」不等于「模型会用」。

🚦

先停在这里:记住「现算解决了有没有向量,没解决会不会用」,进下一课。
再深一层:读 SideRef 里苏剑林的第 1 篇,看注意力分数展开后,绝对位置项和相对位置项各在哪里。

下一个缺口

能不能让注意力直接感受到「相隔多远」? → 第 4 课:RoPE 到底旋转了什么?

线索已经在本课里了:「平移 k 个位置 = 每组转一个固定角度」。第 4 课把这个旋转从输入上挪进注意力里,直接作用在 Q 和 K 上。

你可能会问