如果你把一个训练长度只有 4K 的模型直接拿去读 8K 的文本,结果不是“后面那 4K 内容它记不住”,而是从第 4097 个 token 开始,困惑度像断崖一样往上跳——模型开始复读、乱跳主题,甚至生成不存在的词。我第一次看到这个实验曲线时,还以为是评测代码写错了。后来把每一层都翻了一遍才发现,问题几乎不在“记忆”上,而在一个更安静、更底层的部件:位置编码。

Transformer 没有顺序,位置是后加的
Transformer 本身没有顺序概念。你把一句话的词随机打乱再喂进去,它的注意力计算路径和原句没有任何区别——注意力是对一个集合做加权求和,集合是无序的。所以每个 token 都必须带一个“座位号”。早期模型用两种办法:
- 绝对位置:每个位置学一个固定向量。BERT、GPT-2 就是这么干的。位置表训练到 512,推理时你想要第 1000 个位置?对不起,表里不存在。
- 相对位置:让注意力只依赖两个位置之间的距离。RoPE(旋转位置编码)是这种思路的代表。
读到这儿你可能会想:相对位置总该能外推了吧?如果距离是 9000,模型只需要知道“很远”不就行了?——这是我最早的误解,也是很多人卡住的地方。
RoPE 已经“相对”了,为什么还是崩?
我过去一直以为,模型只要学会了“相对距离”这个抽象概念,就能泛化到任意距离。后来读了 RoPE 原文 才意识到:RoPE 确实让 attention logits 变成了相对位置的函数,但它没有告诉模型“距离 9000 应该怎么分配注意力”。模型在训练时见过的距离差只有 -4095 到 4095。距离差为 8000 的注意力模式,是它从未学过的函数输入。
| 位置编码方案 | 外推性 | 失败原因 |
|---|---|---|
| 可学习绝对位置 | 几乎为零 | 超过位置表就没有向量 |
| 正弦绝对位置 | 理论上可行,实际很差 | 模型仍依赖训练范围内的位置模式 |
| RoPE 相对旋转 | 超范围陡降 | 相对距离差超出训练区间,高频旋转角开始混淆 |
| ALiBi 偏置法 | 相对较好 | 固定斜率无法覆盖所有尺度 |
旋转角度超过 π 的那一刻,位置认不出来了
RoPE 的细节值得展开。它把每个位置 m 的 q 向量和 k 向量按分量旋转。对第 i 对维度,旋转角度是:
theta_i = 1 / base ** (2 i / d)
base = 10000
angle = m * theta_i
两个位置 m 和 n 的距离差 d = m-n 进入 attention logits 时,也要乘同样的 theta_i。训练长度是 4096,那么训练中距离差最大就是 4095。当测试时距离差变成 8000,某几个高频维度的旋转角会比训练时大近一倍。问题就出在这些维度上:如果 8000 * theta_i 已经转了好几圈,cos 和 sin 的周期性会让“距离 8000”和“距离 8000 减掉一个周期”产生几乎相同的旋转向量。
这会带来什么?模型在训练中学到的“距离越大,注意力越弱”的单调先验,超出了某个阈值后开始周期性反弹。高频维度说“我和他很近”,低频维度却说“我们很远”。互相矛盾的证据把 attention 的 softmax 分布搅乱,模型只能复读和胡说。这是我很长时间里没有想通的机制——外推崩溃不是“预测能力不够”,而是位置特征本身出现了混叠。
正弦绝对位置也没好到哪儿去
你可能会问:原始 Transformer 用的是连续的正弦位置编码,理论上可以生成任意长度的位置向量,为什么还是不能外推?答案是:能生成新位置,不等于能理解新位置。这篇 长度泛化研究 专门测过:在短训练、长测试的设置下,正弦位置编码的 Transformer 在超出训练长度后预测质量接近随机;反而是某些相对位置编码和 ALiBi 能做到不崩溃。
原因在于:位置向量的生成函数是连续的,但模型内部的线性变换和注意力权重是在固定长度上学会的。超出训练区间后,这些参数面对的是分布外的输入,再完美的位置函数也救不回来。
与其外推,不如把 8K 的内容压回 4K 的镜头里
现在大模型把上下文从 4K 扩到 128K,很少直接硬推。主流思路是插值:测试时不使用真实距离,而是把距离映射回训练区间。比如 8K 长度用 4K 的训练区间表示,相当于把每个旋转角除以 2。但这会引入新的副作用——所有维度转得都变慢,相邻位置间的编码差异变小,短距离的顺序感变钝。
NTK-aware 缩放 的聪明之处在于不统一压缩所有频率:高频维度尽量保持原始转速,把压缩压力主要放在低频维度上。这就像把一整段电影时间轴压缩,远景镜头整体被拉慢,但近景关键动作还保持原来的节拍。之后出现的 YaRN 又在 NTK 基础上加入了注意力温度校正,进一步修复了高频维度混叠的问题。
# 直接外推:用真实位置
angle = m / base ** (2 i / d)
# 线性插值:把距离统一缩放
angle = (m / scale) / base ** (2 i / d)
# NTK-aware 缩放:改 base,间接改变不同频率的缩放量
base2 = base * scale ** (d / (d - 2))
angle = m / base2 ** (2 i / d)
| 方法 | 思路 | 局限 |
|---|---|---|
| 直接外推 | 用模型没见过的真实距离 | 高频旋转混淆,模型直接崩溃 |
| 线性插值 | 把新距离压回训练区间 | 高频信息损失,短距离感知变模糊 |
| NTK-aware | 高频不变,低频压缩 | 只在特定扩展比有效 |
| YaRN | NTK + 注意力温度校正 | 仍有上限,大扩展比时也需训练数据配合 |
外推本质上是一个统计问题
所以答案很清楚:训练 4K 的模型直接在 8K 上跑,崩溃不是运气问题,而是训练分布里根本没有距离差大于 4095 的样本。位置编码只是把这个统计缺口暴露了出来。任何数学变换,无论叫 NTK 还是 YaRN,都是在给旧模型打补丁。补丁可以撑几个扩展倍率,但到了某个阈值,高频混淆、长程衰减失真这些物理规律会一起找上门。
说句我的判断:别再指望后处理把 4K 模型魔改成 128K 还能无损。往前看,真正稳的做法是在预训练阶段就让模型见过多个时间尺度的文本,或者用 RAG 把长输入切短再喂。位置编码要学的是一种距离感知能力,而距离感知需要足够的距离样本练出来。任何回避训练的手段,都只是在借旧模型的能力补课。
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/716.html