什么是混合专家(MoE)?它如何做到参数多但计算不变?
简化版
MoE(Mixture of Experts,混合专家)把 Transformer 里的一个 FFN 换成多个并列的 FFN 专家,再加一个路由器(gating)为每个 token 只挑选 top-k 个专家来计算。关键是稀疏激活:模型总参数很多(N 个专家),但每个 token 只走 k 个(如 8 选 2),所以实际计算量只和 k 个专家有关,而非全部。这样就能「参数量大涨、单 token 计算几乎不变」,用更多参数装下更多知识而不成比例地增加推理成本。代表:Mixtral 8×7B、DeepSeek-MoE、Qwen-MoE。它的主要挑战是负载均衡(别让 token 都挤到少数专家)和显存开销(所有专家都要存)。
详细版
结构:把 FFN 变成”多专家 + 路由”
标准 Transformer 块的 FFN 被替换为:
router 给出每个 token 对 N 个专家的打分 → 选 top-k
输出 = Σ_{i∈topk} g_i · Expert_i(x) # g_i 是路由权重(softmax 归一)
- 专家(Expert):每个就是一个独立的 FFN。
- 路由器(Gating):一个小的线性层,输入 token 表示,输出对各专家的偏好分,选分最高的 k 个。
核心特性:稀疏激活
- 总参数 ∝ N(专家数),但每个 token 只激活 k 个专家。
- 计算量 ∝ k,而非 N。例如 8 专家 top-2:参数约等于 8 个 FFN,计算约等于 2 个 FFN。
- 于是可以「参数规模上去、FLOPs 基本不变」——这是 MoE 的最大卖点。
主要挑战
- 负载不均 / 路由坍缩:若不加约束,路由器倾向于总把 token 发给少数几个「明星专家」,其余专家训不起来。需辅助负载均衡损失、容量上限(capacity)、token 丢弃或 drop-less 策略。
- 显存大:虽计算省,但所有专家参数都要驻留显存,部署成本高。
- 通信开销:专家常分布在多卡上,token 路由带来 all-to-all 通信。
- 训练稳定性:路由是离散选择,训练更难调。
代表模型
- Mixtral 8×7B:8 专家、top-2。
- DeepSeek-MoE:细粒度专家 + 共享专家(shared expert)。
- Switch Transformer:top-1 路由,极简高效。
完整版教学
一、动机:想要更多参数,又不想付更多算力
大模型有个朴素规律:参数越多,能记的知识、能学的模式越多,效果越好。但稠密模型(dense,每个 token 都过全部参数)里,参数翻倍 → 计算也翻倍 → 训练和推理成本线性上涨,很快吃不消。
MoE 的思路是打破「参数量」和「单 token 计算量」的绑定:让模型拥有海量参数,但每个 token 只用其中一小部分。就像一家医院有几十个专科医生(专家),但每个病人只看其中最对口的两三个,而不是让所有医生都会诊。这样医院的「总能力」很大,单个病人的「诊疗成本」却很低。
二、稀疏激活如何实现”参数多、算力省”
把一层的 FFN 换成 N 个专家 FFN + 一个路由器:
- token 表示 x 进路由器,得到对 N 个专家的打分;
- 取 top-k(如 k=2)个专家,softmax 得到权重 g;
- 只让这 k 个专家计算,输出按 g 加权求和。
算一笔账(N=8, k=2, 每个专家是标准 FFN):
- 参数:约 8 个 FFN 的量(全都要存)。
- 计算:每个 token 只跑 2 个 FFN,FLOPs 约等于 2 个 FFN。
- 于是参数是稠密模型的 ~4 倍,计算却基本持平。
这就是「参数与计算解耦」。Mixtral 8×7B 的总参数约 47B,但每 token 激活的参数只有约 13B,推理成本接近一个 13B 稠密模型,效果却远超它。
关键区分:总参数(total) 决定容量和显存;激活参数(active) 决定单 token 计算和速度。MoE 的精髓就是「总参数大、激活参数小」。
三、路由器:MoE 的大脑,也是麻烦的源头
路由器决定「每个 token 交给谁」,通常是一个简单的线性层 + softmax + top-k 选择。它很轻,却是训练成败的关键,因为它引入了两个难题:
难题一:离散选择不可导。 top-k 是硬选择,梯度不好传。实践上用「被选中专家的 softmax 权重」参与计算,让梯度能流经被选专家;未被选专家这一步拿不到梯度。
难题二:负载坍缩(load imbalance)。 训练早期若某几个专家碰巧表现好,路由器就更爱选它们,它们得到更多训练又变更好——正反馈导致少数专家垄断、多数专家饿死。这会浪费容量、损害效果。
四、负载均衡:让专家们”雨露均沾”
解决坍缩是 MoE 工程的核心,常用手段:
- 辅助负载均衡损失(auxiliary loss):额外加一项损失,鼓励「token 在专家间分布均匀」和「路由概率均匀」。它像一个软约束,惩罚「过度集中」。
- 专家容量(capacity factor):给每个专家设一个「本批最多处理多少 token」的上限;超出的 token 被丢弃(drop,直接走残差跳过)或溢出到次优专家。容量太小丢太多、太大浪费,需要调。
- 噪声路由(noisy top-k):给路由打分加噪声,增加探索,避免过早锁死。
- 无丢弃策略(drop-less,如 DeepSeek):通过更精细的路由与分配避免丢 token。
- 共享专家(shared expert,DeepSeek-MoE):设几个「所有 token 都过」的共享专家承载通用知识,其余路由专家学专精知识,缓解冗余与不均。
面试能点出「负载均衡靠辅助损失 + 容量限制」,并说明「为什么会坍缩(正反馈)」,就抓住了要害。
五、代价:省了计算,付出了什么
MoE 不是免费午餐:
- 显存爆炸:所有专家都要加载,Mixtral 8×7B 虽只激活 13B,但要存 47B 的权重,部署门槛高。
- 通信开销:专家常做专家并行分散到多张卡,token 路由需要 all-to-all 通信,网络不好时成为瓶颈。
- 训练更难:离散路由、负载均衡、容量调参都增加了不稳定性。
- 批处理不规整:不同 token 去不同专家,导致计算不规则,需要专门的 kernel/调度优化。
所以 MoE 的适用场景是「参数容量比推理算力更稀缺、且有足够显存与工程能力」——它把「算力瓶颈」换成了「显存与工程复杂度瓶颈」。
六、用 Top-2 路由算“总参数大、激活参数小”
假设一层有 8 个同尺寸专家,每个专家含 100M 参数,路由对每个 token 只激活 2 个专家。该层拥有约 800M 专家参数,但单个 token 的专家计算只经过约 200M 参数;这就是 MoE 扩大模型容量而不同比例增加 FLOPs 的来源。
总专家参数 = 8 * 100M = 800M
每 token 激活参数 = top_k(2) * 100M = 200M
理想激活比例 = 2 / 8 = 25%
| 指标 | 理想状态 | 异常信号 |
|---|---|---|
| 专家负载 | 各专家接近平均 | 少数专家长期过载 |
| token 丢弃率 | 接近 0 | 容量不足或路由集中 |
| all-to-all 时间 | 占比可控 | 跨机通信吞没计算收益 |
理想账目没有包含跨卡 all-to-all、容量溢出和负载倾斜。若 1000 个 token 中有 400 个都路由到同一专家,即便平均负载应是 250(Top-2 共 2000 次分配除以 8),该专家也可能成为尾延迟瓶颈,所以路由质量必须和系统吞吐一起看。
七、常见误区与追问
- 误区:MoE 每个 token 都计算所有专家。 稀疏 MoE 的路由器通常只选择 Top-k 专家,因此总参数量大而单 token 激活参数较少。
- 追问:专家负载不均为什么会拖慢整批? 并行步骤要等待最慢设备,热点专家的计算与通信成为 straggler,其他设备空等。
- 误区:辅助负载均衡损失越强越好。 过强会迫使均匀路由,压制专家专门化;需要在均衡、质量和通信之间调权重。
- 追问:容量因子不足会发生什么? 专家接收槽位溢出,token 可能被丢弃、回退或转发,造成质量下降或额外延迟。
- 追问:MoE 为什么常受网络而非 FLOPs 限制? 专家跨设备放置会触发 all-to-all,token 重排和跨机带宽可能吞没稀疏计算节省。
八、加强记忆
MoE 简要说抓本质:把 FFN 换成”多专家 + 路由器”,每个 token 只走 top-k 个专家(稀疏激活),于是总参数大涨、单 token 计算几乎不变——用更多参数装更多知识而不涨算力。 记住三组对照:total 参数(大,决定容量/显存)vs active 参数(小,决定速度);省的是计算,付的是显存 + 通信 + 训练复杂度;最大工程难题是负载坍缩,靠辅助均衡损失 + 容量上限 + 共享专家解决。医院多科室、病人只看对口医生——这个比喻能帮你随时还原整套逻辑。