把一个又大又贵的 FFN,换成一堆小"专家",每个词只请其中几个出工。参数量很大、单次算力很小--这就是 Mixtral、DeepSeek 能做超大又跑得动的关键。 教学性模拟--所有图示为确定性示意,用以理解原理,非真实模型实现。
一句话:把一个大 FFN 换成 N 个小 FFN(专家),每个 token 只激活其中 k 个。
普通模型里,FFN(前馈网络)是装知识的胖地方,每个 token 都过同一个 FFN。 MoE 把这个 FFN 换成 N 个并行的"专家"(每个就是个小 FFN),再加一个路由器 gate,给每个 token 打分、挑 top-k 个专家去算,把结果按权重加起来。 结果就是:总参数量大(N 份 FFN,装的知识多),单次计算量小(只算 k 份)。"用大模型的脑容量,跑小模型的速度"。
是的。MoE 的稀疏只发生在 FFN 这一段;Self-Attention 部分通常是稠密、所有专家共享的。所以"混合专家"的"专家"特指那些并行的 FFN。每隔几层放一个 MoE 层、其余仍是稠密 FFN,是常见做法。
gate 给每个专家打分,选分最高的 top-k。点 ROUTE 看一个 token 怎么被分配。
"猫"
gate 本质是个小线性层,给每个专家算一个分数;取 top-k(这里 k=2),对这 k 个分数做 softmax 当权重,把选中专家的输出加权求和。没被选中的专家,这次完全不参与计算--这就是"稀疏"。不同 token 走不同专家,所以叫"混合"。
用 Mixtral 8×7B 算笔账:脑容量 47B,单次只动 13B。
| 模型 | 总参数(脑容量) | 单 token 激活 | 单次算力 |
|---|---|---|---|
| 稠密 13B(如 Llama-2 13B) | 13B | 13B | 13B |
| Mixtral 8×7B(8 专家激活 2) | ~47B | ~13B | ~13B |
Mixtral 有 8 个 7B 级的专家 FFN,每个 token 只激活其中 2 个:总参数约 47B,但每次前向只算约 13B。 代价是--47B 全都要驻留显存,哪怕每次只用一小撮。所以 MoE 的"显存/算力比"很差:脑容量按总参数吃显存,干活只按激活参数算。
DeepSeek-MoE 把专家切得更小更多(比如 64 个小专家激活 6 个),并留少量共享专家始终激活、承载通用知识,避免每个路由专家都重复学一遍通用特征。每个 token 能组合更多专家,表达更丰富,显存利用率也更好。
gate 会偷懒,把 token 都往几个"热门"专家送,其他专家学废。切 tab 看两种状态。
不约束时,gate 很快把绝大多数 token 都送到少数热门专家,其余专家收不到活、学不到东西,参数白占显存。
训练时加一个辅助损失,惩罚各专家被选概率的不均匀,逼 gate 把活摊开。DeepSeek-V3 进一步用无辅助损失的偏置项微调冷门专家的被选率,不干扰主损失。
上面是 320 个 token 的专家被选次数(确定性模拟)。左图严重偏斜:E1/E2 接到大多数活,E7/E8 几乎饿死。右图摊开后接近均匀,每个专家都学到东西。
MoE 服务化的并发/显存难题,比稠密模型更棘手。
所以 MoE 服务的调度,要在"高并发填满算力"和"显存别爆"之间找平衡:显存按总参数压得很紧,但又必须凑大 batch 才不吃亏--连续批处理(continuous batching)几乎必备,且并发上限通常按显存动态估算,而非固定线程数。
| 术语 | 一句话 |
|---|---|
MoE | 混合专家,把一个 FFN 换成多专家稀疏激活 |
专家 Expert | 一个并行的小 FFN,是 MoE 里装知识的基本单元 |
路由器 gate | 给每个 token 给各专家打分、选 top-k 的小线性层 |
top-k | 每个 token 只激活分数最高的 k 个专家(如 k=2) |
稀疏激活 | 只算被选中的专家,其余不参与--参数大而计算省 |
辅助损失 | 惩罚专家被选概率不均,防止 gate 坍缩到少数专家 |
专家并行 | 不同专家分布到不同 GPU,需要 all-to-all 通信 |