1. Dense 模型与 MoE 模型
Dense 模型
Dense 模型中,每个 token 都会经过同一套完整参数。
在 Transformer 中,一层通常包含:
Attention
→ FFN
其中 FFN 的参数量和计算量通常占较大比例。无论输入哪个 token,Dense 模型都会激活完整的 FFN。
特点:
-
所有参数对每个 token 都参与计算;
-
训练过程相对稳定;
-
实现简单,通信开销较低;
-
参数量增加时,每个 token 的计算量也会同步增加。
MoE 模型
MoE 全称为:
Mixture of Experts
中文为"混合专家模型"。
MoE 的核心目标是:
在显著增加模型总参数量的同时,只让每个 token 激活少量参数,从而控制实际计算量。
MoE 通常不是替换整个 Transformer,而是将普通 FFN 替换成多个专家 FFN:
Attention
→ MoE FFN
多个专家通常具有相同的网络结构,但拥有不同的参数。
例如:
Expert 0:一套 FFN 参数
Expert 1:一套 FFN 参数
...
Expert 7:一套 FFN 参数
2. Router 如何选择专家
每个 token 不会经过全部专家,而是先交给一个 Router,也称为 Gate 网络。
Router 通常是一个较小的线性层:
token 隐藏向量
→ Router
→ 每个专家的分数
假设有 8 个专家,某个 token 的 Router 输出为:
Expert 0:0.05
Expert 1:0.40
Expert 2:0.02
Expert 3:0.25
Expert 4:0.08
Expert 5:0.04
Expert 6:0.12
Expert 7:0.04
如果使用 Top-2 路由,就选择分数最高的两个专家:
Expert 1
Expert 3
这个 token 只进入这两个专家计算,其他六个专家不参与该 token 的前向传播。
不同 token 可以选择不同的专家:
token A → Expert 1、Expert 3
token B → Expert 0、Expert 6
token C → Expert 1、Expert 5
因此,MoE 是一种稀疏激活模型。
3. MoE 的参数量与计算量
假设一个 Dense 7B 模型中:
Attention 等非 FFN 参数:约 1.4B
FFN 参数:约 5.6B
总参数:约 7B
总参数量
总参数量
= 共享参数 + 8 个专家参数
= 1.4B + 8 × 5.6B
= 46.2B
现在将 FFN 替换为 8 个专家,每个专家都有约 5.6B 参数,而 Attention 等参数仍然共享。
如果每个 token 只选择两个专家:
激活参数量
= 共享参数 + 2 个专家参数
= 1.4B + 2 × 5.6B
= 12.6B
可以近似理解为:
总参数量约 46B
每个 token 实际激活约 13B 参数
因此 MoE 可以做到:
模型总容量很大
但单个 token 的计算量明显低于同规模 Dense 模型
需要注意,激活参数量不完全等于实际 FLOPs,但可以用于直观比较计算规模。
4. MoE 节省计算,但不等于节省全部显存
虽然每个 token 只经过少量专家,但模型仍然需要保存所有专家的参数。
原因是:
当前 token 可能选择 Expert 1、Expert 3
下一个 token 可能选择 Expert 0、Expert 7
因此推理或训练时,所有专家参数都必须存在于设备显存、CPU 内存或多卡系统中。
可以概括为:
总参数量:约 46.2B
每个 token 激活参数量:约 12.6B
参数存储仍需容纳全部 46.2B
MoE 主要减少的是:
-
每个 token 的 FFN 计算量;
-
每一步实际激活的参数数量。
它不会自动减少:
-
全部模型权重的存储空间;
-
优化器状态占用;
-
多卡训练时的通信开销。
而且在多 GPU 场景中,不同专家可能分布在不同 GPU 上,token 需要在设备之间发送,这种方式称为 Expert Parallelism,可能带来较高通信成本。
因此:
MoE 的理论计算量较低,但实际训练和推理速度不一定按参数比例直接提升。
5. MoE的问题:专家坍缩与负载不均衡
专家坍缩
专家坍缩是指 Router 长期只选择少数几个专家。
例如有 8 个专家,但大多数 token 都被路由到:
Expert 1
Expert 3
其他专家很少收到 token。
这会导致:
-
热门专家负载过高;
-
冷门专家训练不足;
-
多个专家没有形成差异化能力;
-
设备负载不均衡;
-
部分 token 因容量不足被丢弃或重新路由;
-
模型训练不稳定。
理想情况下,不是要求每个专家使用次数绝对相同,而是避免流量过度集中。
6. 常见的负载均衡方法
辅助负载均衡损失
训练时加入额外的辅助损失,鼓励 Router 将 token 较均匀地分配给不同专家。
总损失可以写成:
total_loss
= language_model_loss
+ balance_coefficient × load_balance_loss
负载均衡损失通常同时考虑:
-
每个专家被实际选择的 token 比例;
-
Router 分配给每个专家的平均概率。
它不是简单地规定"某专家被选择一次就增加一次惩罚",而是:
当流量过度集中在少数专家时,提高辅助损失。
辅助损失权重过小,可能无法解决专家坍缩;权重过大,又可能干扰模型根据 token 内容选择合适专家。
专家容量限制
每个专家在一个 batch 中能够处理的 token 数量通常有上限。
例如:
每个专家最多接收 100 个 token
当某个专家超过容量后,额外 token 可能会:
-
被丢弃;
-
进入第二候选专家;
-
被重新分配;
-
通过残差路径跳过专家计算。
专家容量通常与下面因素有关:
总 token 数
专家数量
每个 token 选择的专家数量
capacity factor
容量限制可以防止单个专家负载过大,但容量过小可能导致大量 token 无法进入首选专家。
Router 噪声
训练时可以在 Router logits 中加入少量噪声:
router_logits
→ 加入噪声
→ 再选择 Top-k 专家
作用是:
-
增加早期探索;
-
防止 Router 过早固定在少数专家上;
-
让不同专家有机会接收到训练样本。
这并不是直接强制选择低分专家,而是轻微扰动专家排序,使分数接近的专家都有机会被选择。
推理阶段通常关闭这类随机噪声。
Router 正则化与稳定化
还可以使用:
-
Router logits 正则化;
-
限制 Router logits 过大;
-
合理初始化 Router;
-
调整 Router 学习率;
-
对 Router 使用更高精度计算;
-
设置共享专家或始终激活的专家。
这些方法主要用于避免 Router 过早饱和和训练数值不稳定。
7. Dense 与 MoE 对比
| 对比项 | Dense | MoE |
|---|---|---|
| FFN 数量 | 每层通常一套 | 每层包含多个专家 FFN |
| 每个 token 激活范围 | 激活全部 FFN 参数 | 只激活 Top-k 专家 |
| 总参数量 | 相对较小 | 可以非常大 |
| 单 token 计算量 | 随总参数量增加 | 低于同总参数量 Dense 模型 |
| 权重存储 | 保存全部参数 | 仍需保存全部专家参数 |
| KV Cache | 主要由 Attention 决定 | 通常不会因 FFN MoE 直接变化 |
| 训练稳定性 | 相对稳定 | Router 和负载均衡更复杂 |
| 多卡通信 | 相对简单 | 可能产生较大 All-to-All 通信 |
| 主要问题 | 扩大参数会直接增加计算量 | 专家坍缩、负载不均、通信开销 |
核心区别可以概括为:
Dense:
每个 token 使用同一套完整 FFN。
MoE:
模型拥有多套专家 FFN,
但每个 token 只选择其中少数几个参与计算。
MoE 并不是让模型"用更少参数",而是:
保存大量参数形成更大的模型容量,同时通过稀疏激活控制每个 token 的实际计算量。