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

能算出位置编码,就能读懂长文吗?

算得出不等于读得懂
RoPE 能把位置算到任意长,但训练时有几组低频对一圈都没转满;推理得更远,它们就转到了没见过的角度。PI、NTK-aware、YaRN 都是把新位置折算回见过的范围。另外,窗口长度不等于有效长度。
❓

本课一问:RoPE 的旋转角是算出来的,位置 100 万也算得出。那模型是不是就能读懂 100 万个 token 的长文?

这一课先不碰:长上下文的显存和计算代价(KV cache 在 C3,线性 / 稀疏注意力在 C11)、长文本训练数据怎么配(C7)、训练阶段怎么把长度一步步拉长(C11)。

从已有出发

第 4 课结束时留下一个数:Qwen3.8 的 32 个频率对里,有 10 对的周期超过它的原生上下文 262,144——在这个长度之内,它们一圈都转不完。第 3 课留下的教训是「算得出 ≠ 会用」。这两条放在一起,就是本课的问题。

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

先把代际数字对齐。对话样本里「预训练 32,768、YaRN 扩到 131,072」这组数字属于 Qwen3(2025-04),不属于 Qwen3.8:

模型(代际)RoPE base旋转维数原生上下文官方扩展
Qwen3-8B(2025-04)1,000,000128(全部)32,768YaRN ×4 → 131,072
Qwen3.8-27B(2026-08)10,000,00064(每头 256 维的 25%)262,144YaRN ×4 → 约 1,000,000(4 × 262,144 = 1,048,576)
DeepSeek-V4.1-Flash(2026-09)10,00064(每头 512 维中)65,536YaRN ×16 → 1,048,576

数字全部取自官方 config 与 model card(anchor-model.json、frontier-models.json)。讲 YaRN 的原理先用 Qwen3 那组,再看 Qwen3.8 怎么用同一个方法走到约 100 万。

先自己设计:直接外推

最省事的做法:训练多长无所谓,推理时位置照算,角度照转。先预测,再看:

模型
做法

点上图任意一根柱子,看这一对的全部数字。

每一组在训练长度 L 内转了 ri = L ÷ 周期 圈。转满一圈的组,圆上每个角度都见过,推理得再远,角度也还在见过的范围里;没转满一圈的组,只见过圆上的一段弧。直接外推到 4 倍长,这些组要转到训练时从没出现过的角度——上图的红柱。高频组反而无所谓:Qwen3 最快那组在 32,768 之内已经转了 5,000 多圈。也正因为如此,慢的组在短距离上几乎不携带位置,它们是专门为远距离准备的。

这种「越界」有多严重?提出位置插值(PI)的论文专门分析过:对没见过的位置,注意力分数可能大到灾难性的程度,而插值后的分数有一个小得多的上界(论文估计小约 600 倍) 。

我们自己的小模型上也能看到。它每头 32 维(d_model 256 ÷ 8 头)、base 10,000、训练长度 128,16 个频率对里有 10 对在 128 之内转不满一圈(在上面的组件里切到「我们的小模型」可以核对)。拿同一个 checkpoint、不做任何续训,直接读 512 长的序列:

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案直接外推:训练 128,直接读 512
项目实测 · RoPE 直接外推:512 长的序列里每一段的 loss

改进一:位置插值(PI)

2023 年 Chen 等人的做法:推理长度是训练的 s 倍,就把所有位置除以 s,位置 m 按 m/s 去转。最远处正好落回训练见过的范围,越界的组一个都不剩。原论文用不超过 1,000 步的微调,把 Llama 扩到了 32,768 。

代价在上面组件的第 ② 张图里:所有组的相邻角度差都只剩 1/s,本来分辨近处的高频组也被压扁了。回到上面的组件,切到「PI 线性插值」看:越界 0 对,但被压扁的高频对是全部。这也解释了我们自己的零样本结果——PI 那条线连训练长度 128 之内都比不缩放差:相邻 token 的角度差变成了模型没见过的样子,不续训就用不好。

改进二:NTK-aware——改 base,不改位置

同年 6 月,Reddit 上的用户 bloc97 发帖提出:别压位置,把 base 调大。新 base = base × sd/(d−2)。这样最快那组几乎不动,越往低频压得越多,最慢那组正好压 s 倍。帖子标题就强调「不需要任何微调」 。

在组件里切到「NTK-aware」:高频分辨率大多保住了,但中低频还有一部分组仍然越界——压得不够。YaRN 论文指出的正是这一点。

改进三:YaRN——按「转了几圈」分段

YaRN(Peng 等,2023)把两者的优点合起来:按每一组在训练长度内转了几圈来决定怎么处理。核心公式逐项看:

YaRN 的分段插值(NTK-by-parts)+ 注意力温度 · Peng et al. 2023
= (1 − ) · + γi · , γi 由 与 决定; logit ×
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
HF transformers 按维度下标实现同一件事:先由「转 32 圈」和「转 1 圈」反解出两个下标,之间线性过渡。组件里的分段边界按它的取整规则计算。

YaRN 论文报告:比先前的方法少用 10 倍的 token、2.5 倍的训练步数就能完成扩展 。回到组件切到 YaRN:越界 0 对,本来安全的高频对一个没压。Qwen3、Qwen3.8、DeepSeek-V4.1 的官方扩展方案都是它。

不过,YaRN 的 β = 32 是为训练长度几千的 Llama 调的。在组件里切到「我们的小模型」再选 YaRN:训练长度只有 128,连最快那组也只转了 20 圈左右,按 β = 32 的尺子没有一组算「安全」,几乎全部被插值。我们实测里 YaRN 在训练长度之内也有代价,原因就在这里。方法的超参数带着它被调出来时的规模。

🎯

试三件事:① 在上面的组件里,选 Qwen3-8B,依次点四种做法,对照两张图的变化;② 切到 DeepSeek-V4.1-Flash 看「直接外推」:在 65,536 之内每一组都转满了一圈,按「角度见没见过」这把尺子一对都不越界,它却仍然配了 YaRN ×16——读一下组件给的解释;③ 回到 NaiveFailer 的改进一侧,把指针移到图上,比较四条线在位置 128 前后的变化。

另一个旋钮:base 本身

除了推理时折算,训练时就可以把 base 调大,让最慢的组转得更慢。RoFormer 证明过:多频率下,打分的上界随相对距离衰减。base 越大,衰减来得越晚:

把指针移到图上,读出那个距离上三条曲线的值。
数字口径:RoFormer(Su et al. 2021,arXiv 2104.09864)§3.4.3 式 (37) 的上界 (1/(d/2))·Σj=1..d/2|Sj|,Sj = Σk=0..j−1 ei·r·θk;统一取 64 个旋转维(32 对),只改 base,浏览器里逐点现算。它是上界,不是某个头的实际打分。

Qwen3 在长上下文训练阶段(序列长 32,768)就用了这个办法,把 base 从 10,000 调到 1,000,000(称为 ABF) ;Qwen3.8 进一步用到 10,000,000。2024 年有研究专门论证了「base 的大小给可用上下文长度设了一个下限」:base 太小,困惑度看起来正常,长距离检索却做不到 。

两个常见误解

⚠

误解一:「上下文窗口 = 有效长度。」

窗口是架构参数,写在 config.json 里,可以直接核对(Qwen3.8:max_position_embeddings = 262,144)。有效长度是能力,只能测,而且随任务变。Qwen3.8-Flash-Next 技术报告(官方自报)里,8 针 MRCR 这类多处检索任务,全注意力版本在 128K 得 97.14,512K 掉到 30.66,1M 只有 20.71;换上他们的新注意力(QSA),1M 是 26.44 。窗口到了 1M,不等于 1M 处还能找到东西。

看到「支持 1M」,接着问一句:在 1M 上,NIAH / MRCR / RULER 是多少?三者测的东西不同:NIAH(大海捞针)在长文某个深度埋一句事实,看能否取回,是单针检索;MRCR(多轮共指消解,Gemini 1.5 报告提出,Vodrahalli et al. 2024 细述)在很长的多轮对话里放几段相似的请求,要求找回「第 i 个」,是多针、还要分清彼此;RULER(Hsieh et al. 2024)是一组可调长度的合成任务(多键检索、变量追踪、词频聚合、问答),用来报告有效长度。DeepSeek-V4.1-Flash 的 1M 也要这样读:它是 65,536 × YaRN 16 = 1,048,576,是插值扩展出来的,不是原生 RoPE 直接外推到的。

⚠

误解二:「NoPE(不加位置编码)就是没有位置。」

第 1 课的伏笔在这里兑现:带因果掩码的模型,第 i 个位置能看到 i+1 个 token,「能看到多少」本身就随位置变化。有研究证明,不加位置编码的模型在理论上也能表示绝对和相对位置,小规模合成任务上它的长度泛化还更好 。2026 年真有模型这么做:Kimi K3 的 24 个全局注意力层、GLM-5.3-Flash 的 11 个全局注意力层都不用任何位置编码(config 里 mla_use_nope = true),顺序信息交给占大多数的线性注意力层去携带。

另一边是反证:Qwen 在自家模型上试过把全注意力层的 RoPE 去掉,预训练阶段看不出差别,后训练之后「停不下来、无限生成」的比例明显升高,于是保留了 RoPE 。两条路线都做到了百万级上下文:这是 2026 年分歧最大的地方之一,没有唯一正解。

我们自己的小模型上也有一组「不加位置」的对照。按位置拆开,看它和 RoPE 越过训练长度之后各自怎么变:

项目实测 · 不加位置 vs RoPE:训练长度之外

读这张图要带着条件:3.7M 参数、训练长度 128、只训 400 步。不管哪一组退化得少,都不能推出「NoPE 更好」——Qwen 的反证是在后训练之后才暴露的,预训练的 loss 上看不出来。

位置编码的演进,到这里走完一轮

位置编码的演进:每一代都被上一代的某个真数字逼出来
  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. 第四阶段 长上下文扩展:PI → NTK-aware → YaRN 2023 你在这里
    解决了把新位置折算回见过的范围: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 结论同一报告,只有定性描述。

证据三问

问本课的回答
① 它解决什么问题?让训练在短序列上的模型,用到更长的序列:把新位置折算回训练见过的角度范围
② 数学上为什么可能有效?插值后每一组的角度都落回见过的范围,这一点按构造成立 ;「转满 32 圈的组不必动」「插值后要调温度」是理论动机加经验
③ 实验上为什么最后选了它?YaRN 在 Llama 2 上用更少的 token 和步数完成扩展;Qwen3、Qwen3.8、DeepSeek-V4.1 都采用它;但「窗口 ≠ 有效长度」,有效长度只能靠 NIAH / MRCR / RULER 去测

一句话

📌

能算出位置 ≠ 读得懂长文:超出训练范围的是那几组没转满一圈的低频角度,PI、NTK-aware、YaRN 都是把它们折算回见过的范围;而窗口长度不等于有效长度。

🚦

先停在这里:记住「越界的是低频组」「YaRN 按转了几圈分段」「窗口 ≠ 有效长度」三句,就可以进 C3。
再深一层:读 SideRef 里苏剑林的第 10、16 篇,再去实验课把我们自己模型的数据从头看一遍。

下一个缺口

位置已经进了 Q/K,那 Q、K、V 到底是什么? → C3 第 1 课:已经有 Embedding 了,为什么还要变成 Q、K、V 三份?

这一章反复说「转 Q、K」「V 不转」,Q、K、V 却一直只是三个名字。C3 从它们开始;到 C3 第 6 课,RoPE 会回来。

你可能会问