位置:模型怎么知道顺序
主线定位
点任一已学环节,看这一步的输入 → 输出形状、参数量,以及它解决了什么问题(数字取自 Qwen/Qwen3.8-27B 真实 config)。
- 上游 · C1 文字怎么变成数字:一句话已经变成一个 [T × 5,120] 的矩阵。但查表只看 ID,「小明打了小王」和「小王打了小明」得到的是同一组向量。
- 本章:解决「在哪里」。结论是 RoPE——在注意力内部按位置旋转 Q 和 K,不加任何参数;Qwen3.8 每个头 256 维里只转 64 维。
- 下游 · C3 注意力:这一章反复说「转 Q、K」「V 不转」,Q、K、V 却一直只是名字。C3 从它们开始,并在第 6 课回到 RoPE。
本章问题链
每一课只回答一个问题;上一课的失败,逼出下一课的问题。
| 课 | 这一课的问题 | 朴素方案在哪个真数字上失败 | 一句话 |
|---|---|---|---|
| 第 1 课 | 同样三个 token 换个顺序,模型分得出来吗? | 不加位置:两句话里同一个 token 的输出,最大差值恰为 0 | 注意力只看「有哪些 token」,不看「谁在前」 |
| 第 2 课 | 直接把位置编号告诉模型,行不行? | 位置 37 时内容只剩 1/37;GPT-2 的位置表只有 1,024 行 | 编号会淹没内容;位置表有多少行,就只认多少个位置 |
| 第 3 课 | 没训练过的位置,能不能用公式算出来? | 算得出,但越过训练长度 loss 照样变坏(项目实测) | 位置可以现算,但「算得出」不等于「会用」 |
| 第 4 课 | RoPE 到底旋转了什么? | 位置加在输入上:整句平移后打分变了(交叉项) | 转 Q、K,点积里只剩 n − m |
| 岔路 | RoPE 丢了绝对位置吗?LLM 的设计是证明出来的吗? | — | 用绝对位置去转,在点积里只留相对距离;设计靠三层证据 |
| 第 5 课 | 能算出位置编码,就能读懂长文吗? | Qwen3 原生 32,768 之内,64 组里有 24 组没转满一圈,直接外推越界 | 越界的是低频组,PI/NTK/YaRN 把它们折算回来;窗口 ≠ 有效长度 |
| 实验课 | 三种位置编码在我们自己的模型上比一比 | — | 只改一项、跑三个种子、连同条件报告结论 |
演进地图
- 解决了注意力对所有 token 一视同仁,一次矩阵乘并行算完。卡在交换「小明打了小王」为「小王打了小明」,每个 token 的输出向量逐位相同,差值 = 0(第 1 课在浏览器里实算)。
- 解决了每个位置一个不同的数,简单直接。卡在编号没有上限:在位置 37,内容只剩位置信号的 2.7%(内容 RMS = 1 时;按项目初始化尺度只剩 0.054%)。
- 解决了位置也查表,和词向量一样训练出来。卡在表有多少行就只能处理多少个位置:GPT-2 的位置表 1,024 行 × 768 维 = 786,432 个参数,位置 1,024 没有对应的行。
- 解决了不背位置,用多组 sin/cos 现算,任意位置都算得出来;两个位置编码的点积只依赖距离。卡在「算得出」不等于「会用」:原文表 3 里它和可学习位置几乎一样(dev PPL 4.92 vs 4.92,BLEU 25.8 vs 25.7);而且加在输入上,整句平移后注意力分数会变。
- 解决了直接告诉注意力「相隔多远」,语言规律在文章各处一样。卡在要改注意力的计算,为每个距离单独加一项,距离还被截断在 [rmin, rmax] 之内(RoFormer §2.3 的综述)。
- 解决了按位置旋转 Q、K,转完再点积,绝对位置被约掉,只剩 n − m;不加参数。卡在能算到任意长,却只在训练见过的角度内可靠:Qwen3 原生 32,768,64 个频率对里有 24 对一圈都没转满;Qwen3.8 原生 262,144,32 对里有 10 对。
- 解决了把新位置折算回见过的范围: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(全注意力版本)。
- 解决了Qwen3.8 只转 25% 的维度;Kimi K3、GLM-5.3-Flash 的全局注意力层不用任何位置编码,顺序交给线性注意力层。卡在Qwen 报告:全注意力层去掉 RoPE,预训练看不出差别,后训练后「停不下来」的比例明显升高——所以它保留了 RoPE。两条路线都做到了百万级上下文,没有唯一正解。
三层交互
| 层 | 本章里的组件 | 在哪一课 |
|---|---|---|
| 概念动画 | 正弦位置编码的 8 根指针(可播放);2D 的 q、k 按位置旋转 | 第 3 课、第 4 课 |
| 算法模拟器(真算法、小数据) | 置换演示(真注意力,3 个真 token);直接加编号的尺度崩塌;加法式与旋转式打分对照;多频率 RoPE(真实 config);长上下文扩展四种做法 + 远程衰减上界 | 第 1、2、4、5 课 |
| 真模型 / 真数据 | 我们自己从 0 训练的小模型:四组位置编码、三个种子、128 训练 / 512 测试的真实日志回放;GPT-2、Qwen3、Qwen3.8、DeepSeek-V4.1 的官方 config;Qwen3.8 真 tokenizer 的切分 | 第 2、3、5 课与实验课 |
项目推进:给我们的模型选位置编码
对应 04-实践项目/MILESTONES.md 的「C2 位置」。分工照旧:代码 AI 来写,决策你来做。位置编码的四种实现、RoPE 缩放(PI / NTK / YaRN)和对照实验脚本 experiments/exp_c2_position.py 已经写好,实验导出本章组件读取的 c2-position.json。
你要拍板的三件事
- 位置编码选哪种,理由是什么?理由要同时引用训练长度之内的 val loss 和超出训练长度之后的表现(第 2–5 课与实验课)。
- RoPE 的 base(rope_theta)取 10,000 还是更大?它决定最慢的一组有多慢、哪些组在训练长度内转不满一圈(第 4、5 课的组件可以直接算)。
- 如果要支持训练长度 2–4 倍的上下文:直接外推、PI、NTK 还是 YaRN?零样本还是准备续训?
验收标准(全部可测):
tests/test_core.py的 TestRoPE 5 项通过,其中 test_dot_depends_only_on_relative_position 要求平移 1–1000 个位置后,旋转后 q·k 的最大误差 < 1e-4。- learned 位置在超出训练长度时报错而不是静默出错(test_learned_positions_cannot_extrapolate),并能在课程里把它当成「外推失败」的真实现象来解释。
- 四组 run 的 val loss 表和超长评估曲线齐全(下图),能说出 none 与 rope 在训练长度之内差多少,以及为什么 none 没有崩(因果掩码透露了位置)。
- 长度外推不退步:以 RoPE 直接外推在 2 倍训练长度处的涨幅为基线(下表「2× 处涨幅」一列),之后任何改动不能让它变大;差距小于种子间标准差的改动不算数。阈值取自实测,不拍脑袋。
坑与带走
| 坑 | 症状 | 后果 | 怎么办 |
|---|---|---|---|
| 位置编码没加或加错 | 「猫追狗」和「狗追猫」输出接近 | 模型对词序不敏感 | 注意力本身没有位置概念,必须显式注入(第 1 课) |
| 把位置编号直接加进向量 | 位置越靠后 loss 越怪 | 内容被位置淹没,位置 37 时只剩 1/37 | 位置要做成有界的向量(第 2 课) |
| 用可学习位置,推理时输入更长 | 越界报错;强行延长后 loss 在训练长度处跳升 | 长输入不可用 | 换成能现算的位置编码,或截断(第 2 课、实验课) |
| sinusoidal 直接加在很小的 embedding 上 | 训练长度之内就明显更差 | 位置信号淹没内容 | 先把 embedding 乘 √dmodel(原论文 §3.4;我们踩过,第 3 课) |
| 以为 RoPE 加在 embedding 上、以为每一维都转 | 读 config 读不懂 partial_rotary_factor | 张量形状、参数量都对不上 | RoPE 在每个全注意力层里转 Q、K;Qwen3.8 只转 64 / 256 维(第 4 课) |
| 相邻配对与 rotate_half 两种写法的权重混用 | 换实现后输出完全乱掉 | 模型等于报废 | 两者差一个固定置换,移植权重要重排 Q、K(第 4 课 Dig) |
| 零样本用 PI 扩长度 | 连训练长度之内的 loss 都变高 | 短文本也变差 | PI 要续训;零样本优先只压低频的 NTK-aware(第 5 课、实验课) |
| 把「窗口 1M」当「有效 1M」 | 生产环境长文检索翻车 | 高估能力 | 窗口看 config,有效长度看 NIAH / MRCR / RULER(第 5 课) |
| 以为 DeepSeek-V4.1 的 1M 是原生 RoPE 外推 | 高估长上下文可靠性 | 选型失误 | config:65,536 × YaRN 16 = 1,048,576,是插值扩展的(第 5 课) |
| 把小模型上的实验结论直接搬到大模型 | 结论与论文相反 | 错误决策 | 引用实验结论时带上规模与条件(岔路、实验课) |
这一章你应该带走的(各课「一句话」):
- 注意力只看「有哪些 token」,不看「谁在前」:不注入位置信息,换个顺序只会把输出换个顺序。
- 位置不能当一个数加进去(会淹没内容);做成可学习的位置向量能用,但位置表有多少行,模型就只认多少个位置。
- 位置可以用多组不同转速的 sin/cos 现算,任意长度都算得出,两个位置的点积只看距离;但「算得出」不等于「模型会用」。
- RoPE 不给向量加位置,而是按位置把 Q 和 K 转一个角度;转完再点积,绝对位置被约掉,只剩位置差 n − m。
- RoPE 用绝对位置去转,在点积里只留下相对距离;LLM 的设计多数是「数学性质 + 理论动机 + 实验选择」三层叠出来的。
- 能算出位置 ≠ 读得懂长文:超出训练范围的是那几组没转满一圈的低频角度,PI、NTK-aware、YaRN 都是把它们折算回见过的范围;而窗口长度不等于有效长度。
深入这一章
每条都实际打开核对过(2026-09-26):写清它讲清了什么、对应哪一课、为什么推荐。spaces.ac.cn 对脚本访问有防护,浏览器里打开正常。
🎮 想更直观 10–30 分钟
🔬 想吃透原理 1–3 小时
📄 想读原文 按需
排除了什么(也是筛选标准):① 火山引擎开发者社区《从 ROPE 到 Yarn,一条通用公式速通…》(转载自知乎)——把 NTK-by-parts 讲反了,说高频插值、低频不动;② CSDN《一篇搞明白上下文长度扩展:从 RoPE 到 YARN》——多平台同步的转载,称 YaRN 把 Qwen3-32B「从 40K 扩展至 128K」(原生是 32,768),还有无出处的「99.8%」「显存降低 70%」;③ 博客园《大模型长度扩展:直接外推, PI, NTK-aware…》(2024-07)——目录逐节照搬另一篇 CSDN 文章,未注明出处;④ CSDN《【位置编码速通】从 ROPE 到 Yarn》——返回 521,且是同一篇速通文的转载;⑤ 对话样本引用的转载站 chenshi221.github.io——改为直接引用 Qwen3 技术报告原文。另注:B 站上李宏毅课程多为转载,本章给的是官方 YouTube。