上一章 KV Cache:多轮对话的隐性账单 Agent 的成本大头不在输入,而在每一轮都要重新送一遍的历史。KV Cache 把重复计算变成缓存命中,而命中率取决于一个你从没注意过的细节:前缀稳定性。 I · 大模型原理 · 第 02 章 · 进阶 · 约 26 分钟
Agent 工程学习站 做棵大树 出品 主站 beatree.cn 免费 · 无需登录 · 进度存本机
I 版 · 大模型原理 ◆ 第 03 章 ◆ Sparse Activation
I · 大模型原理 03 / 22 进阶

MoE 与稀疏激活

Sparse Activation
预计阅读 24 分钟
难度 进阶
关键词 MoE · 路由
本机状态 未读

一个 671B 总参数的模型,为什么在成本上能和几十 B 的稠密模型打平?答案藏在两个数字之间的那条缝里:总参数量与激活参数量。理解这条缝,你就能解释模型选型里最反直觉的那些现象。

编辑部注 · 本章最容易答错的是一道看似简单的推理题:稀疏激活省的是算力还是显存?请务必读到最后一节。

模型参数有两个口径,混用会让人得出完全相反的结论。

第一个是 总参数量(Total Parameters)——模型文件有多大,要占多少显存去装。第二个是 激活参数量(Active Parameters)——每生成一个 token,实际参与计算的有多少。稠密模型(Dense Model)里这两个数字相等;混合专家(Mixture of Experts)把它们拆开了。

一、两个数字之间的缝

设一个 MoE 模型有 256 个专家(Expert),每个专家约 2.6B 参数,每层路由稀疏激活(Sparse Activation)其中 8 个。

口径稠密模型MoE 模型工程后果
总参数量与激活量相同所有专家之和,例如 671B决定显存下限:权重得装得下
激活参数量同上每 token 只走 top-k 个专家,例如 37B决定单 token 算力:接近一个 37B 稠密模型
每 token FLOPs与总参数成正比与激活参数成正比吞吐高、单价低
跨设备通信少(同层并行即可)多(专家分布在不同设备,需 All-to-All)延迟与实现复杂度上升
训练稳定性较稳路由易坍缩,需负载均衡损失训练工程难度更高

一句话概括 MoE 的交易:用显存和通信换算力效率。参数总量上去了(容量变大),但每个 token 的计算量没跟着上去——由门控网络(Gating Network)在运行时挑出少数专家来算。

MoE 不是让模型变小,而是让「不参与计算的参数」变得便宜。本刊编辑部

二、路由是怎么工作的

MoE 层内部:先选路,再计算 token x [d] 门控 / 路由 softmax(x·W_g) 取 top-k 专家 17 权重 0.61 激活 专家 03 权重 0.39 激活 专家 88 权重 0 专家 129 权重 0 ⋮ 其余 252 个专家不参与本 token 计算 加权求和 0.61·E17(x) + 0.39·E03(x) 为什么 MoE 的成本结构这么特殊 容量看总数:256 个专家 = 671B 参数的知识容量 → 需要显存装下全部权重。 算力看激活:每 token 只跑 2 个专家 ≈ 37B 的算力 → 单 token 成本接近 37B 稠密模型。 代价:专家分散在多卡上,每次路由都要跨设备搬运 token(All-to-All 通信)。
图 1 MoE 层用一个小门控网络给每个 token 选 top-k 个专家,只跑选中的那几个,最后按权重加权。注意「权重 0」的专家并非从显存里消失——它们仍占着地方,只是不参与这一 token 的计算。

三、省的是算力,不是显存

这是本章最重要的一句话,也是最容易答错的地方:

常见错误答案

错误说法:「MoE 因为只激活部分专家,所以显存需求也降低了,能在小显存上部署大模型。」

为什么错:路由是运行时根据输入动态决定的。你无法预知下一个 token 会选哪两个专家,所以所有专家的权重都必须常驻显存(或在需要时快速换入,代价极高)。MoE 压缩的是每 token 的 FLOPs,不是权重的存储体积。

正确说法:MoE 让「参数容量」和「单 token 算力」解耦——你可以拥有 671B 的知识容量,却只付 37B 的算力账单;但显存下限仍然由 671B 决定。

由此衍生出几个工程结论:

  • MoE 的部署门槛是显存,不是算力。 这就是为什么 MoE 模型通常只在云端大规模集群上跑,很难本地化。
  • MoE 的延迟优势不如吞吐优势明显。 单请求延迟受 All-to-All 通信 影响,可能反而比同激活量的稠密模型更慢;但吞吐(单位时间处理 token 数)会好很多。
  • MoE 对 batch 敏感。 batch 越大,专家利用率越高,单位成本越低。这解释了为什么小 batch 场景下 MoE 的性价比优势会缩水(也更容易出现路由坍缩(Routing Collapse),需要负载均衡损失(Load Balancing Loss)来对抗)。
总参数与激活参数之间,那道缝 条宽 ∝ 参数量(同一比例);缝 = 没被激活的参数 总参数量 671B(容量)→ 决定显存下限 激活 37B 每 token 算力 ≈ 37B 稠密模型(仅 5.5%) 路由只激活 top-8 / 256 ↑ 这道缝就是 MoE 的性价比来源 一句话:容量看总数,算力看激活,显存看总数 总参数量(671B)决定「模型文件多大、显存下限多少」——权重必须全部装下。 激活参数量(37B)决定「每生成一个 token 要算多少」——这是单 token 成本与吞吐的来源。 所以 MoE 让「参数容量」和「单 token 算力」解耦:你能拥有 671B 的容量,却只付 37B 的算力账。
图 2 同是 671B 的 MoE,每 token 实际只跑约 37B 的算力。这道「缝」就是 MoE 的全部性价比:容量上去了,单 token 账单没上去——但显存下限仍由 671B 决定。
路由坍缩:容量是怎么被浪费的 左:理想均匀 右:少数专家占满、其余闲置 理想:均匀使用 256 个专家,使用率接近均匀(各 ≈ 1/256) 每个专家都被训练到 → 671B 容量全用上 坍缩:少数占满 E1 高 E2 E3 其余 253 个专家使用率 ≈ 0 门控正反馈是坍缩的根因 某些专家偶然表现更好 → 门控更偏向它们 → 它们被训练得更好 → 进一步被偏向。 结果:花 671B 显存,只用上约 37B 有效容量。解法:加负载均衡损失强制使用率均匀。 判据:看每个专家的使用次数分布,若少数专家占比极高即已坍缩。
图 3 左图每个专家都参与训练,容量不浪费;右图少数专家承担绝大多数 token,其余形同虚设。坍缩不是网络崩溃,而是容量被白白浪费——这是 MoE 训练里最该监控的指标。

四、专家怎么分布与并行

前面讲的是「单个 MoE 层里发生了什么」,这一节把镜头拉到整个集群——671B 的权重,物理上到底放在哪、怎么分工。这决定了一个 MoE 模型能不能上线、以及它为什么难本地化。

第一个事实:总参数太大,单卡根本装不下。 671B 参数按 fp16 算约 1.3 TB,远超单张 GPU 的显存(80GB 或更小)。所以专家必须被切开放到多张卡上——这就是专家并行(Expert Parallelism)(EP):不同专家住在不同设备,门控网络选出专家后,token 要被送到对应设备上算。

第二个事实:把专家分开,就引出了通信这个新代价。 一个 token 被选中的两个专家可能分布在两张不同的卡上,于是每层都要做一次 All-to-All 通信:把各卡的 token 按「目标专家」重新分发,算完再送回原卡。这张图就是这一节要讲的「分布 + 通信」:

专家并行:把专家摊到多张卡,换来 All-to-All GPU 0/1/2/3 各装一部分专家;一个 token 被选中的专家可能不在本卡 → 必须跨卡搬运 GPU 0 专家 0–63 GPU 1 专家 64–127 GPU 2 专家 128–191 GPU 3 专家 192–255 token 选到专家 88(GPU 1) 选到专家 200(GPU 3)→ 跨卡搬运 「专家并行」是一组取舍 并行度越高(专家分得越散)→ 单卡显存压力越小,但 All-to-All 通信越频繁、延迟越高。 稠密模型只需同层数据并行,没有这种跨设备点对点搬运——这是 MoE 难本地化的根因。 判据:小 batch 时每个专家分到的 token 极少,GPU 算力空转,通信固定开销照付 → 性价比缩水。
图 4 专家分散在多卡上,token 被选中的专家若不在本卡,就要跨卡搬运(All-to-All)。「专家并行度」就是在「显存压力」和「通信开销」之间拉的那根尺子——这也是 MoE 只适合云端大集群、难以下沉本地的物理原因。

由此引出三个可直接用于选型与面试的结论:

  • 专家并行度和通信开销成正比。 专家分得越散(并行度越高),单卡显存越省,但每层 All-to-All 的固定开销越高。部署时要在「显存装得下」和「通信扛得住」之间找平衡点,不是越高越好。
  • 这解释了「MoE 延迟不如吞吐」的深层原因。 单请求延迟被跨卡搬运拖累,但高并发下大量 token 可以「凑成一批」一起分发,通信被摊薄,吞吐反而高。所以 MoE 适合高并发、可批量的云端,不适合低并发、强延迟敏感的本地。
  • 「未激活的专家」不是可以卸载的。 有人会问:能不能把没选到的专家换出显存、省显存?答案是否定的——路由是运行时动态决定的,你无法预知下一个 token 会选谁;换入换出的代价远高于常驻。所以显存下限始终由总参数量决定,专家并行只是把这份「必须常驻」的总量分摊到多张卡,而不是削减它。

这一节补上了 MoE 成本结构的最后一块拼图:容量看总数、算力看激活、显存看总数、通信看并行度。记住这四句,MoE 相关的面试题基本都能兜住。

五、动手:三十行感受一次路由

moe_router.pypython
import numpy as np
def softmax(x, axis=-1):
    m = x.max(axis=axis, keepdims=True)
    e = np.exp(x - m)
    return e / e.sum(axis=axis, keepdims=True)
class MoELayer:
    def __init__(self, d_model=16, n_experts=8, top_k=2, seed=0):
        rng = np.random.default_rng(seed)
        self.top_k = top_k
        # 门控权重 [d_model, n_experts]
        self.Wg = rng.normal(size=(d_model, n_experts)) / np.sqrt(d_model)
        # 每个专家的权重 [n_experts, d_model, d_model]
        self.experts = rng.normal(size=(n_experts, d_model, d_model)) / np.sqrt(d_model)
    def forward(self, x):
        """x: [n_tokens, d_model]"""
        gates = softmax(x @ self.Wg)                  # [n, n_experts]
        idx = np.argsort(-gates, axis=1)[:, :self.top_k]   # [n, top_k]
        out = np.zeros_like(x)
        for t in range(x.shape[0]):
            acc = np.zeros(x.shape[1])
            w_sum = gates[t, idx[t]].sum()             # 重归一化,保证权重和为 1
            for e in idx[t]:
                acc += (gates[t, e] / w_sum) * (x[t] @ self.experts[e])
            out[t] = acc
        # 专家利用率统计 —— 这是训练稳定性的关键观察指标
        used, counts = np.unique(idx, return_counts=True)
        self.last_usage = dict(zip(used.tolist(), counts.tolist()))
        return out
layer = MoELayer()
x = np.random.default_rng(1).normal(size=(64, 16))
y = layer.forward(x)
print('输出形状:', y.shape)          # (64, 16),与输入一致
print('专家使用次数:', layer.last_usage)   # 观察是否集中在少数专家身上
实操任务
  • 把 n_experts 从 8 调到 64,观察 last_usage 的长尾分布——你会看到少数专家被反复选中,这就是「路由坍缩」;
  • 加上一个负载均衡项:统计每个专家的使用次数,对过度使用的专家施加惩罚,再跑一次;
  • 计算「激活参数量占比」:top_k / n_experts,并说明它与「每 token 算力」和「显存占用」分别是什么关系。

六、常见误区与追问

6.1 误区:MoE 因为只激活部分专家,所以显存也省了

错在哪:把「不计算」等同于「不占显存」。为什么自然:直觉上「没用到的东西就不用准备」,符合常识。正确做法:路由是运行时按输入动态决定的,你无法预知下一个 token 会走哪个专家,所以所有专家权重必须常驻显存。MoE 压的是每 token 的 FLOPs,不是权重的存储体积。判据:被问「未激活专家能不能卸载到磁盘省显存」时,答案是否定的——除非你能接受极慢的换入换出,否则显存下限仍由总参数量(671B)决定。

6.2 误区:拿总参数量去和稠密模型比成本

错在哪:用 671B 的总参数去断言「这个模型比 70B 稠密贵一个量级」。为什么自然:总参数确实大一个量级,直觉成立。正确做法:比单 token 成本要看激活参数量(37B),比容量/显存才看总参数(671B)。判据:比成本比激活,比容量比总参;一句话说清「这模型单 token 算力≈一个 37B 稠密,但显存门槛≈一个 671B 稠密」。混用两个口径必然得出相反结论。

6.3 误区:稀疏激活 ≈ 稀疏注意力

错在哪:把「稀疏」两个字当成同一种技术。为什么自然:中文都叫稀疏,容易并类。正确做法:MoE 的稀疏是参数/专家层面的稀疏激活(每个 token 只走少数专家),稀疏注意力是注意力矩阵层面的稀疏(只算部分位置对)。两者解决不同瓶颈、属于不同技术线,不能互相替代。判据:问「它改的是哪一步」——MoE 改的是 FFN/专家选择,稀疏注意力改的是 QKᵀ 的 [n,n] 计算。

6.4 误区:路由坍缩只是训练不稳,不影响上线

错在哪:认为坍缩只是训练期现象,推理时无所谓。为什么自然:推理时路由照常工作,输出看起来正常。正确做法:坍缩意味着少数专家承担了绝大多数 token,其余专家形同虚设——等于你付了 671B 显存,只用了约 37B 的有效容量。这是纯粹的成本浪费,且会让容量上限被悄悄锁死。判据:上线前统计各专家在真实流量上的使用次数分布;若基尼系数高(少数专家占比超 80%),说明已坍缩,需要回炉训练加负载均衡损失。

6.5 误区:MoE 延迟一定比同激活量稠密模型更低

错在哪:把「吞吐高」等同于「延迟低」。为什么自然:单位时间处理更多 token,听起来更快。正确做法:单请求延迟受 All-to-All 跨设备通信 拖累,往往比同激活量的稠密模型更慢;MoE 的优势在吞吐(高并发下单位成本更低),不在单请求延迟。判据:高并发、可批量 → 用 MoE 划算;低并发、强延迟敏感、要本地化 → 稠密模型反而更合适。

6.6 误区:每个专家是一个「领域专家」

错在哪:按字面把 expert 理解成「懂金融的专家」「懂代码的专家」。为什么自然:中文「专家」自带领域含义。正确做法:专家只是层内的一个前馈子网络,门控网络按 token 的表示动态选 top-k,并不按主题分工;同一个专家在不同 token 上可能扮演不同角色。判据:想验证,就看消融实验——打乱专家分配标签,模型表现基本不变,说明专家没有稳定的「主题身份」。

七、自测

本章自测第 1 题是高频陷阱题
Q1MoE 通过稀疏激活省下了什么?
C。路由是运行时决定的,无法预知下一个 token 会走哪个专家,所以全部权重必须常驻。MoE 解耦的是「容量」与「算力」,不是「容量」与「显存」。另外它完全不改变注意力的平方复杂度——那是另一条独立的技术路线(稀疏注意力 / 线性注意力)要解决的问题。
Q2为什么 MoE 模型在 batch 很小的时候性价比优势会缩水?
B。MoE 的效率来自「把大量 token 一次性分发到各专家,让每个专家都有活干」。batch 小的时候,每个专家分到的 token 可能只有一两个,算力利用率大幅下降,而 All-to-All 通信的固定开销不会等比例减少。这是「MoE 适合高吞吐、不适合低并发」的物理原因。
Q3路由坍缩(routing collapse)指的是什么现象?
D。训练早期若某些专家偶然表现更好,门控会更偏向它们,形成正反馈,最终少数专家承担绝大部分 token,其余专家形同虚设——等于花了 671B 的显存,只用了 37B 的有效容量。标准解法是加负载均衡损失(auxiliary load balancing loss)强制使用率均匀。

八、小结

你要能回答的问题一句话答案
MoE 省什么省每 token 的计算量(FLOPs),不省显存
MoE 贵在哪显存下限高、跨设备 All-to-All 通信、训练需要负载均衡
什么时候 MoE 划算高并发、高吞吐的云端推理场景
什么时候不划算低并发、强延迟敏感、本地化部署
专家并行(EP)是什么把专家摊到多张卡,用 All-to-All 通信换单卡显存——并行度越高,通信越贵
与 KV Cache 的关系完全独立:KV Cache 管的是历史复用,MoE 管的是参数复用

一句话记住成本结构:容量看总数、算力看激活、显存看总数、通信看并行度。

下一章换个更贴近日常的问题:既然输出是采样出来的,那「同一个问题问两次答案不同」到底该不该修,以及怎么修。

九、参考与延伸

本章机制部分只讲到「够用」为止。想往下深挖,下面按「先看图、再看代码、最后读论文」的顺序排好了。全站不做原文转载,这里只登记链接与「为什么值得读」。

先看图(建立直觉)

  • Switch Transformers(arXiv:2101.03961) —— 先只看它的 Figure 1:token → 门控 → top-k 专家 → 加权,MoE 层最经典的那张结构图就在这里。对着它再看本章第二节的图 1,「未选中的专家仍然占着显存、只是不参与计算」会立刻变具体;负载均衡损失与专家容量这两个概念也出自这篇,想深挖再读正文。

再看代码(动手实现)

最后读论文(对齐一手定义)

  • Mixtral of Experts(arXiv:2401.04088) —— 开源 MoE 模型的一手技术报告。重点看它怎么设置每 token 激活的专家数(top-k),以及稀疏激活比例怎么影响成本;本章「激活参数量只占总量一小部分」在它身上有具体数字。
  • DeepSeek-V3 Technical Report(arXiv:2412.19437) —— 本章那组「671B 总参 / 37B 激活」的数字就出自这里。它用的是 DeepSeekMoE + MLA,并提出 auxiliary-loss-free 的负载均衡策略——不加辅助损失也能压住坍缩。想知道工业界怎么在保住吞吐的前提下平衡专家负载,看它第 4 节。

◇ 面试官会怎么问

共 6 条 · 其中 2 条高频 · 先自己答一遍,再展开对照

为什么 MoE 的总参数量和激活参数量不是一回事? 高频
MoE 把前馈层(FFN)拆成很多个专家,每个 token 只被路由到其中 Top-K 个专家参与计算。于是:
总参数量是所有专家参数之和——决定模型需要
要多少显存/内存装下它;
激活参数量是单个 token 实际参与运算的那部分参数——决定算力开销。
所以一个总参数 671B 的模型,单 token 激活可能只有 37B 量级,算力像小模型,容量像大模型,这就是它便宜的原因。

追问链

  1. 那显存能不能按激活参数量来估?
  2. 路由不均(专家负载倾斜)会带来什么工程问题?
加分点:能说清"显存看总参数、算力看激活参数、通信看专家并行",这三句话就完整了。
MoE 和稠密模型分别适合什么场景?
这道题答错会直接扣分,因为它考察的是工程选型直觉。
MoE 适合:预算充足、追求单位算力下的质量、有大规模并发可以摊薄通信与调度开销、以及显存资源相对宽裕的服务端部署。
稠密模型适合:显存受限(端侧、单机小卡)、并发低且延迟敏感(MoE 的专家并行会引入额外通信延迟)、需要极简部署与稳定吞吐的场景。
换句话说:MoE 换来的是"用容量换质量",代价是显存占用、通信开销与调度复杂度。
加分点:主动提 MoE 的代价(通信、负载均衡、显存),而不是只夸它便宜。
MoE 的负载不均衡是什么问题?会怎么表现?
门控网络倾向于把 token 集中路由到少数"表现好"的专家,导致部分专家过载、部分闲置。表现是:训练时出现"专家坍缩"(大部分专家学不到东西),推理时吞吐被少数热专家的算力上限卡住,整体并行效率下降。
常规处理是加负载均衡损失(鼓励路由分布均匀)、设置专家容量上限与溢出丢弃策略、以及在工程侧做专家并行的重排布。对使用方的启示:同一个模型在不同任务分布下的实际吞吐可能差异很大,压测要用真实流量而不是随机文本。
客户要求「把 671B 的 MoE 模型部署到两台 80GB 的机器上」,你会怎么回应? 高频
先算账再回答。MoE 的显存下限由总参数量决定,不是激活参数量:671B 参数即使按 fp8 存放也要约 671GB 权重,两台 80GB 加起来只有 160GB,差一个数量级——装不下就是装不下,调小 top-k 也救不回来(路由是运行时决定的,无法预知下一个 token 走哪个专家)。
正确回应是给出可选项:
  • 换成激活量相近的稠密小模型;
  • 用能跑下的量化版 MoE,并明确精度风险;
  • 若一定要这份容量,接受多机多卡 + 专家并行带来的 All-to-All 通信开销,并说清延迟代价。
判据:容量看总参数,算力看激活参数,显存看总参数。

追问链

  1. 如果客户愿意把机器加到 16 台,还缺什么才能跑起来?
  2. 专家并行的 All-to-All 主要伤害吞吐还是延迟?
加分点:加分点:把「装不下」算成具体 GB 再给替代方案,而不是含糊地说「MoE 很吃显存」。
一个 256 专家、每 token top-8 的 MoE,把 top-8 改成 top-4,单 token 算力和显存下限各怎么变?
算力约减半(准确说是专家承担的那部分 FFN 计算量减半);显存下限完全不变。
因为这两件事由不同口径决定:激活参数占比从 8/256 ≈ 3.1% 变成 4/256 ≈ 1.6%,砍掉的是每 token 的 FLOPs;但路由是运行时才决定的,你无法预知下一个 token 会走哪几个专家,所以全部 256 个专家的权重必须常驻显存。
判据:被问「调 top-k 能省显存吗」,答案是不能;要省显存只能动总参数量或做量化。

追问链

  1. 那调小 top-k 会带来什么副作用?
  2. 如果只想省显存,有哪些可用手段?
加分点:加分点:说清「激活参数量是运行时量、总参数量是静态量」,这是这道题唯一的考点。
MoE 省的 FLOPs 和 KV Cache 省的重复计算会叠加吗?叠加之后瓶颈会挪到哪里?
会叠加,但省的不是同一样东西,所以叠加后瓶颈会转移。
KV Cache 省的是重复计算(同样的前缀不再重算),MoE 省的是单位 token 的参数量(不激活全部专家);两者降低的都是「算多少」。但 MoE 同时引入两个新成本:显存下限由总参数量决定,以及跨设备搬运 token 的 All-to-All 通信。
于是高并发场景下,瓶颈常常从算力挪到显存容量与通信带宽;反过来,小 batch 时专家利用率低,MoE 的性价比优势会缩水甚至变成负担。
判据:把两项优化叠在一起之前,先确认新的瓶颈不是显存或通信。

追问链

  1. 多大的 batch 规模下,MoE 才开始划算?
  2. 如果 MoE 只在云端划算,本地化部署该怎么选型?
加分点:加分点:主动说出「被优化掉的那个瓶颈不再是瓶颈,代价会从另一个地方冒出来」——这是有实战判断的标志。
答这类题的通用结构

结论先行(一句话给出取舍)→ 机制(为什么是这样,涉及哪条链路)→ 代价或边界(这么做放弃了什么)→ 你的实践或数字(真实场景里怎么落地)。 只讲机制不讲代价,是背题;只讲取舍没有数字,是空谈。

本章收尾 · Wrap up
掌握度自评
点一下给自己打分;低于 3 分建议加入复习队列
个人笔记 · Notes
    下一章 采样、温度与确定性 同一个问题问两次得到不同答案,这不是 bug,是解码策略的必然结果。但在 Agent 里,不确定性会直接变成"工具参数写错了"。这一章讲清每个采样参数到底在动什么。 I · 大模型原理 · 第 04 章 · 入门 · 约 20 分钟