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

更多参数,但不要更多算力?

参数和计算分家:MoE
dense 模型想多一倍参数,每个 token 就要多一倍计算。MoE 把 FFN 拆成很多个专家,由一个小路由器给每个 token 挑几个:Qwen3.8-2.4T-A95B 有 2.4 万亿参数,每个 token 的计算却只相当于 950 亿参数的 dense 模型。代价写在另一本账上:所有专家都得常驻显存。

本课一问:更多参数,但不要更多算力?

这一课先不碰:专家为什么会抢活、怎么均衡(第 2 课);专家该大还是小、要不要共享专家(第 3 课);几百个专家怎么分到很多张卡上、token 怎么送过去(已在 C10 岔路 2 讲过)。

从已有出发

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

贯穿例句「小明把苹果给了小王」的 5 个 token 一路走到 FFN。C4 已经算过:锚点 Qwen3.8-27B 是 dense 模型,每个 token 都经过全部参数;FFN 是其中的大头(C4 岔路:全模型参数的 61.6%,文本主干的 63.6%)。把「参与矩阵乘的参数」数一遍——总参数去掉输入 embedding 查表、视觉塔和 MTP——是 25,624,600,064 个。每个参数每个 token 做一次乘加(2 FLOPs),所以:

这一章先回答 C6 留下的一个疑问:DeepSeek-V3 为什么按 37B 算、不按 671B 算?

先自己设计:直接把 dense 放大

想要更多「知识容量」,最直接的办法是把模型做大。同家族的 Qwen3.8 最大号有 2.4 万亿参数;假如它也是 dense 的,账是这样:

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案dense 直接放大:参数翻几倍,每 token 的计算就翻几倍

dense 模型里,参数量 N 与每 token 的计算是绑在一起的:前向 ≈ 2N、训练 ≈ 6N(C6)。容量翻倍,算力翻倍,没有商量的余地。

改进:FFN 本来就能拆成许多块之和

先看一个恒等式。FFN 是 y = f(x·WA)·WB,中间维 D。把 WA 按列、WB 按行切成 n 块,激活 f 是逐元素的,所以

y = Σi=1..n f(x·WA(i))·WB(i)

一个 FFN 恰好等于 n 个小 FFN 的输出之和 。MoE 问的是:能不能只挑其中 k 块来算,近似这个和?挑哪几块,交给一个便宜的打分器——路由器——对每个 token 现算。

这个想法很老。1991 年 Jacobs、Jordan、Nowlan、Hinton 提出「自适应的局部专家混合」;把它做成深网里的稀疏门控,是 Shazeer 等人 2017 年:在 LSTM 层之间插入最多 1370 亿参数的 MoE 层,摘要里说模型容量提升超过 1000 倍、计算效率只有很小的损失 。GShard(2020)把它放进 Transformer,每个 token 选 2 个专家,训出 6000 亿参数的翻译模型;Switch Transformer(2021)干脆只选 1 个:

MoE 层:替换掉 C4 的那个 FFN(Switch 式 (2);DeepSeek-V3 式 (12)–(15))
= · + , s =
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
旧版课程 M6 的三项解释(路由器是学出来的、TopK 把其余置 −∞、计算 ∝ k 容量 ∝ E)全部保留在上面;新增共享专家与「门控值让路由器可导」两项。

Switch 用同样的 FLOPs,在 T5 的底座上把预训练加速到最高 7 倍 。

极小真数字:一个 token 怎么被路由

先用小规模把选择链走一遍。每一步都在浏览器里现算;「分数」「索引」「掩码」三种东西画法不同——分数是连续值(渐变),索引是离散的编号(编号槽),掩码是 0 / 1(斜线 = 不计算):

路由选择链 · 贯穿例句 5 个 token × 8 个专家(教学构造的小向量,算法是真的)
路由选择链 · 一个 token 走一遍(浏览器现算)
🎯

试三件事:① 点「给了」,看 ② 行 8 个分数里哪两个最大,④ 行就是它们的编号,⑤ 行只有这两格是 1;② 把 k 从 2 拖到 1:门控 g 变成一个 1.000,只剩一个专家参与;③ 拖动路由温度 τ:门控 g 在「几乎全给一个」和「接近平分」之间变,但 ④ 行的编号、下面整句的负载一格都不变——top-k 只看排序,温度不改变排序。旧版课程说「温度调低,token 就挤向少数专家」,这是错的:挤不挤,取决于分数本身,第 2 课看它怎么在训练里越挤越偏。

同一条选择链放到真实维度上(Qwen3.8-2.4T-A95B 的 config;可切回小规模核对):

MoE 路由:连续分数 → 离散索引 → 掩码 → 选中的门控值(Qwen3.8-2.4T 真实维度)
G = normalize(gather(softmax(X·Wr), TopK))
输入参数(可学习)输出中间结果 渐变 = 分数(连续值)编号槽 = 索引斜线 = 掩码(留白 = 不读)
边长按对数比例缩放,块边上的数字是真实值;同一维度符号的边在全图等长。
维度含义 真实规模 小规模
T 序列长度(贯穿例句在 Qwen3.8 tokenizer 下 5 个 token) 5 5
d hidden_size 8192 4
E 路由专家数(num_experts) 512 8
k 每 token 选几个(num_experts_per_tok) 10 2
维度取自 frontier-models.json(Qwen3.8-2.4T-A95B 官方 config)。选择链闭合:连续的 S、P → 离散的 I → 0/1 的 M → 回到连续的 G。I 不可导;梯度经由 G 回到 P、S、W_r。

两本账:参数跟着 E 涨,计算只跟着 k 涨

MoE 账本 · 官方 config 逐项现算,并与官方口径核对
MoE 的两本账:参数跟着专家总数涨,每个 token 的计算只跟着 k 涨(官方 config 现算)
① 参数账:这些参数里,一个 token 实际用到多少?
② 算力账:每个 token 前向一次要做多少乘加?
③ 显存账:权重要全部放进显存吗?
④ 贯穿例句:「」经过这一层

🎯

试三件事:① 看 Qwen3.8-2.4T 那一行「✓」:按 config 逐项现算的 2,446,182,725,504 与 HF 的 safetensors 计数逐位相同;激活参数 95.29B(含输入 embedding)对上官方的「A95B」;② 切到 DeepSeek-V3:现算的总参与激活参数对上官方的 671B / 37B(误差在 0.5% 以内)——C6 第 3 课「按 37B 算」的理由就在算力那一栏;③ 回到 Qwen3.8-2.4T 看显存账:一个 token 只用到约 191 GB 的参数,可权重一共 4.89 TB,每张 80 GB 的卡只放权重也要 62 张。

所以 MoE 的收益和代价写在两本不同的账上:

DeepSeek 从 dense 到 MoE 的真实账:DeepSeek-V2(236B 总参 / 21B 激活)相对自家 dense 的 67B,训练成本 −42.5%,最大生成吞吐 5.76 倍 。

⚠

常见误解一:「MoE 省显存。」 省的是每个 token 的计算,不是参数。Qwen3.8-2.4T 的 11 个专家(含共享)只占这个 token 的计算,可 512 个路由专家的权重一个都不能少放。按激活参数估显存,上机必爆。

常见误解二:「2.4T 参数,每个 token 都用到了。」 每个 token 每层只经过 10 个路由专家 + 1 个共享专家;一句 5 个 token 的话,在一层里最多碰到 50 个路由专家,至少 462 个完全没被计算(账本第 ④ 栏)。

常见误解三:「top-k 是离散选择、不可导,所以路由器学不到东西。」 选谁(索引 I)确实不可导;但被选中的专家输出乘了门控值 g,g 来自路由分数,主 loss 的梯度经 g 回到路由器(Switch §2.1)。代价是:没被选中的专家,这一步拿不到任何梯度——第 2 课的问题就从这里长出来。

🔍 2026 年的一个极端例子:DeepSeek-V4.1-Flash 的两本账

官方口径:骨干 552B 参数(另有 196B 的 Engram 查表),prefill 每 token 激活 8B、decode 激活 16B(它的上半部分层在 prefill 时可以跳过,第 5 课的 CED)。按「每 token FLOPs ≈ 2 × 激活参数」,decode 约 32 GFLOPs;若 552B 全部参与,约 1.1 TFLOPs——差 34 倍。可 552B 的权重,即便专家用 FP4 存,HF 上的文件也有几百 GB 。这两本账的比值,就是 MoE 的全部买卖。

本章演进图:每一代都被上一代的某个真数字逼出来(本课所在的一代已高亮;其余两条线可展开)
① 更多参数,不要更多算力(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)。

证据三问

问本课的回答
① 它解决什么问题?让参数(容量)与每 token 的计算脱钩:参数跟着专家总数 E 涨,计算只跟着每 token 选的 k 涨
② 数学上为什么可能有效?FFN 恰好等于若干小 FFN 之和,MoE 只挑其中 k 个来近似 ;每 token FLOPs ≈ 2 × 激活参数是记账算术
③ 实验上为什么最后选了它?同 FLOPs 下,Switch 预训练最高快 7 倍;DeepSeek-V2 相对 67B 训练成本 −42.5% ;2026 年的前沿旗舰几乎全是 MoE

一句话

📌

MoE 把 FFN 拆成很多专家、每个 token 只算其中 k 个:容量跟着专家总数涨,每 token 的计算只跟着 k 涨;但所有专家的权重都得常驻显存。

🚦

先停在这里:记住「两本账」:算力按激活参数,显存按总参数。
再深一层:读 SideRef 里 Switch 的 §2.1–2.2,再去 C10 岔路 2 看这几百个专家怎么分到 64 张卡上。

下一个缺口

路由器是和专家一起学出来的——它会不会总把 token 发给同几个专家? → 第 2 课:专家为什么抢活、闲置?

误解三留下的那句话——「没被选中的专家拿不到梯度」——下一课会在一个真的在浏览器里训练的小 MoE 上变成一个数字。

你可能会问