27届大模型面试准备(二十一):MoE 架构全攻略——稀疏激活、路由、负载均衡与专家并行

27届大模型面试准备(二十一):MoE 架构全攻略------稀疏激活、路由、负载均衡与专家并行

上一篇《评测体系全攻略》收尾时说过,A 系列前二十篇走完了"架构---训练---对齐---推理---量化---评测"的完整链路,接下来转向更前沿的主题。这一篇是第二十一篇,讲混合专家(Mixture of Experts,MoE)。为什么先讲它?因为 2024 年之后所有你叫得出名字的开源旗舰模型------Mixtral、DeepSeek-V2/V3、Qwen2-MoE、Llama 4、Kimi K2------全部是 MoE 架构。面试里问"你了解 MoE 吗",大部分人能答出"稀疏激活、只激活部分专家",然后就没了。而真正的区分度在后面:路由怎么设计、负载不均衡怎么办、专家并行的 All-to-All 通信开销有多大、为什么 MoE 训练容易崩、为什么 MoE 推理的显存和吞吐特性和稠密模型完全不同。本文按"为什么要 MoE → MoE 层的结构 → 路由算法演进 → 负载均衡 → 细粒度与共享专家 → 专家并行与通信 → 推理部署的坑 → MoE 的固有缺陷"展开,结尾给面试速答和高频追问清单。


一、为什么需要 MoE:Scaling Law 撞上成本墙

1.1 稠密模型的困境

Scaling Law 告诉我们模型效果随参数量增长,但稠密(Dense)模型有一个残酷的性质:参数量翻倍,训练算力翻倍,推理算力也翻倍。每一个 token 的前向计算都要走过全部参数。

设模型参数量为 N,训练 token 数为 D,稠密模型的训练 FLOPs 约为 6ND,推理时每 token 前向约 2N。这意味着:

  • 想要 400B 的效果,就得付 400B 的推理成本
  • 而推理成本是乘以请求量的,训练是一次性的,推理是永久性的

于是问题变成:能不能让参数量涨、但每个 token 实际用到的参数不涨?

1.2 MoE 的核心思想:解耦总参数与激活参数

复制代码
              稠密模型 vs MoE 的计算路径对比

  Dense (70B)                        MoE (总 400B / 激活 40B)

  token                              token
    │                                  │
    ▼                                  ▼
  ┌──────────────┐              ┌──────────────┐
  │  Attention   │              │  Attention   │  (通常不做 MoE)
  └──────┬───────┘              └──────┬───────┘
         ▼                             ▼
  ┌──────────────┐              ┌─────────────────────────┐
  │              │              │  Router (gating)        │
  │   FFN 全部   │              │  选 Top-2 / 64 专家     │
  │   参数参与   │              └───┬─────────────────┬───┘
  │   计算       │                  │  只激活 2 个    │
  │              │              ┌───▼──┐ ┌────┐ ┌───▼──┐
  └──────┬───────┘              │ E1 ✓ │ │ E2 │ │ E3 ✓ │ ...
         ▼                      └───┬──┘ └────┘ └───┬──┘
      输出                          └────加权求和────┘
                                            ▼
                                          输出
  参数量 = 计算量                  参数量 >> 计算量
  推理每 token 走 70B              推理每 token 只走 40B
  显存 70B                         显存仍需 400B(全部专家要驻留)

最关键的一句话总结 :MoE 用显存算力。参数全部要放进显存,但每个 token 只用其中一小部分做计算。这句话是回答后面所有推理部署问题的钥匙。

1.3 主流 MoE 模型参数对照

模型 总参数 激活参数 专家数 每 token 激活 共享专家 备注
Mixtral 8x7B 46.7B 12.9B 8 Top-2 MoE 开源破圈之作
Mixtral 8x22B 141B 39B 8 Top-2
DeepSeek-V2 236B 21B 160 Top-6 2 细粒度专家
DeepSeek-V3 671B 37B 256 Top-8 1 无辅助损失负载均衡
Qwen2-57B-A14B 57B 14B 64 Top-8 8
Llama 4 Scout 109B 17B 16 Top-1 1 交替 MoE 层
GPT-OSS-120B 117B 5.1B 128 Top-4 稀疏度极高

从表里能读出两条清晰的演进趋势:

  1. 专家数从 8 涨到 256:即"细粒度专家化",每个专家变小、数量变多,组合空间指数级增长
  2. 稀疏度越来越极端:GPT-OSS-120B 激活率只有 4.4%,DeepSeek-V3 是 5.5%,而 Mixtral 8x7B 是 27.6%

面试可以主动抛出的观点:稀疏度是可以调的超参,它本质上是在"专家专业化程度"和"训练稳定性"之间做权衡。稀疏度越高,单位算力能撑起的知识容量越大,但路由学习越困难、训练越不稳定。


二、MoE 层的结构与前向计算

2.1 替换的是 FFN,不是 Attention

标准 Transformer 层 = Attention + FFN。MoE 替换的是 FFN 部分,Attention 保持稠密。

原因很直接:FFN 占了稠密模型约 2/3 的参数量(在 d_ff = 4*d_model 的配置下),是参数大头;而 Attention 涉及 token 之间的交互,如果稀疏化,不同 token 走不同的 Attention 权重会破坏序列建模的一致性,且 KV Cache 会变得无法管理。

2.2 前向计算公式

对输入 token 表示 x ∈ R^d

复制代码
1) 路由打分:     h = W_g · x            (W_g ∈ R^{E×d}, E 为专家数)
2) 选 Top-K:     I = TopK(h, k)         (返回 k 个专家下标)
3) 归一化权重:   g_i = softmax(h_I)_i   (只在选中的 k 个上做 softmax)
4) 专家计算:     y = Σ_{i∈I} g_i · FFN_i(x)

注意第 3 步的细节------softmax 是在 Top-K 之后做,还是之前做,这是一个高频考点:

  • 先 softmax 再 TopK:权重是全局归一化后取 k 个,选中权重之和小于 1
  • 先 TopK 再 softmax(主流做法):选中的 k 个权重之和恰好为 1

后者更常见,因为它保证了输出的尺度稳定,不会因为路由置信度低而整体衰减。DeepSeek-V3 用的是 sigmoid 打分加归一化,进一步解耦了专家之间的竞争关系。

2.3 一个最小可运行的 MoE 层

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F


class Expert(nn.Module):
    """标准 SwiGLU FFN 作为单个专家。"""
    def __init__(self, d_model: int, d_ff: int):
        super().__init__()
        self.w1 = nn.Linear(d_model, d_ff, bias=False)   # gate
        self.w3 = nn.Linear(d_model, d_ff, bias=False)   # up
        self.w2 = nn.Linear(d_ff, d_model, bias=False)   # down

    def forward(self, x):
        return self.w2(F.silu(self.w1(x)) * self.w3(x))


class MoELayer(nn.Module):
    def __init__(self, d_model, d_ff, n_experts=8, top_k=2,
                 n_shared=0, capacity_factor=1.25):
        super().__init__()
        self.n_experts = n_experts
        self.top_k = top_k
        self.capacity_factor = capacity_factor
        self.gate = nn.Linear(d_model, n_experts, bias=False)
        self.experts = nn.ModuleList(
            [Expert(d_model, d_ff) for _ in range(n_experts)])
        # 共享专家:所有 token 都经过,负责通用知识
        self.shared = nn.ModuleList(
            [Expert(d_model, d_ff) for _ in range(n_shared)])

    def forward(self, x):
        B, T, D = x.shape
        x_flat = x.reshape(-1, D)                    # [N, D], N = B*T

        logits = self.gate(x_flat)                   # [N, E]
        topk_logits, topk_idx = logits.topk(self.top_k, dim=-1)
        topk_w = F.softmax(topk_logits, dim=-1)      # TopK 之后再 softmax

        out = torch.zeros_like(x_flat)

        # 按专家分组批处理,避免逐 token 循环
        for e in range(self.n_experts):
            mask = (topk_idx == e)                   # [N, k]
            if not mask.any():
                continue
            tok_idx, slot_idx = mask.nonzero(as_tuple=True)
            expert_in = x_flat[tok_idx]              # [n_e, D]
            expert_out = self.experts[e](expert_in)
            w = topk_w[tok_idx, slot_idx].unsqueeze(-1)
            out.index_add_(0, tok_idx, expert_out * w)

        for sh in self.shared:                       # 共享专家无条件参与
            out = out + sh(x_flat)

        aux = self._aux_loss(logits, topk_idx)
        return out.reshape(B, T, D), aux

    def _aux_loss(self, logits, topk_idx):
        """Switch Transformer 式负载均衡损失。"""
        probs = F.softmax(logits, dim=-1)                             # [N, E]
        one_hot = F.one_hot(topk_idx, self.n_experts).sum(1).float()  # [N, E]
        f = one_hot.mean(0)                          # 实际路由比例
        P = probs.mean(0)                            # 路由概率均值
        return self.n_experts * torch.sum(f * P)

这段代码有三个实现要点值得在面试里主动讲:

  1. 按专家分组而非逐 token 循环mask.nonzero() 把 token 按专家聚类,一次性做矩阵乘法。逐 token 循环会让 GPU 利用率跌到个位数
  2. index_add_ 而不是索引赋值:一个 token 可能被多个专家处理(Top-K),必须累加而不是覆盖
  3. 辅助损失在前向里返回:负载均衡损失是每层都要算的,最后汇总加到总 loss 上

三、路由算法:从 Noisy Top-K 到 Expert Choice

路由器(Router)是 MoE 的灵魂,它决定"哪个 token 交给哪个专家"。演进路线值得完整讲一遍。

3.1 演进脉络

复制代码
2017 Noisy Top-K Gating (Shazeer, Sparsely-Gated MoE)
     └─ 加高斯噪声打破平局,Top-K (k≥2)
     └─ 认为 k≥2 才能让梯度传到路由器
              ▼
2021 Switch Transformer (Fedus et al.)
     └─ 大胆用 Top-1,证明 k=1 也能训好
     └─ 引入 capacity factor + token drop
              ▼
2022 Expert Choice (Zhou et al.)
     └─ 反转选择方向:专家挑 token,天然负载均衡
              ▼
2022 BASE / S-BASE
     └─ 把路由看成最优传输/线性分配问题,硬约束均衡
              ▼
2024 DeepSeekMoE + Aux-Loss-Free
     └─ 细粒度专家 + 共享专家
     └─ 用可学习 bias 替代辅助损失,不干扰主任务梯度

3.2 Token Choice vs Expert Choice

复制代码
  Token Choice (主流)               Expert Choice
  每个 token 选 k 个专家             每个专家选 c 个 token

  t1 ──┐                            E1 ──选──> [t1, t3, t7]
  t2 ──┼──> E1 (超载! 3个)          E2 ──选──> [t2, t3, t5]
  t3 ──┘                            E3 ──选──> [t4, t6, t8]
  t4 ─────> E2 (只有1个)
  t5 ─────> E3                      每个专家恰好 c 个 token
  ...                               负载天然完美均衡
  → 负载天然不均衡,需要辅助损失     → 但某些 token 可能没人选
  → 每个 token 保证被处理            → 或被超多专家选中
  → 自回归推理友好                   → 需要看到整个 batch,
                                       自回归解码时不可用

Expert Choice 的致命问题 :它需要在专家维度上对整个 batch 的 token 做 Top-C 选择,这在训练时可以(整个序列已知),但在自回归解码时,token 是一个个生成的,无法预知未来 token,会造成信息泄漏(future token leakage)。所以生产模型基本都用 Token Choice,Expert Choice 主要用在编码器或非自回归场景。

3.3 各路由方案对比表

方案 选择方向 负载均衡 需要辅助损失 自回归可用 代表模型
Noisy Top-K token→expert GShard
Switch (Top-1) token→expert Switch-T
Expert Choice expert→token 完美 部分编码器
BASE (最优传输) 双向匹配 完美 BASE Layers
Aux-Loss-Free token→expert 否(用 bias) DeepSeek-V3
Soft MoE 加权混合 完美 视觉领域

四、负载均衡:MoE 训练最大的工程难题

4.1 为什么会不均衡:马太效应

路由器初始化是随机的,某个专家偶然被多选几次,它就得到更多训练、变得更强、被选中概率更高,其他专家逐渐饿死。这就是专家坍塌(expert collapse),极端情况下 90% 的 token 都涌向两三个专家,剩下的专家参数纯属浪费。

不均衡带来两个后果:

  • 效果层面:等效于一个参数量小得多的模型,MoE 白做了
  • 系统层面:专家分布在不同 GPU 上,负载最重的那张卡成为瓶颈,其他卡等待,训练吞吐被拖垮

4.2 辅助损失(Auxiliary Loss)

Switch Transformer 的经典形式:

复制代码
L_aux = α · E · Σ_{i=1}^{E} f_i · P_i

f_i = 被路由到专家 i 的 token 比例(离散,不可导)
P_i = 路由器给专家 i 的平均概率(连续,可导)
α   = 权重系数,典型值 0.01

理解这个式子的关键:f_i 不可导,梯度只通过 P_i 回传。当专家 i 过载时 f_i 大,这一项的梯度会压低 P_i,从而减少后续路由到 i 的概率。当所有专家完全均衡时,f_i = P_i = 1/EL_aux 达到最小值 1。

还有一个常被忽略的 z-loss

复制代码
L_z = (1/N) · Σ_n (log Σ_i exp(h_i^{(n)}))²

它约束路由 logits 的绝对值不要发散。MoE 训练中 router logits 爆炸是训练崩溃的常见前兆,尤其在 bf16 下。z-loss 权重一般取 1e-3。

4.3 容量因子与 Token Drop

专家并行下每个专家有固定的 buffer 大小:

复制代码
capacity = capacity_factor × (tokens_per_batch × top_k / n_experts)

超出容量的 token 会被丢弃(drop),直接走残差连接跳过 MoE 层。

capacity_factor 显存 Token Drop 率 适用场景
1.0 最省 高(10%+) 极端省显存
1.25 低(1-3%) 训练常用
2.0 接近 0 微调/小规模
无限(dropless) 变长 0 MegaBlocks 方案

面试加分点 :现代实现(MegaBlocks、DeepSpeed-MoE 的 dropless 模式)用块稀疏矩阵乘法(block-sparse GEMM)替代固定 buffer,把变长的专家输入组织成分块稀疏矩阵,从而彻底消除 token drop,同时保持 GPU 效率。这是 dropless MoE 的技术本质。

4.4 DeepSeek-V3 的 Aux-Loss-Free 策略

辅助损失有个固有矛盾:它是和主任务 loss 竞争的,权重大了伤效果,权重小了压不住不均衡。

DeepSeek-V3 的解法非常优雅------给每个专家加一个可学习的 bias,只影响选择、不影响权重

python 复制代码
# 路由打分
score = sigmoid(W_g @ x)              # [E], 用于计算最终加权
# 选择时加 bias
topk_idx = (score + bias).topk(k).indices
# 但加权仍用原始 score,bias 不参与前向输出
weight = normalize(score[topk_idx])

# 训练中每步根据负载调整 bias(不走梯度,直接规则更新)
for e in range(E):
    if load[e] > avg_load:
        bias[e] -= gamma          # 过载则降低被选概率
    else:
        bias[e] += gamma          # 欠载则提高

bias 不参与梯度反传,纯靠规则更新,因此完全不干扰主任务的优化方向。这是 V3 能在 671B 规模上稳定训练的关键工程点之一,也是面试里非常容易讲出彩的细节。


五、细粒度专家与共享专家(DeepSeekMoE)

5.1 细粒度专家:切碎组合空间

传统做法是 8 个大专家选 2 个,组合数 C(8,2) = 28。DeepSeekMoE 的思路是:把每个专家的 d_ff 缩小到 1/m,专家数扩大 m 倍,同时 Top-K 也扩大 m 倍。

配置 专家数 每专家 d_ff Top-K 组合数 激活参数
传统 8 4096 2 28 相同
细粒度 m=4 32 1024 8 10,518,300 相同

激活参数量完全不变,但专家组合的表达空间从 28 涨到千万级。这让每个专家能学到更专精、更正交的知识。代价是路由计算量增加、All-to-All 通信的消息数增加。

5.2 共享专家:隔离通用知识

观察:语法、常识这类通用知识每个专家都得学一遍,造成参数冗余。

DeepSeekMoE 拿出 1 到 2 个共享专家(shared expert),所有 token 无条件经过;剩下的路由专家专注差异化知识。

复制代码
        输入 token
             │
      ┌──────┴──────┐
      ▼             ▼
  共享专家       Router → Top-K 路由专家
  (必经)              (E1  E5  E9 ...)
      │                    │
      └────── 相加 ────────┘
             ▼
           输出

好处有三个:减少专家间的知识冗余、给路由失误提供兜底(哪怕路由错了,共享专家保证基础能力)、稳定训练早期的梯度。


六、专家并行与 All-to-All 通信

这部分和第十七篇《分布式训练全攻略》直接衔接。

6.1 EP(Expert Parallelism)的通信模式

专家分布在不同 GPU 上,token 需要飞到目标专家所在的卡上计算,再飞回来:

复制代码
  Step 1: 本地路由打分(各卡独立)
  Step 2: All-to-All Dispatch ------ 按目标专家把 token 发出去

     GPU0 [t1→E2, t2→E0]      GPU1 [t3→E0, t4→E3]
              │                        │
              └────── All-to-All ──────┘
                        ▼
     GPU0 持有 E0,E1 收到 [t2, t3]
     GPU1 持有 E2,E3 收到 [t1, t4]

  Step 3: 各卡本地跑专家 FFN
  Step 4: All-to-All Combine ------ 结果发回原始 token 所在卡
  Step 5: 加权求和 + 残差

每个 MoE 层需要 2 次 All-to-All,这是 MoE 训练最主要的通信开销。All-to-All 的特性是通信量随参与设备数线性增长,且对网络拓扑极其敏感------跨节点(NVLink 之外走 InfiniBand/RoCE)的带宽比节点内低一个数量级。

6.2 并行策略组合

并行维度 切分对象 通信原语 在 MoE 中的角色
DP batch All-Reduce 基础,配 ZeRO 分片优化器
TP 单层权重矩阵 All-Reduce 切 Attention 与共享专家
PP P2P Send/Recv 跨节点扩展
EP 专家 All-to-All MoE 专属
SP 序列 All-Gather 长序列时配合

典型的 DeepSeek-V3 配置是 EP × PP × DP 的三维组合,EP 尽量放在节点内(用 NVLink 跑 All-to-All),PP 跨节点。

6.3 通信优化手段

  1. 计算通信重叠:把 dispatch 拆成多个 chunk,第一个 chunk 通信完就开始算,与后续 chunk 的通信重叠。DeepSeek 的 DualPipe 把这个做到了极致
  2. 限制跨节点路由(Device-Limited Routing):约束每个 token 最多路由到 M 个节点(V2 用 M=3),把 All-to-All 的跨节点消息数压下来
  3. 通信量压缩:dispatch 时用 FP8 传输,combine 时用 BF16(因为 combine 涉及累加,精度更敏感)
  4. 分层 All-to-All:先节点内聚合,再节点间传输,最后节点内分发,减少跨节点消息数

七、推理部署:MoE 的特性与稠密模型完全不同

7.1 显存墙才是主要矛盾

回到第一节那句话:MoE 用显存换算力。DeepSeek-V3 激活只有 37B,但 671B 参数全部要驻留显存:

复制代码
FP16:  671B × 2 Byte = 1342 GB  → 需要 17 张 H100(80G)
INT8:  671B × 1 Byte =  671 GB  → 需要 9 张
INT4:  671B × 0.5 B  =  336 GB  → 需要 5 张

对比稠密的 Llama-70B FP16 只要 140GB,两张卡搞定。所以 MoE 是"大厂友好、个人不友好"的架构:它降低了单 token 的算力成本,但抬高了部署的显存门槛。

7.2 批处理下的"专家激活爆炸"

这是最容易被忽略、也最能体现工程经验的一点:

  • batch=1 时,一个 token 只激活 8/256 个专家,实际读取的权重很少,是标准的 memory-bound 场景,MoE 优势巨大

  • batch=64 时,64 个 token 各选 8 个专家,并集很可能覆盖了几乎全部 256 个专家

    复制代码
    batch=1   → 激活专家集合 {E3, E17, E88, ...}  共 8 个
    batch=8   → 并集约 50 个
    batch=64  → 并集约 220 个(接近全部)
    batch=256 → 并集 = 全部 256 个

后果:大 batch 下 MoE 的权重读取量退化到接近稠密模型,节省的只是矩阵乘法的 FLOPs,而不是显存带宽。这就解释了为什么 MoE 在高并发服务下的吞吐优势远小于理论值。

应对手段是 Expert Parallel 加大规模专家分片:把专家摊到很多卡上,每张卡只持有少量专家,用 All-to-All 换取每卡显存压力下降,同时靠更大的总 batch 摊薄通信成本。DeepSeek 的推理系统用了 EP144 这种极端配置就是这个道理。

7.3 专家卸载(Expert Offloading)

单卡跑大 MoE 的方案:把不常用的专家放在 CPU 内存或 NVMe,按需加载。

复制代码
GPU 显存: Attention 权重 + 共享专家 + 热点专家缓存(LRU)
CPU 内存: 全部路由专家
         ↑ 按 router 预测结果预取

关键优化是预取:利用相邻层路由结果的相关性,在计算第 L 层时提前预测第 L+1 层可能用到的专家并异步加载。Mixtral-Offloading、Fiddler 等工作证明这能把单卡跑 8x7B 的速度做到可用(3 到 5 token/s)。

7.4 MoE 量化的特殊性

和第十九篇《模型量化全攻略》呼应,MoE 量化有三个独有的坑:

  1. 专家间敏感度差异巨大:高频专家量化误差影响大,冷门专家可以更激进。混合精度方案(热点专家 INT8、冷门专家 INT4)比统一量化效果好
  2. 共享专家绝对不能激进量化:它参与所有 token 的计算,误差会被无条件放大到每一个 token 上,通常保持 FP16 或 INT8
  3. Router 必须保持高精度 :router 只有 E × d 个参数,占比极小,但量化它会直接改变路由决策,导致完全不同的专家被选中,属于典型的省了芝麻丢了西瓜

八、MoE 的固有缺陷

诚实地讲清楚缺点,是面试里体现判断力的地方。

缺陷 表现 缓解手段
训练不稳定 router logits 发散、loss spike z-loss、bf16、router 用 fp32 计算
微调易过拟合 小数据集上 MoE 显著差于稠密 冻结专家只调 router/Attention;更强正则
显存门槛高 部署成本高 量化、专家卸载、EP 分片
负载不均衡 训练吞吐被最慢卡拖累 辅助损失、bias 调整、dropless
通信瓶颈 All-to-All 占 20-40% 时间 重叠、分层通信、限制跨节点路由
效果收益非线性 专家数翻倍收益递减 细粒度 + 共享专家

关于微调过拟合再多说一句,这是实际项目里最常踩的坑:MoE 的总参数量巨大,在几千条 SFT 数据上全参微调几乎必然过拟合,且路由会退化------所有 token 都涌向少数专家。实践中的做法是用 LoRA(见第十八篇)只在 Attention 和共享专家上加适配器,路由器和路由专家整体冻结。


九、面试速答

Q:一句话解释 MoE,以及它到底省了什么?

A:MoE 把 Transformer 的 FFN 层替换成多个并行的专家网络加一个路由器,每个 token 只激活其中 Top-K 个专家。它省的是每 token 的计算量(FLOPs),不省显存------所有专家参数都要驻留。所以本质是用显存换算力,让模型的知识容量和推理成本解耦。

Q:为什么 MoE 只替换 FFN,不动 Attention?

A:三个原因。第一,FFN 占稠密模型约三分之二的参数,是参数大头,收益最大。第二,Attention 负责 token 之间的信息交互,如果不同 token 走不同的 Attention 权重,序列建模的一致性会被破坏。第三,工程上 KV Cache 的管理会变得极其复杂------每个 token 的 KV 用哪个专家的投影矩阵算出来的,后续注意力还怎么统一计算。

Q:负载不均衡为什么必须解决?辅助损失的原理是什么?

A:不均衡有两层危害。模型层面会出现专家坍塌,大部分 token 涌向少数专家,其他专家参数浪费,等效于一个小得多的模型。系统层面在专家并行下,专家分布在不同 GPU 上,最重负载的卡成为木桶短板,其他卡空转。辅助损失的形式是 α·E·Σ f_i·P_i,其中 f_i 是实际路由比例(不可导),P_i 是路由概率均值(可导),梯度只通过 P_i 回传,过载专家的概率会被压低。均衡时该损失取最小值 1。

Q:DeepSeek-V3 的无辅助损失负载均衡怎么做的?为什么更好?

A:给每个专家加一个可学习的偏置项,这个偏置只参与 Top-K 的选择过程,不参与最终输出的加权计算。训练中每步统计各专家实际负载,过载的降低 bias、欠载的提高 bias,用规则更新而非梯度更新。它更好的原因是:传统辅助损失是加在总 loss 上和主任务竞争的,权重大了伤模型效果、小了压不住不均衡,本质上是个两难;而 bias 完全不进入反向传播,对主任务优化方向零干扰,把负载均衡从优化目标降级成了调度手段。

Q:Top-1 和 Top-2 路由怎么选?

A:早期 Shazeer 认为必须 k 大于等于 2,理由是只有多个专家参与,路由权重之间才有相对比较,梯度才能有效传到 router。Switch Transformer 推翻了这个观点,证明 Top-1 配合合适的辅助损失和初始化也能训好,而且通信量和计算量直接减半。现在的实践是:在细粒度专家架构下用较大的 k(比如 256 选 8),因为单个专家变小了,需要多个组合才能提供足够的表达能力;在粗粒度大专家架构下用小 k。选择依据是激活参数量这个预算约束,而不是 k 本身。

Q:MoE 在推理服务里的吞吐优势为什么没有理论值那么大?

A:因为批处理下的专家激活并集问题。batch=1 时只激活 8 个专家,权重读取量确实只有理论上的一小部分。但 batch 增大后,不同 token 选中的专家并集迅速扩张,batch 到 64 以上时并集几乎覆盖全部专家,此时权重读取量退化到接近稠密模型,只在矩阵乘法的 FLOPs 上有节省。而 LLM 解码阶段本来就是 memory-bound 而非 compute-bound,所以节省 FLOPs 的收益有限。这也是为什么大规模 MoE 服务必须配合大规模专家并行,把专家摊到很多卡上摊薄单卡的权重读取压力。

Q:Expert Choice 路由为什么不能用在自回归生成上?

A:Expert Choice 是反转选择方向,让每个专家从整个 batch 里挑固定数量的 token,这样负载天然完美均衡。但它要求在做选择时能看到 batch 内所有 token 的打分,而自回归解码是逐 token 生成的,当前步无法看到未来 token。如果强行在训练时用 Expert Choice,等于让模型在训练时用到了未来信息,训练和推理行为不一致,属于信息泄漏。所以它只适用于编码器或非自回归场景。

Q:MoE 微调有什么特别注意的?

A:最大的问题是过拟合和路由退化。总参数量巨大而下游数据往往只有几千到几万条,全参微调几乎必然过拟合,同时路由器会快速退化成只用少数几个专家,破坏预训练时学到的专业化分工。实践方案是分层处理:路由器和路由专家整体冻结,只在 Attention 和共享专家上加 LoRA 适配器;如果一定要动路由器,用极小的学习率并保留辅助损失。另外评测时要专门监控专家使用分布的熵,熵大幅下降就是路由退化的信号。

Q:怎么判断一个 MoE 训练是否健康?看哪些指标?

A:至少四个。第一是专家负载分布,用变异系数或熵衡量,理想是接近均匀;第二是 token drop 率,超过 5% 说明容量因子设小了;第三是 router logits 的最大绝对值,持续增长是发散前兆,靠 z-loss 压制;第四是辅助损失本身的数值,Switch 形式的理论下界是 1,长期显著大于 1 说明均衡没做好。此外还要看不同层的路由模式,浅层通常路由较随机、深层专业化更明显,如果所有层都随机说明专家没学出分工。


十、高频追问清单

  1. MoE 的辅助损失里 f_i 不可导,为什么整个损失还能优化负载均衡?
  2. z-loss 具体防止什么问题?为什么 bf16 下更需要它?
  3. dropless MoE 用块稀疏矩阵乘法实现,它和固定容量方案的性能差距在哪?
  4. All-to-All 通信量怎么估算?和 All-Reduce 相比在什么规模下更贵?
  5. 细粒度专家把 d_ff 切小,会不会影响单个专家的表达能力?边界在哪?
  6. 共享专家的数量怎么定?多了少了各有什么问题?
  7. 如果观察到某几个专家从来不被激活,你会怎么排查和处理?
  8. MoE 模型做知识蒸馏,学生模型该用稠密还是 MoE?
  9. 上下文并行(CP)和专家并行(EP)能同时用吗?会有什么冲突?
  10. MoE 的 router 能不能做成基于内容的层次化路由(先选组再选专家)?
  11. 为什么有些模型(Llama 4)用交替的 MoE 层和稠密层,而不是每层都 MoE?
  12. 推理时能否根据请求难度动态调整 Top-K?会带来什么问题?

MoE 是当前所有旗舰模型的默认选择,但它带来的不只是架构变化,而是整条训练与推理工程链路的重构。下一篇会讲推理时扩展(test-time scaling)与强化学习新范式------如果说 MoE 解决的是"如何让模型更大而不更贵",那么推理时扩展解决的是"如何让模型在不变大的前提下想得更深",两者正好是当前提升模型能力的两条正交路径。

相关推荐
tachibana21 小时前
知识库文档上传接口
数据库·人工智能·大模型·llm
@Mr_LiuYang3 小时前
《深入理解 AI Agent:设计原理与工程实践 》实验2-2 2-7 大模型注意力权重分布可视化
人工智能·大模型·agent·注意力机制
落子AI17 小时前
智谱GLM-4.5编程智能体深度实测:355B MoE架构如何重塑AI编程体验
大模型·ai编程·智能体·glm-4.5·ai工具推荐
thesky1234561 天前
27届大模型面试准备(十九):模型量化全攻略——INT8/INT4、GPTQ、AWQ、SmoothQuant 与 KV Cache 量化
大模型·模型量化·gptq·awq·kv cache·smoothquant·int4
深圳市快瞳科技有限公司1 天前
个体识别、行为解读、健康管理:多模态宠物AI大模型的场景化落地
人工智能·算法·计算机视觉·大模型·多模态·宠物·宠物ai识别
安逸sgr1 天前
AI 编程工具在真实项目中适合做什么?不适合做什么?
人工智能·ai·大模型·agent·智能体
thesky1234561 天前
27届大模型面试准备(二十):评测体系全攻略——Benchmark、数据污染、LLM-as-Judge 与 Arena 对战
大模型·benchmark·模型评测·llm-as-judge·数据污染·elo·mmlu
大鹏的NLP博客1 天前
大模型 Tokenizer:从字符到 Byte,再到大词表
深度学习·机器学习·大模型·分词