🏠 总目录📚 本教程 02d · MoE 混合专家
📑 本页目录(点开跳转)

02d · MoE 混合专家

64 分钟 | ⭐⭐ 教程里被反复引用、却从没讲过的那个东西


🎯 一句话

MoE 把「参数量」和「计算量」拆开了:一个模型可以有 6710 亿参数,但每个 token 只经过其中 370 亿。 代价也很直白——显存要按总参数算,速度才按激活参数算。 这不是免费午餐,是一次很具体的交易。


🚪 为什么要补这一章

翻一下这套教程,你会发现一件有点尴尬的事:

   《全景导论》第 2 章:用「MoE 只替换 FFN」解释了三件事之一
   《全景导论》第 7 章:本地部署的显存表里有一行「200B+ MoE」
   《ML 基础》第 14 章:「Transformer 之后」那张表里有 MoE 一行
   《AI基础设施》第 14 章:整整一节在讲 MoE 的专家并行

   ⚠️ 但全站没有任何一处讲过:MoE 到底是怎么工作的

这是典型的「用了没讲」:一个结论被当成公理反复引用,而它自己从来没被证明过。这一章补上它。

🔗 前置:读之前最好先有第 2 章里「注意力横向、FFN 纵向」那个分工的印象——这一章几乎全部建立在那句话上


🎯 一、它想解决什么

Scaling Law 的结论很朴素:参数越多,效果越好(🔗 第 4 章)。但参数越多,每生成一个 token 的计算量也越大,推理成本跟着线性涨。

于是有了一个很自然的念头:

   人在处理不同的问题时,也不是整个大脑一起上
   → 能不能让模型也这样:参数很多,但每次只用一小部分?

   ⭐ 这就是 MoE:把 FFN 换成【一组】FFN,每个 token 只走其中几个

两个必须分清的数字(面试和选型都会用到):

概念 是什么 决定了什么
总参数量 所有专家加起来的参数 显存占用
激活参数量 一个 token 实际经过的参数 计算量、生成速度
   Mixtral 8×7B:总参数 46.7B,激活约 12.9B
   DeepSeek-V3 :总参数 671B ,激活约 37B

   ⚠️ 注意 Mixtral 那个名字有误导性:
      「8×7B」不等于 56B —— 因为【注意力那部分是所有专家共享的】,
      只有 FFN 被复制了 8 份。所以是 46.7B 不是 56B ⭐

🧩 二、为什么只替换 FFN,不替换注意力

这是第 2 章直接给了结论、没给理由的那一条。三条理由,第三条才是决定性的

理由 1:FFN 是参数大头

FFN 约占一层参数的 2/3。要稀疏化,当然挑最大的那块下手——把注意力稀疏化了,最多也就省下 1/3 的空间来做文章。

理由 2:FFN 本来就是「逐 token 独立」的

回想那句分工:注意力是横向的(token 之间交换信息),FFN 是纵向的(每个 token 单独深加工)。

   FFN 对每个位置做【完全一样、互不相干】的变换
   → 那么把它换成"每个位置走不同的变换",
     在语义上是完全成立的,不破坏任何结构 ⭐

理由 3:注意力根本没法这样稀疏化 ⭐

这条最关键。注意力要算 Q 和 K 的内积——而内积只有在两者处于同一个向量空间时才有意义。

   假设 token A 走"专家1的注意力",token B 走"专家2的注意力"
   → A 的 Query 和 B 的 Key 来自两套不同的投影矩阵
   → 它们的内积【不代表任何东西】,就是两个不相干空间的数字硬乘 💀

   而且注意力的本质是"所有 token 互相看",
   它天然要求【所有 token 都在场、都用同一套坐标系】

🔑 一句话记住FFN 是"每人自己想",所以可以每人想得不一样;注意力是"大家一起讨论",所以必须说同一种语言。

⚠️ 顺带一提:确实有人尝试过稀疏化注意力头(MoA 之类的研究),但没有成为主流,原因就在上面。


🚦 三、路由:谁决定 token 去哪

一个 MoE 层里,单个 token 走过的路 token「猫」 Router 一个线性层 d×E 专家 1 0.02 专家 2 0.05 专家 3 ✅ 0.61 专家 4 0.01 专家 5 0.02 专家 6 ✅ 0.28 专家 7 0.00 专家 8 0.01 加权求和 0.61·E3 + 0.28·E6 输出(形状不变) ⭐ 8 个专家的参数【全都在显存里】,但这个 token 只算了 2 个 虚线 = 没被选中,这一层里它们一次乘法都没做;下一个 token 可能选到完全不同的两个
MoE 层的完整流程。⭐ 注意两点:① 门控权重(0.61 / 0.28)要乘回专家输出上,这不是可有可无的细节,下面会讲为什么;② 下一个 token 走的可能是另外两个专家——路由是逐 token 的,不是逐句的

数学上就三步

$$g = \text{softmax}(W_g\,x), \qquad \mathcal{T} = \text{top-}k(g), \qquad y = \sum_{i \in \mathcal{T}} g_i \cdot E_i(x)$$

⭐ 为什么门控权重必须乘回去

这是个特别值得想明白的点,面试也常拿它筛人。

   top-k 是【离散选择】—— 它不可导,梯度传不过去

   如果你只是把选中的两个专家的输出【直接相加】:
     y = E3(x) + E6(x)
   → router 的参数 W_g 对 loss 的影响路径【完全断了】
   → 它永远拿不到梯度,永远学不会该怎么路由 💀

   乘上去之后:
     y = 0.61·E3(x) + 0.28·E6(x)
   → g_i 这个【标量】是可导的,梯度能沿着它回到 W_g ⭐
   → router 学到的信号是:"我给专家3 打的分高了还是低了"

🔑 一句话门控权重是 router 唯一的一条梯度通路。 去掉它,MoE 就变成了随机分派。

top-k 取多少

方案 k 代表 特点
Switch Transformer 1 Google, 2021 论文的主要贡献之一就是证明 k=1 就够——此前大家以为至少要 2 个才能让 router 学到东西
GShard / Mixtral 2 Mixtral 8×7B 最常见的选择,k=2 的容错性比 k=1 好
细粒度 MoE 6~8(从几十上百个里选) DeepSeek-V3 专家更小更多,选得更多,见第五节
import torch
import torch.nn as nn
import torch.nn.functional as F

class MoEFFN(nn.Module):
    """一个能跑通逻辑的极简 MoE 层(教学用,不含容量限制和并行)。"""
    def __init__(self, dim: int, hidden: int, n_expert: int = 8, top_k: int = 2):
        super().__init__()
        self.top_k = top_k
        self.router = nn.Linear(dim, n_expert, bias=False)          # ⭐ router 就这么小
        self.experts = nn.ModuleList(
            nn.Sequential(nn.Linear(dim, hidden), nn.SiLU(), nn.Linear(hidden, dim))
            for _ in range(n_expert))

    def forward(self, x):                       # x: (tokens, dim)
        logits = self.router(x.float())         # ⭐ router 用 fp32 算,见第四节的坑
        probs = F.softmax(logits, dim=-1)
        topv, topi = probs.topk(self.top_k, dim=-1)
        topv = topv / topv.sum(-1, keepdim=True)                    # 重新归一化
        out = torch.zeros_like(x)
        for e in range(len(self.experts)):
            sel = (topi == e)                                       # 哪些 token 选了这个专家
            if not sel.any():
                continue
            tok, slot = sel.nonzero(as_tuple=True)
            # ⭐ 门控权重乘回去 —— 这是 router 唯一的梯度通路
            out[tok] += topv[tok, slot].unsqueeze(-1).to(x.dtype) * self.experts[e](x[tok])
        return out, probs

layer = MoEFFN(dim=64, hidden=176, n_expert=8, top_k=2)
h = torch.randn(10, 64)                 # 10 个 token
y, p = layer(h)
print(y.shape, p.shape)                 # (10, 64)  (10, 8)
print("每个专家分到的 token 比例:", (p.argmax(-1).bincount(minlength=8) / 10).tolist())

⚠️ 上面这份是教学实现:用 for 循环遍历专家,真实框架会用 grouped GEMM 一次算完(见第六节)。


⚖️ 四、负载均衡:不加会怎样

这是 MoE 里最容易出事、也最容易被跳过的一节。

坍缩是怎么发生的

router 是学出来的,而它有一个正反馈回路

   ① 初始化时,专家 3 恰好比别人稍微好那么一点点
   ② 于是更多 token 被路由到专家 3
   ③ 专家 3 拿到更多梯度,训练得更好
   ④ 于是【更多】token 被路由到专家 3
   ⑤ 回到 ②……

   💀 最终:8 个专家里只有 2~3 个在干活,
      剩下的从初始化之后【几乎没被更新过】

💀 这个失败是静默的

   发生了什么:8 个专家里 6 个从来没被路由到过
   为什么没被发现:loss 曲线【看起来完全正常】,一直在降 ——
                  因为那 2~3 个活跃专家确实在学东西
   代价:你用 8 倍的显存、训练了一个约等于 2 个专家的模型;
        推理时也要把 8 份权重全加载进显存
   该补什么:⭐ 训练时把【每个专家分到的 token 比例】打到监控面板上,
            理想是接近 1/E 的平坦直方图。这一条比看 loss 有用得多

(🔗 《AI基础设施》第 14 章从并行的角度讲了同一件事的另一面:负载不均衡时,90% 的 token 挤到一张卡上,整个集群被它拖垮。

辅助损失(auxiliary loss)

标准解法是在主损失外面加一项,惩罚"不均匀"

$$\mathcal{L}_{\text{aux}} = \alpha \cdot E \cdot \sum_{i=1}^{E} f_i \cdot P_i$$

为什么是这两个相乘,这是设计里最精巧的一处:

   f_i 提供"实际有多不均"的【强度】—— 但它不可导,单用它没有梯度
   P_i 提供【可导的通路】          —— 但它是软的,单用它反映不了真实拥挤程度

   ⭐ 相乘:某个专家实际超载(f_i 大)时,
      惩罚会通过 P_i 这条可导的路,把它的 softmax 分数压下去

数学上,这个和在 fP 都等于 1/E(完全均匀)时取到最小值。

⚠️ α 的取值是个真实的权衡

α 后果
太小(如 0.001) 压不住,还是会慢慢坍缩
太大(如 0.1) 辅助损失开始干扰主任务——模型为了均匀而均匀,路由变得没有语义 💀

容量因子与 token drop

即使有辅助损失,也不能保证每一步都均匀。所以还要一道硬限制:

   每个专家的容量 C = capacity_factor × (本 batch 的 token 数 / 专家数)

   capacity_factor = 1.0  → 完全没有余量,一旦不均就大量丢弃
   capacity_factor = 1.25 → 常见取值,留 25% 余量

   ⚠️ 超出容量的 token 会被【丢弃】(token drop):
      它这一层跳过 FFN,直接走残差通路过去
      → 它不是报错,是【悄悄少算了一层】⭐

⚠️ 一个真实的坑:训练和推理的 capacity factor 常常设得不一样(推理时为了省显存调小),导致同一个输入在训练和推理下走的路径不同。排查"离线评测好、线上效果差"时,这是一个值得看一眼的地方。

Switch Transformer 的三个具体改动

改动 为什么
top-1 路由 计算量直接减半,且论文证明效果不掉。此前的共识是 k≥2 才行
容量因子 + token drop 让每个专家的计算量固定,才能高效地做静态形状的批处理
router 用 fp32 算 bf16 下 softmax + exp 的数值抖动会让路由决策本身翻转——同样的输入,这一步选专家 3、下一步选专家 5。这是低精度训练里少数必须留 fp32 的地方之一 🔗 混合精度

DeepSeek-V3 的另一条路:无辅助损失

辅助损失有个绕不开的问题:它是一个和主任务无关的梯度,多少会干扰模型学正事。

DeepSeek-V3 的做法是把它拿掉,换成一个偏置项:

   给每个专家一个可调的偏置 b_i:
     用于 top-k 筛选的分数  = s_i + b_i     ← b_i 只在这里出现 ⭐
     用于加权求和的权重     = s_i           ← b_i【不进入】这里

   训练中根据实际负载动态调 b_i:
     这个专家过载了 → 把 b_i 调小一点(让它更难被选中)
     这个专家太闲了 → 把 b_i 调大一点

   ⭐ 关键:b_i 是【手动按规则调的,不参与反向传播】
      → 均衡这件事完全不产生梯度,一点都不干扰主任务

💡 这个设计的思路值得单独记一下:把一个「本来要用梯度解决的问题」改成「用一条控制规则解决」,从而彻底避开它对主目标的污染。这类技巧在工程里到处能用。


🛑 读到这里可以停 —— 机制部分讲完了(约 31 分钟),刚好到全章一半。 你已经拿到最核心的三块:为什么只换 FFN(内积必须在同一个空间里)门控权重是 router 唯一的梯度通路不加负载均衡会静默坍缩后半章还有:DeepSeek-MoE 的细粒度 + 共享专家 · MoE 的五个代价(尤其是显存那条)· 它和 EM/高斯混合的亲戚关系。 回来的时候不用重读,直接从下一节接着看就行。


🔬 五、DeepSeek-MoE 的两个创新

2024 年之后的 MoE 基本都跟了这两条。

① 细粒度专家切分

   传统:16 个大专家,每个 token 选 2 个
   细粒度:把每个专家切成 4 份 → 64 个小专家,每个 token 选 8 个

   ⭐ 激活的总参数量【完全不变】(8 个小的 = 2 个大的)
      但可能的组合数爆炸了:
        C(16, 2) = 120 种组合
        C(64, 8) ≈ 44 亿 种组合   💥

为什么这有用:专家越大,它就越被迫成为一个"什么都会一点"的通才;切小之后,每个专家可以专攻一个更窄的模式,而组合的自由度补回了表达能力。

② 共享专家隔离

   留 1~2 个【所有 token 都必过】的共享专家,不参与路由

   要解决的问题:
     语法、常见搭配这类【每个 token 都需要】的通用知识,
     在纯路由 MoE 里【每个专家都得学一遍】 → 参数冗余 💀

   ⭐ 把通用知识集中到共享专家里,
      路由专家就腾出容量去学各自专精的东西

所以现在主流 MoE 层的结构是输出 = 共享专家(x) + Σ 路由选中的专家(x)

⚠️ 另一个 2025-26 的趋势:门控从 softmax 转向 sigmoid。softmax 强制所有专家分数加起来等于 1(专家之间在抢一个固定的蛋糕),sigmoid 让每个专家独立打分。专家数量很多时后者更稳定。知道有这回事就行。


💸 六、代价(这一节别跳过)

MoE 常被说成「白赚参数量」,那是销售话术。真实的账是这样的:

⭐ 代价 1:显存按总参数算

这是最重要的一条,也是本地部署时最容易被坑的一条。

   稀疏的是【计算】,不是【存储】

   下一个 token 会路由到哪个专家?不知道
   → 所以【全部 8 个专家的权重都必须在显存里待命】

   Mixtral 8×7B:
     速度像一个 13B 模型 ⭐
     显存像一个 47B 模型 💀   ← 别被"8×7B"这个名字骗了

🔗 第 7 章本地部署那张显存表里「200B+ MoE → 100GB+」这一行,说的就是这件事。

代价 2:通信

多卡训练时,专家分散在不同的卡上(专家并行 EP)。每一层都要做两次 All-to-All:把 token 送到它该去的卡,算完再收回来。

   ⚠️ All-to-All 不是 AllReduce —— 它的通信量随卡数增长得更凶
   ⚠️ 跨机时(走 IB 而不是 NVLink)这一步能成为整个训练的瓶颈

🔗 《AI基础设施》第 14 章有完整的 EP 配置讨论;第 5 章互联与集群拓扑解释了为什么"跨机"这两个字这么贵。

代价 3:批处理效率下降

   稠密模型:一个 batch 的所有 token 走同一个 FFN
             → 一次大矩阵乘,GPU 吃满 ✅

   MoE:一个 batch 的 token 被打散到 8 个专家
        → 变成 8 次【小】矩阵乘,每次都吃不满 GPU ⚠️
        → 必须用 grouped GEMM 这类专门的算子才能拉回来

🔗 《AI基础设施》第 7 章算子融合讲的正是这类问题。

代价 4 和 5:训练更不稳、微调更难

问题 说明
训练不稳 路由是离散选择,梯度路径断断续续;loss spike 比稠密模型更常见 🔗 训练稳定性
微调容易废 小数据上微调 MoE,很容易让路由退化成"总选同几个专家"。⚠️ 一个常见做法是冻住 router 只微调专家,或者干脆只做 LoRA 🔗 第 5 章微调与 LoRA

💡 什么时候 MoE 不划算

   ❌ 显存紧张的本地部署 —— 你付了大模型的显存,只拿到小模型的速度收益
   ❌ 极低延迟的单请求场景 —— MoE 的吞吐优势需要 batch 起来才体现
   ✅ 高吞吐 + 显存充裕的服务端 —— 这才是 MoE 的主场

🧠 七、它和你学过的一个东西是亲戚

《ML 基础》第 14 章在 MoE 那一行链到了《数学原理》第 13 章 EM 与高斯混合——这条链是对的,但过去链过去发现没有 MoE 正文。现在补上了。

高斯混合模型(GMM) MoE
隐变量 这个样本属于哪个高斯分量 这个 token 该去哪个专家
怎么分配 软分配:所有分量都参与,按后验概率加权 硬分配 + 软加权:只有 top-k 参与
怎么学 EM 算法,交替更新 端到端反向传播,router 和专家一起学 ⭐

🔑 同一个思想的两种实现:「用一个隐变量决定该用哪个子模型」。 区别在于 GMM 用 EM 做全量软分配,MoE 用 top-k 硬选——而硬选正是它省算力的全部原因


🔗 这一章连到哪里

去哪 为什么
02 · Transformer 原理 「注意力横向 / FFN 纵向」那个分工是本章第二节的全部依据。那一章把「MoE 只替换 FFN」当结论用,这一章给出理由
02b · 现代 LLM 架构的四处改动 MoE 里的每个专家现在基本都是 SwiGLU FFN,参数量怎么算在那一章
02c · 为什么都是 Decoder-only 架构选型的另一个维度。定了 decoder-only 之后,MoE 是横在 FFN 这一层上的第二个选择
05 · 微调与 LoRA 微调 MoE 容易让路由退化,LoRA 是常见的规避方式
07 · 本地部署与开源生态 那张显存表里「200B+ MoE → 100GB+」的由来就是本章第六节
《AI基础设施》14 · 并行策略怎么组合 专家并行 EP 的完整工程视角:All-to-All 为什么贵、负载不均衡怎么拖垮整个集群
《AI基础设施》05 · 互联与集群拓扑 「跨机做 All-to-All 是杀手」这句话背后的带宽数字
《AI基础设施》06 · 混合精度 「router 必须用 fp32 算」属于低精度训练里少数必须留 fp32 的地方,那一章有完整清单
《AI基础设施》07 · 算子融合与编译 MoE 把一次大矩阵乘拆成一堆小的,grouped GEMM 要解决的正是这个
《数学原理》13 · EM 与高斯混合 「隐变量决定用哪个子模型」的祖师爷。想搞清 MoE 的统计学出身,去那里
《ML 基础》14 · 通往 Transformer 那张「Transformer 之后」的表里,MoE 一行说的就是本章

✅ 检查点

  1. 「总参数量」和「激活参数量」各决定了什么?Mixtral 8×7B 这两个数字分别是多少,为什么不是 56B?
  2. 为什么 MoE 只替换 FFN 不替换注意力?三条理由里哪条是决定性的?
  3. 路由的三步公式写出来。router 本身有多大?
  4. 为什么门控权重 g_i 必须乘回专家输出上?不乘会怎样?
  5. 专家坍缩是怎么发生的?为什么说这个失败是「静默」的?该怎么监控?
  6. 辅助损失里 f_iP_i 分别是什么?为什么要把它们相乘?α 太大太小分别有什么后果?
  7. 容量因子是什么?token 超出容量会发生什么——是报错吗?
  8. Switch Transformer 为什么要求 router 用 fp32 算?
  9. DeepSeek-V3 的无辅助损失方案,那个偏置项加在哪、不加在哪?为什么这么设计?
  10. 细粒度专家切分「激活参数不变」,那它到底赚在哪?共享专家又解决了什么问题?
  11. MoE 的五个代价里,本地部署时最容易踩的是哪个?
👀 答案
  1. 总参数量决定显存占用,激活参数量决定计算量和生成速度。 Mixtral 8×7B:总参数 46.7B、激活约 12.9B。不是 56B 是因为注意力那部分是所有专家共享的,只有 FFN 被复制成了 8 份。
  2. ① FFN 是参数大头(约 2/3),稀疏化收益最大 ② FFN 本来就是逐 token 独立的,换成"每个 token 走不同变换"语义上完全成立 ③ ⭐决定性的是第三条:注意力要算 Q·K 内积,内积只有在同一个向量空间里才有意义——如果不同 token 走不同的注意力投影,它们的 Q 和 K 就在不相干的坐标系里,内积不代表任何东西。FFN 是「每人自己想」,注意力是「大家一起讨论」。
  3. g = softmax(W_g·x)T = top-k(g)y = Σ_{i∈T} g_i · E_i(x)。router 就是一个 d×E 的小矩阵,小到可以忽略。
  4. 因为 top-k 是离散选择、不可导。如果只把选中专家的输出直接相加,router 的参数对 loss 的影响路径完全断了,永远拿不到梯度,MoE 就退化成随机分派。乘上 g_i 这个可导的标量后,梯度才能回到 W_g门控权重是 router 唯一的一条梯度通路。
  5. 正反馈:某专家初始稍好 → 更多 token 去 → 训得更好 → 更多 token 去 → 坍缩。最终 8 个里只有 2~3 个在干活。静默是因为 loss 曲线看起来完全正常(那几个活跃专家确实在学)。代价是用 8 倍显存训了个约等于 2 个专家的模型。监控方式:⭐把每个专家分到的 token 比例打到面板上,理想是接近 1/E 的平坦直方图
  6. f_i = 实际路由到专家 i 的 token 比例(硬计数,不可导);P_i = router 给专家 i 的平均 softmax 概率可导)。相乘是因为:f_i 提供"有多不均"的强度但没有梯度,P_i 提供可导通路但反映不了真实拥挤程度——相乘后,实际超载的专家会通过 P_i 这条路被压低分数。α 通常 0.01太小压不住会慢慢坍缩;太大会干扰主任务,模型为了均匀而均匀、路由失去语义。
  7. C = capacity_factor × (batch 的 token 数 / 专家数),常见取 1.25(留 25% 余量)。超出容量的 token 不报错,会被悄悄丢弃——这一层跳过 FFN 直接走残差过去,等于少算了一层。⚠️ 训练和推理的 capacity factor 设得不一样时,同一输入走的路径会不同。
  8. 因为 bf16 下 softmax + exp 的数值抖动会让路由决策本身翻转——同样的输入,这一步选专家 3、下一步选专家 5。这是低精度训练里少数必须保留 fp32 的地方之一
  9. 偏置 b_i 只加在用于 top-k 筛选的分数上(s_i + b_i),不进入最终加权求和的权重(仍用 s_i)。训练中按负载手动按规则调(过载调小、太闲调大),不参与反向传播。这样均衡完全不产生梯度,一点都不干扰主任务——把「本要用梯度解决的问题」改成「用一条控制规则解决」。
  10. 赚在组合数C(16,2) = 120 种 vs C(64,8) ≈ 44 亿 种。专家越大越被迫当通才,切小之后每个能专攻更窄的模式,而组合自由度补回了表达能力。共享专家解决的是参数冗余:语法这类每个 token 都要的通用知识,在纯路由 MoE 里每个专家都得学一遍;把它集中到共享专家后,路由专家腾出容量学各自专精的东西。
  11. 显存。稀疏的是计算不是存储——下一个 token 会去哪个专家不知道,所以全部专家的权重都得在显存里待命。Mixtral 8×7B 速度像 13B,显存像 47B。另外四个代价是:All-to-All 通信(尤其跨机)、批处理效率下降(大矩阵乘被拆成一堆小的,要 grouped GEMM)、训练更不稳、微调容易让路由退化。

🛑 可以停在这里

走神救援

MoE 把参数量和计算量拆开:⭐总参数量决定显存,激活参数量决定速度Mixtral 8×7B = 总参 46.7B / 激活 12.9B(不是 56B,因为注意力是所有专家共享的,只有 FFN 复制了 8 份);DeepSeek-V3 = 671B / 37B。为什么只换 FFN:①FFN 是参数大头 2/3 ②FFN 本来就逐 token 独立 ③⭐决定性的一条:注意力算 Q·K 内积,内积只在同一个向量空间里才有意义——不同 token 走不同投影矩阵的话内积毫无意义。FFN 是"每人自己想",注意力是"大家一起讨论"路由三步g = softmax(W_g x)top-ky = Σ g_i·E_i(x),router 只是个 d×E 的小矩阵。⭐门控权重必须乘回去——top-k 是离散不可导的,g_i 是 router 唯一的梯度通路,不乘 router 永远学不会。k 的选择:Switch 证明了 k=1 就够,Mixtral 用 k=2,DeepSeek 是"几十上百个里选 6~8 个"。💀负载均衡必须有:router 有正反馈(某专家稍好→更多 token→训得更好→更多 token),最终 8 个里只剩 2~3 个干活;⭐这个失败是静默的——loss 曲线完全正常,你得把每个专家的 token 占比打到面板上看直方图平不平才发现。辅助损失 L = α·E·Σ f_i·P_if_i 是实际占比(不可导,提供强度),P_i 是平均 softmax 概率(可导,提供梯度通路),相乘才两者兼得;α 通常 0.01,太小压不住、太大干扰主任务。容量因子常取 1.25,⚠️超容量的 token 不报错,是悄悄跳过 FFN 走残差——等于少算一层。⭐Switch 要求 router 用 fp32,因为 bf16 下 softmax 抖动会让路由决策本身翻转DeepSeek-V3 无辅助损失:偏置 b_i 只加在 top-k 筛选的分数上、不进加权权重,按负载手动调、不参与反传 → 均衡完全不产生梯度DeepSeek-MoE 两创新细粒度切分(激活参数不变但组合数从 C(16,2)=120 爆到 C(64,8)≈44 亿)、共享专家(把语法这类通用知识集中,避免每个专家重复学)。⭐代价别忽略显存按总参数算(下一个 token 去哪不知道,所有专家都得在显存待命,Mixtral 速度像 13B、显存像 47B)、All-to-All 通信跨机是杀手、批处理效率下降(大矩阵乘被拆成一堆小的,要 grouped GEMM)、训练更不稳、微调容易让路由退化。MoE 的主场是高吞吐+显存充裕的服务端,不是本地部署。它和 GMM 是亲戚——都是"隐变量决定用哪个子模型",区别是 GMM 用 EM 软分配全部分量,MoE 用 top-k 硬选,而硬选正是它省算力的全部原因

下一节 👉 03-Tokenizer与上下文.md

打卡记录保存在你的浏览器里,首页能看到总进度