实验课:三种位置编码在我们自己的模型上比一比
这一课不讲新概念。前五课的每一条结论,都放到我们自己从 0 训练的小模型上核对:三种位置编码(可学习位置、sinusoidal、RoPE),再加一个什么都不加的对照组。所有图都直接读取实验导出的真实结果;每张图下面的「数字口径」一行写明了模型规模、语料、步数、种子和噪声。
这一课先不碰:续训版的 PI / YaRN(本轮只做了零样本)、更大的模型与更长的训练长度(C6 讲规模)。
实验是怎么设计的
对照实验的原则只有一条:一次只改一项。
- 只改位置编码:四组用同一份语料、同一个分词器、同样的层数和宽度、同样的学习率与步数。参数量只有 learned 多出一张位置表(训练长度 × d_model),其余三组完全相同。
- 训练短、测试长:训练长度 128;测试时把验证集切成 128、256、512 三种长度的窗口,三种长度覆盖同一批 token,val loss 是所有位置的平均交叉熵。
- 跑三个种子:图和表里的外推数字是三个种子的均值 ± 样本标准差;两组差距小于约 2 倍标准差时,组件会标「不下结论」。训练曲线和逐位置曲线只画第一个种子。
- RoPE 的缩放:用同一个 RoPE checkpoint,只改推理时的旋转(不缩放 / PI / NTK-aware / YaRN),不续训。
一、先猜,再看外推
读这张表要回答三个问题:① 训练长度 128 之内,谁最低?② 谁在 256、512 上根本跑不起来,为什么?(第 2 课)③ 虚线那组和 sinusoidal 实线差在哪?(第 3 课「我们踩的坑」)
二、训练过程
把指针移到曲线上,找两个时刻:哪一组最先拉开差距?训练结束时,val 与 train 的差(最右一列)哪组最大?注意这里的 train loss 是在固定的训练集窗口上评估出来的,不是小批次的均值,所以能和 val 直接比。
三、越过训练长度,坏在哪一段
竖线左边是训练见过的位置,右边是没见过的。每一组越过竖线之后怎么变,就是第 2–5 课在各自方案上讲的那件事。
四、RoPE 的三种折算方法
先把理论算一遍:我们的模型每头 32 维、base 10,000、训练长度 128,切到「我们的小模型」,四种做法各有几组越界、几组被压扁:
再看实测:
理论和实测对得上吗?三个核对点:PI 让所有组都不越界,却把训练长度之内的 loss 也抬高了(相邻角度被压扁,零样本用不好);NTK-aware 只压低频,训练长度之内几乎不受影响;YaRN 在这个小模型上几乎把每一组都插值了——因为训练长度只有 128,最快的一组也转不满 32 圈。
五、把结论对回前五课
| 课 | 那一课的结论 | 在我们的模型上看什么 |
|---|---|---|
| 第 1 课 | 注意力本身对顺序无感 | 「不加位置」这一组照样能学,loss 只是更高:我们的模型带因果掩码,掩码本身透露了位置(第 5 课误解二) |
| 第 2 课 | 位置表有多少行,就只认多少个位置 | learned 在 256、512 上是「✗」;强行延长(复用第 127 行)在竖线之后立刻跳升 |
| 第 3 课 | 算得出 ≠ 会用 | sinusoidal 越过竖线后变坏;不先乘 √d 时连训练长度之内都被位置淹没 |
| 第 4 课 | RoPE 让打分只看相对位置 | 训练长度之内,RoPE 这一组最低,和第二名的差距远大于种子间波动 |
| 第 5 课 | 越界的是低频组,折算能缓解 | RoPE 直接外推在竖线之后变坏;零样本折算里,只压低频的 NTK-aware 最稳 |
这些结论只在这个规模上成立:3.7M 参数、约 50 万 token 的语料、训练长度 128、400 步 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条我们自己的实验;三个种子的均值与标准差见表格;规模小,不能直接外推到十亿级模型。 出处待补 。第 4 课 RoFormer 的作者、第 5 课 Qwen 的 NoPE 反证都说明:有些差别到了更大的规模、甚至后训练之后才会显现。实验课的价值不在「证明谁最好」,而在练习先写下预测、再只改一项、最后连同条件一起报告结论。
六、为项目拍板
你要拍板的三件事(对应章首页的项目里程碑):
- 选哪种位置编码?依据上面的表:训练长度之内谁最好、谁 0 参数、谁有成熟的延长方案。
- 训练长度定多少?它决定了哪些频率对能转满一圈(第四部分的组件),也决定了注意力的计算量(C3)。
- 要不要为更长的输入预留缩放方案,用哪一种?看第四部分:零样本还是准备续训?
验收标准写成「不比实测基线更差」,而不是拍一个数:以本页 RoPE 直接外推在 2 倍训练长度处的涨幅为基线(表中「2× 处涨幅」一列),之后任何改动都不能让它变大;差距小于种子标准差的改动,不算改进也不算退步。
🔍 自己复现这个实验
脚本在 04-实践项目/experiments/exp_c2_position.py,训练配置沿用 04-实践项目/configs/baseline.json,只把 model.pos 换成四选一、训练长度设成 128;数据导出到 知识平台/src/data/project/c2-position.json,本页所有图自动读它。项目的 tests/test_core.py 里,TestRoPE 有 5 项测试:旋转后点积只依赖位置差、相对位置确实影响分数(反例对照)、加法式 sinusoidal 不满足平移不变(反例对照)、线性插值后依赖 (n−m)/s 且保持向量长度、放进完整注意力后整体平移分数不变;另有一项检查 learned 位置超出表长时报错。
一句话
同一数据、同一步数、只改位置编码:RoPE 在训练长度之内最好,但每一种方案越过训练长度都会变坏;零样本折算里只压低频的 NTK-aware 最稳,PI 必须续训。
下一个缺口
位置已经进了 Q/K,那 Q、K、V 到底是什么? → C3 第 1 课:已经有 Embedding 了,为什么还要变成 Q、K、V 三份?