从0训练LLM · 现代大模型体系 阅读 + 实验 ≈ 50 分钟 页内实验 ×3
C11 更大更省:MoE、线性/稀疏注意力与长上下文 第 4 课

长文本的 KV 还能再压吗?(揭晓锚点另外 48 层)

另外 48 层:Gated DeltaNet
从 C2 起,锚点 Qwen3.8 的 64 层里一直只讲那 16 层全注意力。另外 48 层是 Gated DeltaNet:每个头一块 128 × 128 的固定状态,写之前先擦掉同一个键的旧值,每一步整体衰减一点,不存 KV,也不做 RoPE。3:1 混合让 KV 降到 1/4;代价是容量有限,而且短于 768 个 token 时,这块状态反而比 KV 还大。

本课一问:长文本的 KV 还能再压吗?锚点 Qwen3.8 的另外 48 层是什么?

这一课先不碰:只读一部分 KV 的稀疏注意力(第 5 课);训练时怎么把长度拉长(第 6 课);Gated DeltaNet 分块并行算法的推导(Dig 里只讲结论)。

从已有出发

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

三条已经埋下的线,在这一课汇合:

先用贯穿例句算一笔反直觉的账。「小明把苹果给了小王」只有 5 个 token:16 层全注意力的 KV 只有 5 × 64 KiB = 320 KiB;可那 48 层的固定状态不管输入多短都是 144 MiB,是「这 48 层若也做全注意力」时 KV 的 153.6 倍。短句上,固定状态反而更占地方;过了 768 个 token,它才开始省(下面的账本会画出这个交叉点)。

先自己设计:只加不减的线性注意力

C0 岔路的版本:每读一对「键 k → 值 v」,就把外积 k vᵀ 加进状态;要读时用 q 去乘状态。这一课换一个例子,原因是:要看「写入与遗忘」,需要同一个键被写两次、需要键多到超过状态的维度,贯穿例句的 5 个 token 都做不到。下面用 4 × 4 的状态和教学构造的单位向量:

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案只加不减:S ← S + k vᵀ
只加不减的写法(浏览器现算)

数字口径:浏览器现算。键、值是固定种子生成的单位向量(教学构造),状态只有 4 × 4;真实的 Qwen3.8 每个 GDN 头是 128 × 128,k、q 由 in_proj_qkv + 短卷积 + L2 归一化得到,α、β 每个 token 由输入现算(见正文公式)。误差 = ‖Sᵀk − 这个键最后一次写入的值‖,值是单位向量,所以误差 1 大约等于「完全读不出来」。
🎯

试三件事(在改进一侧):① 点「写完整串」,读 A:只 delta 与衰减 + delta 的误差都是 0.000——写 v4 之前先把 A 方向上的旧值 v1 读出来减掉;② 看读 B:只 delta 是 0.000,衰减 + delta 是 0.360——每步乘 α = 0.8,B 写入后又过了两步,门的代价是忘掉旧的;把 α 拖到 1.00,衰减 + delta 就和只 delta 一样;③ 切到「② 连写 12 对」:12 对塞进 4 × 4 的状态,谁都读不全,但只看最近写的 3 对,衰减 + delta 的误差最小(0.274),加法最大(1.280)。装不下的时候,先擦再写、再让旧的慢慢淡出,最近的才读得清。

改进:delta rule 加上衰减门

第一步,delta rule(Schlag 等人 2021,把线性注意力和上世纪 90 年代的「快速权重」联系起来):写之前先用 k 从状态里读出旧值 Sᵀk,只写差额 β(v − Sᵀk)。β = 1 时就是精确改写。摘要里把它叫作「让网络更容易修正当前的键到值的映射」 。

第二步,衰减门:每一步先把整个状态乘一个 α ∈ (0, 1),让旧内容整体淡出——这是 Mamba2 那一族的门。两者互补:Yang、Kautz、Hatamizadeh 2024 的摘要原话大意是「门控让记忆能被快速清空,delta rule 让更新有的放矢」,合起来就是 Gated DeltaNet 。它不是 Qwen 发明的;Qwen 的贡献是在 Qwen3-Next(2025-09)里第一次把它和全注意力按 3:1 做成前沿规模的量产架构,Qwen3.5 推广到全系,Qwen3.8 沿用(R2 核对)。

揭晓:锚点的 48 层 Gated DeltaNet

逐项对着 Qwen3.8 的 config 与 HF transformers 的源码(models/qwen3_5/modeling_qwen3_5.py,Qwen3_5GatedDeltaNet)看:

Gated DeltaNet 的一步(Qwen3.8 的 48 层;符号对照 HF 源码)
= (I − )St−1 + ; ot = ; y = Wout[]
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
源码核实(HF transformers commit 7cd73d9,2026-09-22):Qwen3_5DecoderLayer.forward 只把 position_embeddings 传给 full_attention 分支,linear_attention 分支不接收——GDN 层不做 RoPE。顺序信息来自两处:逐 token 的递推本身,和核长 4 的因果短卷积。

一个头、一步更新的形状(真实维度;可切回 4 × 4 的小规模):

一个 GDN 头的一步:先衰减 → 读出旧值 → 求差额 → 外积写入 → 读出
St = α St−1 + β k (v − (α St−1)ᵀk)ᵀ, ot = Stᵀ qt
输入输出中间结果
边长按对数比例缩放,块边上的数字是真实值;同一维度符号的边在全图等长。
维度含义 真实规模 小规模
dk linear_key_head_dim 128 4
dv linear_value_head_dim 128 4
锚点每层 48 个这样的头并行,48 层一共 2,304 个;状态始终是 d_k × d_v,不随读过的 token 数增长——这正是它没有 T × T 分数表(C9 第 5 课的 s² 项)的原因。

这 48 层每层的参数是 115,876,064,比一层全注意力(104,858,112)还多(C4 岔路的账)。线性注意力省的是 KV 和长序列的计算,不是参数。

3:1 混合:KV 降到 1/4

混合栈账本 · 各家的层排布、KV 与固定状态(官方 config 现算)
混合栈账本:谁的记忆随长度涨、谁的不涨(官方 config 现算)
全局注意力层(存 KV,随长度涨)线性注意力层(固定状态,不随长度涨)

🎯

试三件事:① 锚点:T 拖到 262,144(原生上下文),实际 16 GiB 多一点(KV + 144 MiB 状态),全换成全注意力要 64 GiB——3:1 让 KV 降到 1/4;② 把 T 拖回 5 和 256:实际反而比「全是全注意力」大,绿点就是交叉点 T* ≈ 768;③ 切到 Kimi K3 与 GLM-5.3-Flash:同样约 3:1,但全局层用的是 MLA(每 token 存一个压缩潜向量),KV 本来就小,交叉点被推到几千个 token。

为什么不干脆全换成线性层? 三条证据,分属三层:

⚠

常见误解一:「线性注意力就是更粗糙的 softmax 注意力。」 它是另一种记忆:固定容量、按 delta 改写、按门遗忘。全注意力能精确回看任意一个 token;线性层只能读回「现在状态里还剩什么」。

常见误解二:「GDN 层也做 RoPE。」 源码核实:只有全注意力层接收位置编码。GDN 的顺序来自递推与短卷积——这也是 Kimi K3、GLM-5.3-Flash 敢让全局层干脆不用位置编码(NoPE)的理由之一(C2 第 5 课)。

常见误解三:「线性注意力在任何长度都更省。」 锚点短于 768 个 token 时,144 MiB 的固定状态比「这 48 层若也做全注意力」时的 KV 还大;MiniMax 博客也说,理论交叉点在「几千个 token」。

常见误解四:「线性注意力省参数。」 锚点一层 GDN 115,876,064 个参数,比一层全注意力还多。

再往前一步:KDA 与一个下界

Kimi Linear 的 KDA 把 α 从「每个头一个标量」细化成「每个通道一个」。旧版课程拆过它的公式,逐项保留:

KDA 的状态更新(Kimi K3 报告式 (1);旧版 M7 的五项解释)
= ( I − ) +
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
出处:KDA、NoPE 与 KDA:MLA 混合栈都出自 Kimi Linear(arXiv 2510.26692,2025-10,48B / 3B);K3 的贡献是把它推到 2.8T 并解决工程问题。「对我是新的」不等于「对领域是新的」。
🔍 一个下界为什么能提速:g_min = −5

KDA 的分块算法要把 key 按块内累积衰减的倒数重新缩放。Kimi Linear 与 Gated DeltaNet 一样用 g = −eA·softplus(z),取值 (−∞, 0) 没有下界,倒数可能超出浮点范围,于是每个对角块只能单独逐位置计算——这条慢路径成了整个算子的瓶颈。K3 改成 g = gmin·sigmoid(eAz),gmin = −5:每一步的保留因子 α > e−5 ≈ 6.7 × 10⁻³,16 个 token 一块的累积对数衰减落在 (−80, 0),倒数小于 e80 ≈ 5.54 × 10³⁴,在 BF16 的上限 3.39 × 1038 之内。所有块都能直接走 Tensor Core 的矩阵乘,慢路径删掉 。这是「算法与系统协同设计」的例子:改一个门的值域,换来整个算子的吞吐。一个月之内 GLM-5.3-Flash 的 config 里就出现了 kda_gate_lower_bound = -5(R3 记录的外溢)。

🔍 固定状态是递推的,训练时怎么并行?

逐 token 递推只在推理时用(源码的 torch_recurrent_gated_delta_rule)。训练时把序列切成 64 个 token 一块(torch_chunk_gated_delta_rule 的默认 chunk_size):块内用矩阵乘一次算完(需要解一个 64 × 64 的下三角方程,UT 变换),块与块之间才递推传状态。所以训练的显存里只有 64 × 64 的块内矩阵,没有 T × T 的分数表。推导见 Songlin Yang《DeltaNet Explained (Part II)》。这也回答了 C9 第 5 课的疑问:线性注意力层的激活没有 s² 项。

本章演进图:每一代都被上一代的某个真数字逼出来(本课所在的一代已高亮;其余两条线可展开)
① 更多参数,不要更多算力(MoE)
  1. 朴素 dense 直接放大 算力 ∝ 参数
    解决了结构最简单:所有参数对每个 token 都生效。
    卡在锚点 Qwen3.8-27B 每 token 前向约 51.2 GFLOPs;同家族 2.4T 规模若是 dense,约 4.84 TFLOPs(94 倍)。
  2. 第一代 稀疏门控 MoE Shazeer 2017 → GShard → Switch
    解决了每个 token 只算 top-k 个专家:Qwen3.8-2.4T-A95B 每 token 约 186.5 GFLOPs,是同参数 dense 的 26 分之一。
    卡在路由会自我强化地偏心:8 个专家全挤到 1 个时,Switch 负载损失从 0.01 升到 0.08;所有专家的权重仍要常驻显存。
  3. 改进 ① 辅助损失 α·N·Σf·P Switch 2021(α = 10⁻²)
    解决了把「均衡」写进 loss,路由器被梯度推向均匀。
    卡在α 难调:太小拉不平,太大干扰主 loss(Switch 在 10⁻¹ 到 10⁻⁵ 之间扫;Wang 2024 的出发点)。
  4. 改进 ② 无辅助损失偏置 Wang 2024 → DeepSeek-V3
    解决了偏置只改「选谁」,不进门控、不产生干扰梯度;DeepSeek-V3 前 14.3T token 用 γ = 0.001,最后 500B 设为 0。
    卡在固定步长在近千个专家时太慢或来回震荡(Kimi K3 报告)→ Quantile Balancing;而且统计范围(整批 vs 单条序列)比「有没有 loss」更要紧。
  5. 改进 ③ 细粒度专家 + 共享专家 DeepSeekMoE 2024
    解决了同参数同计算,16 选 2 的 120 种组合变成 64 选 8 的 4,426,165,368 种;共享专家装公共知识。
    卡在显存账不减:Qwen3.8-2.4T 路由专家占主干参数 97.98%,BF16 权重 4.89 TB。
  6. 2026 极高稀疏度与分歧 Qwen3.8 · K3 · V4.1
    解决了Qwen3.8-2.4T 512 选 10 + 1 共享;K3 896 选 16 + LatentMoE + Quantile Balancing;V4.1 图文两套偏置。
    卡在共享专家 0、1、2 个都有人用(Qwen3 一个不设),稀疏度从 32 到 64 都有(GLM-5.3 与 V3 为 32、GLM-5.3-Flash 36、K2 48、Qwen3.8 51、K3 56、V4.1-Flash 64)——都是实验选择。
② 长文本:KV 与计算不再随长度等比例涨
  1. 解决了每个 token 都能精确回看任意一个前文 token。
    卡在KV ∝ 长度:锚点若 64 层全是全注意力,262,144 token 时 64 GiB。
  2. 第一步 线性注意力 Katharopoulos 2020 你在这里
    解决了去掉 softmax,求和提前累加成一个固定大小的状态,与长度无关。
    卡在只加不减:同一个键写两次,读回的是两个值之和;状态最多装 d 对互不干扰的键值(C0 岔路)。
  3. 第二步 Gated DeltaNet · 3:1 混合 Schlag 2021 → Yang 2024 → Qwen3-Next、3.8 你在这里
    解决了写前先擦(delta)、每步衰减(门):锚点 48 层状态共 144 MiB(FP32)、与长度无关;KV 降到四分之一(262,144 时 16 GiB 对 64 GiB)。
    卡在剩下四分之一的全注意力层仍按长度涨;容量有限,3:1 是实验选出来的。
  4. 工程化 KDA + 衰减下界 Kimi Linear → K3 → GLM-5.3-Flash 等 你在这里
    解决了每通道一个衰减;g_min = −5 让 16 token 块内累积不低于 −80,e⁸⁰ ≈ 5.5 × 10³⁴ 在 BF16 范围内(上限约 3.4 × 10³⁸),慢路径删除。
    卡在MiniMax M1 用线性混合、M2 又退回全注意力:大规模下多跳推理缺陷、训练受访存限制、低精度与缓存难题(官方博客)。
  5. 另一条路 稀疏注意力 DSA DeepSeek-V3.2 2025
    解决了lightning indexer 每个 query 只挑 top-2048 条做核心注意力。
    卡在省计算不省内存:KV 一条不少,每 token 48,068 B;indexer 本身仍要扫全部前文。
  6. 2026 压序列 + 压层 + 压精度 DeepSeek-V4 CSA + HCA → V4.1 CSA2 + CED
    解决了V3.2 每 token 48,068 B → V4-Flash 3,514 B → V4.1-Flash 890 B(1M 时 0.87 GiB)。
    卡在是近似:V4.1 自陈 Bounded Replay「数学上不等价」、选择误差可能在未测过的边界情况退化。
③ 训练 4K,使用 128K
  1. 解决了推理时把新位置折算回训练见过的角度范围。
    卡在零样本外推有代价,方法的超参数带着它被调出来时的规模(C2 第 5 课与项目实测)。
  2. 朴素 从头就用长序列训 最直接的想法
    解决了训练与使用同一个长度,不需要任何折算。
    卡在注意力项随长度涨:Qwen3-32B(64 层全注意力)在 131,072 时注意力项是 6N 的 215%;早期长序列还带来梯度方差极端值(Li 2021)。
  3. 现代做法 先短后长 + ABF BERT → Llama 3 → DeepSeek-V3 · Qwen3
    解决了DeepSeek-V3 的 14.8T token 全在 4K,之后两段各 1,000 步扩到 32K、128K,只占全部训练 token 的 0.84%;Llama 3 405B 六段、约 800B token。
    卡在长序列阶段的数据要专门配(长度上采样、领域均衡、合成跨全文任务)。
  4. 2026 分歧 课程在缩短 Kimi K3 · DeepSeek-V4.1
    解决了K3:8K → 64K → 256K → 1M(NoPE 也照走课程);V4.1 注意力从头就是压缩稀疏的,直接从 64K 起训。
    卡在各家配方大多只公开阶段、不公开每段 token 数,无法横向比较成本。
  5. 岔路 多 token 预测 MTP Stern 2018 → Gloeckle 2024 → DeepSeek-V3
    解决了每个位置多学一个更远的目标;推理时当草稿,接受率 α 时每步期望产出 1 + α 个 token。
    卡在DeepSeek-V3 第 2 个 token 接受率 85%–90%,实测 1.8 倍 TPS;V4.1 预训练干脆去掉 MTP,没有公开消融。
数字口径:锚点、Qwen3.8-2.4T、Qwen3-32B、DeepSeek 各代的数字由 anchor-model.json / frontier-models.json(DeepSeek-V3.2、V4-Flash 取本章补充 config)在构建时现算;KV 字节按 FlashMLA 官方 README 的缓存格式计(indexer key 为推算,见第 5 课);FLOPs 只数矩阵乘,乘加记 2。Switch α、DeepSeek-V3 的 γ 与长上下文两段、K3 的 g_min 与长度课程出自各自原文(本地 PDF 已核);MiniMax 的理由出自其官方博客(2025-10-29)。

证据三问

问本课的回答
① 它解决什么问题?让大多数层的「记忆」不随长度增长:锚点 3:1 混合,KV 降到全注意力的 1/4,长序列的注意力计算也只剩 1/4 的层
② 数学上为什么可能有效?状态大小 dk × dv 与长度无关 ;delta rule 精确改写、门控遗忘让有限容量用在最近、最相关的内容上 ;全局层不能全省有下界证明
③ 实验上为什么最后选了它?Kimi Linear 公平比较超过全注意力;Qwen 的 25B-A3B 消融;2026 年 Qwen3.8、K3、GLM-5.3-Flash 都用约 3:1(Ling-3.0 是 5:1)。反例:MiniMax M2 退回全注意力

一句话

📌

Gated DeltaNet 用固定大小的状态记前文:写之前先擦掉同一个键的旧值,每步整体衰减一点;锚点每 4 层留 1 层全注意力,KV 降到 1/4,代价是容量有限、精确回看靠那 1/4。

🚦

先停在这里:记住三个数:每头 128 × 128、48 层共 144 MiB、交叉点 768 token。
再深一层:读 Songlin Yang 的 Part I,再在实验台的「连写 12 对」里把 β、α 各拖一遍,体会「擦多少、忘多快」的权衡。

下一个缺口

线性层砍掉了 3/4 的 KV,剩下 1/4 的全注意力层仍按长度增长——能不能每次只读一部分? → 第 5 课:稀疏注意力省了什么,没省什么?

C3 第 10 课 KV 阶梯末尾那张 890 字节的虚线卡,也在下一课兑现。

你可能会问