AI-Workshop 文献分享 2026-08-22 22:15

AI-Workshop 文献分享 #20 — MoE:零基础详细讲义(路由、稀疏激活与多 GPU 部署)

ltw 的 MoE 零基础讲义:从 Dense FFN 的容量与计算绑定出发,逐步拆解 MoE 的完整数据流(路由打分 → Top-K 选择 → 专家前向 → 加权合并),解释专家编号与路由权重的区别、条件计算如何实现「大容量、低激活」,并覆盖共享专家与路由专家的分工、负载失衡与路由坍缩的成因及治理、Top-K 之外的执行策略,以及多 GPU 场景下 all-to-all 通信带来的隐性成本。

AI-Workshop 文献分享 MoE 混合专家 稀疏激活 路由 Transformer

AI-Workshop 文献分享 #20 — MoE:零基础详细讲义(路由、稀疏激活与多 GPU 部署)

分享人:ltw | 日期:2026-08-22

主题:MoE(Mixture of Experts,混合专家模型)零基础详解 —— 从 Dense FFN 到稀疏专家,路由机制、负载均衡与多 GPU 部署成本


本讲义独立介绍 MoE(Mixture of Experts,混合专家模型),重点回答四个问题:

  1. MoE 为什么能扩大模型容量?
  2. 路由器怎样为每个 token 选择专家?
  3. 稀疏激活为什么不等于没有代价?
  4. MoE 在训练和多 GPU 部署中有哪些难点?

先记住一句话:

MoE 让模型储备许多套参数,但每个 token 只运行当前需要的少数几套。


1. 从 Dense FFN 到 MoE:为什么要引入专家?

1.1 注意力和 FFN 分别负责什么?

Transformer 层通常先用注意力交换 token 之间的信息,再用前馈网络加工每个 token 的特征:

\[ \operatorname{FFN}(x)=W_2\sigma(W_1x) \]

可以简单理解为:

注意力负责“从其他 token 搬来相关信息”,FFN 负责“在当前位置加工这些信息”。

例如处理“苹果公司发布手机”中的“苹果”时,注意力会把“公司”“发布”“手机”等上下文线索汇集到“苹果”的向量中;FFN 再把这些线索组合成更容易被后续层使用的特征。

“苹果”的原向量
   ↓ 注意力:读取上下文
带有“公司、发布、手机”等线索的向量
   ↓ FFN:组合并转换特征
更符合当前语境的新向量

这里变化的是 token 的向量表示,不是 token 本身。

1.2 FFN 改变特征,不减少 token 数量

假设输入有 4 个 token,隐藏维度是 4096。典型 FFN 会分别处理每个 token:

每个 token:4096 维 → 更大的中间维度 → 4096 维
整个序列:  4 个 token                  → 4 个 token

“先扩展再投影回来”发生在单个 token 的特征维度上,并不是把一句话压缩成更少的 token。

1.3 Dense FFN 的容量与计算绑定在一起

Dense 模型中,所有 token 都使用同一套完整 FFN 参数:

每个 token → 同一个完整 FFN → 新向量

扩大 FFN 可以增加模型容量,但每个 token 都必须运行扩大的网络,计算量也会同步上升。

MoE 要打破的正是这种绑定:

模型总共拥有很多专家
但每个 token 只运行少数专家

2. MoE 的完整数据流:路由、计算、合并

在 Transformer 中,每个专家通常就是一套独立的 FFN:

\[ f_e:\mathbb{R}^{d}\rightarrow\mathbb{R}^{d} \]

不同专家拥有不同参数,因此会把同一个输入加工成不同的候选表示。

一次 MoE 计算可以拆成五步:

当前 token 向量 x
   ↓ 1. 路由器给所有专家打分
专家分数 z
   ↓ 2. 选择 Top-K
被选中的专家集合 T(x)
   ↓ 3. 只运行这些专家
多个候选向量 fₑ(x)
   ↓ 4. 按路由权重加权求和
MoE 输出向量 y
   ↓ 5. 送入后续网络层

2.1 路由输入是上下文化的 token 向量

设隐藏维度为 \(d\),当前 token 进入 MoE 层时的向量为:

\[ x\in\mathbb{R}^{d} \]

这个 \(x\) 通常已经经过注意力,包含当前上下文信息。因此,同一个词出现在不同句子中可能得到不同路由结果;同一句话里的不同 token 也可能选择不同专家。

2.2 路由器给所有专家打分

假设共有 \(E\) 个专家,路由器使用可训练矩阵:

\[ W_r\in\mathbb{R}^{E\times d} \]

计算全部专家的原始分数:

\[ z=W_rx,\qquad z\in\mathbb{R}^{E} \]

其中第 \(e\) 个分数为:

\[ z_e=w_e^\top x \]

因此,\(z\) 是包含 \(E\) 个分数的向量,不是单个分数。\(W_r\) 的每一行都可以理解为一种可学习的匹配规则。

2.3 Top-K 只选择少数专家

路由器从全部分数中选出最高的 \(K\) 个:

\[ \mathcal{T}(x)=\operatorname{TopK}(z,K) \]

如果:

\[ \mathcal{T}(x)=\{2,4\} \]

它只表示专家 2 和专家 4 被选中。数字 2、4 是专家编号,类似员工工号,不能拿来计算专家权重。

路由器:需要给所有专家计算轻量分数
专家 FFN:只运行入选的 K 个

昂贵的专家计算只发生在少数路径上,这就是稀疏激活。

2.4 为入选专家计算合并权重

可以对入选专家的分数做 Softmax:

\[ g_e(x)= \frac{\exp(z_e)} {\sum_{j\in\mathcal{T}(x)}\exp(z_j)}, \qquad e\in\mathcal{T}(x) \]

满足:

\[ \sum_{e\in\mathcal{T}(x)}g_e(x)=1 \]

具体实现也可能先对全部分数做 Softmax,再选 Top-K,或使用其他归一化方式。关键逻辑不变:选择依据来自路由分数,不来自专家编号。

2.5 合并专家输出

被选中的专家分别运行后,按路由权重加权求和:

\[ y=\sum_{e\in\mathcal{T}(x)}g_e(x)f_e(x) \]

这不是拼接向量,而是对同维度向量逐项加权相加。因此:

\[ x\in\mathbb{R}^{d},\qquad y\in\mathbb{R}^{d} \]

MoE 不改变 token 数量,通常也不改变隐藏维度;它改变的是当前 token 实际经过的参数路径。

2.6 Dense FFN 与 MoE 的根本区别

Dense FFN
每个 token → 固定运行同一套完整参数 → 输出

MoE
每个 token → 动态选择少数专家参数 → 加权合并 → 输出

Dense 的计算路径固定;MoE 的计算路径由输入决定。


3. 用一个 Top-2 例子走完整流程

假设某个 MoE 层有 4 个专家,路由器对当前 token 输出:

\[ z=[1.2,\ 3.1,\ 0.4,\ 2.7] \]

第一步:选择专家

Top-2 选择分数最高的专家 2 和专家 4:

\[ \mathcal{T}(x)=\{2,4\} \]
专家 2:原始分数 z₂ = 3.1
专家 4:原始分数 z₄ = 2.7

第二步:计算权重

\[ g_2=\frac{e^{3.1}}{e^{3.1}+e^{2.7}}\approx0.60 \]
\[ g_4=\frac{e^{2.7}}{e^{3.1}+e^{2.7}}\approx0.40 \]

第三步:运行并合并专家

\[ y=0.60f_2(x)+0.40f_4(x) \]

完整过程是:

x
↓
z = [1.2, 3.1, 0.4, 2.7]
↓ Top-2
专家 2、专家 4
↓ 归一化
权重 0.60、0.40
↓ 运行专家并加权求和
y = 0.60f₂(x) + 0.40f₄(x)

专家不等于固定职业

不要机械地把专家理解成“数学专家”“代码专家”或“中文专家”。训练后可能出现专业化,但这种分工通常是隐式且分布式的:

  • 一个专家可能偏向某些语言、语法或上下文特征;
  • 一种能力可能由多个专家共同承担;
  • 同一个专家也可能处理多种在人类看来不同的任务。

“专家”首先是结构名称,不保证具有清晰的人类职业标签。


4. MoE 为什么能做到“大容量、低激活”?

假设共有 \(E\) 个专家,每个专家有 \(P_e\) 个参数,完成一次专家前向计算的成本记为 \(C_e\)。

专家总参数量近似为:

\[ P_{\text{experts}}\approx E P_e \]

如果每个 token 只激活 \(K\) 个专家,专家部分的单 token 计算近似为:

\[ C_{\text{token}}\approx K C_e \]

当 \(K\ll E\) 时,总参数容量主要随 \(E\) 增长,而单 token 的专家计算主要随 \(K\) 增长。这种“根据输入决定运行哪些参数”的方式称为条件计算。

总容量:由全部 E 个专家共同提供
单次计算:只使用其中 K 个专家

如果一个模型有 896 个路由专家,而每个 token 选择 16 个,那么路由专家数量上的激活比例约为:

\[ \frac{16}{896}\approx1.8\% \]

但这不表示整个模型只使用 1.8% 的计算量。一次完整前向还包括注意力、共享专家、路由器、归一化、输出层、数据搬运和通信。

需要区分:

总参数量        模型一共储存多少参数
激活参数量      当前 token 实际使用多少参数
实际运行成本    计算、内存访问和通信共同产生的成本

MoE 主要降低的是激活专家计算,而不是按同样比例消除全部运行成本。


5. 路由专家与共享专家怎样分工?

很多 MoE 同时包含两类专家。

路由专家

只有被 Top-K 选中时才运行
主要提供条件化、差异化的处理能力

共享专家

所有 token 都会经过
主要承接普遍、基础的处理模式

可以类比为:

共享专家 = 所有项目都会使用的公共基础部门
路由专家 = 根据当前任务临时调用的专业团队

若模型包含共享专家,一次 MoE 输出可以教学化地写成:

\[ y=f_{\text{shared}}(x) +\sum_{e\in\mathcal{T}(x)}g_e(x)f_e(x) \]

真实架构可能使用多个共享专家或不同的缩放、合并方式,但基本分工相同。


6. 路由器怎样学习?为什么会负载失衡?

6.1 路由器与专家共同训练

训练时:

  1. 路由器根据 token 向量选择专家;
  2. 入选专家的输出参与模型预测;
  3. 预测误差通过连续的路由权重和相关训练目标影响专家与路由器;
  4. 专家逐渐适应被分配到的输入,路由器也逐渐调整分配方式。

理想情况下会形成:

相似输入被送往相似专家
→ 专家逐渐擅长这些输入
→ 路由器更准确地选择这些专家

但某些专家可能因早期略占优势而持续获得更多 token,最终形成少数热门专家垄断流量的路由坍缩。

6.2 负载失衡会造成什么?

假设 1000 个 token 需要分配给 4 个专家。

理想情况
专家 1:250    专家 2:250
专家 3:250    专家 4:250

失衡情况
专家 1:700    专家 2:180
专家 3:100    专家 4:20

这会造成:

  • 热门专家成为整批计算的瓶颈;
  • 冷门专家样本不足,难以训练充分;
  • 热门专家可能超过设备容量;
  • 其他设备空闲等待,整体吞吐下降。

若批次中有 \(T\) 个 token,每个 token 选择 \(K\) 个专家,共有 \(E\) 个专家,平均专家负载为:

\[ \bar T=\frac{TK}{E} \]

常见治理方法包括:

  • 加入负载均衡辅助损失;
  • 调整路由分数或动态偏置;
  • 为每个专家设置容量上限;
  • 对溢出 token 做丢弃、缓存或重路由;
  • 复制热点专家;
  • 优化批次内 token 的打包与调度。

目标不是消灭专业化,而是在专家分工、训练稳定性和硬件利用率之间取得平衡。


7. Top-K 之外,路由还要解决什么?

7.1 每个 token 选择几个专家?

较小的 K:计算和通信更少,但可用专家组合更少
较大的 K:组合能力更强,但计算和通信更高

Top-1 只运行一个路由专家;Top-2 或更大的 \(K\) 可以融合多个专家输出。不存在脱离模型规模和硬件条件的统一最优值。

7.2 专家满载后怎样处理?

设备通常会给专家设置容量。如果某个专家收到的 token 过多,可以:

  • 丢弃溢出路由;
  • 改派到次优专家;
  • 延后或分批处理;
  • 提高容量,但承担更多内存和延迟。

7.3 训练和推理路由是否完全相同?

训练阶段可能加入噪声、辅助损失或探索机制,避免路由过早固化;推理阶段通常更强调确定性、吞吐和延迟。

所以,MoE 路由并不只是一个孤立的 TopK 操作,而是一整套训练与执行策略。


8. MoE 在多 GPU 上为什么难?

大型 MoE 通常无法把全部专家放在一张 GPU 上,只能把专家分布到多台设备:

GPU 1:一组专家
GPU 2:另一组专家
GPU 3:更多专家
……

一个 token 可能需要跨设备往返:

token 当前所在 GPU
   ↓ dispatch:发送到入选专家所在 GPU
远端专家执行 FFN
   ↓ combine:返回并合并专家输出
原计算流程继续运行

批次中的不同 token 会被发往不同设备,通常形成 all-to-all 通信。实际耗时近似为:

\[ \text{MoE 时间} \approx \text{专家计算} +\text{跨设备通信} +\text{调度与打包} +\text{最慢专家的等待时间} \]

理论 FLOPs 降低,并不保证端到端延迟按相同比例降低。

如果 batch 很小、设备互联较慢或负载严重不均,通信和调度可能抵消稀疏计算带来的收益。


9. MoE 的收益、代价与总结

MoE 得到了什么?

  • 在不同比例增加单 token 专家计算的前提下扩大总参数容量;
  • 让不同 token 使用不同参数路径;
  • 使专家有机会形成一定程度的专业化;
  • 在合适条件下,提高单位计算预算对应的模型容量。

MoE 没有免费解决什么?

  • 全部专家权重仍需存储、加载或分布式承载;
  • 路由器可能发生坍缩和负载失衡;
  • 跨设备 dispatch、combine 和 all-to-all 带来通信成本;
  • 小 batch 或单请求推理不一定获得理想延迟;
  • 训练、部署和故障排查都比 Dense 模型复杂。

最后用一条数据流记住 MoE:

上下文化 token 向量 x
→ 路由器计算专家分数
→ Top-K 选择少数路由专家
→ 入选专家分别加工 x
→ 按路由权重合并输出
→ 得到同维度的新向量 y

MoE 用“更多可选参数、较少激活参数”扩大模型容量;它节省的是单 token 的专家计算,不会自动消除权重存储、通信和调度成本。


10. 自测题

  1. Dense FFN 和 MoE 的计算路径有什么根本区别?
  2. 为什么路由器的输入是上下文化向量?
  3. 专家编号、路由分数和合并权重有什么区别?
  4. Top-K 为什么能实现稀疏激活?
  5. 为什么专家激活比例不能直接视为完整模型的 FLOPs 比例?
  6. 共享专家和路由专家分别承担什么作用?
  7. 路由坍缩为什么会同时影响模型质量和硬件效率?
  8. 为什么 MoE 的理论计算优势不一定能同比转化为推理延迟优势?

11. 参考答案

  1. Dense FFN 为所有 token 固定运行同一套完整参数;MoE 根据每个 token 的向量动态选择少数专家。
  2. 上下文化向量已经包含当前语境,因此路由器可以根据 token 此时的实际含义选择专家。
  3. 专家编号只表示选中了谁;路由分数表示匹配程度;合并权重由入选专家的分数归一化得到。
  4. 路由器只运行分数最高的少数专家,未入选专家不执行昂贵的 FFN 计算。
  5. 完整模型还包括注意力、共享专家、路由器、归一化、输出层以及通信和调度成本。
  6. 共享专家处理普遍基础模式;路由专家提供输入相关的条件化和差异化能力。
  7. 热门专家会成为计算瓶颈,冷门专家又会因为样本不足而训练不充分。
  8. 多 GPU 通信、token 调度、负载等待和内存访问可能抵消部分稀疏计算收益。