【AI面试八股文 Vol.3.3:MoE 架构】从 Dense 到专家路由:为什么 DeepSeek 的 MoE 能把推理成本打下来

15 阅读50分钟

封面图

摘要:围绕 MoE、Dense、Expert routing、Top-K Expert、Router、DeepSeek V2 讲清 MoE 的核心矛盾:总参数变大但激活参数受控,Router 决定 Expert 路径,工程收益体现在推理成本、吞吐和模型服务选型,而不是一句“专家混合”就结束。

【AI面试八股文 Vol.3.3:MoE 架构】从 Dense 到专家路由:为什么 DeepSeek 的 MoE 能把推理成本打下来

这篇目标约 10000 字,围绕 MoE、Dense、Expert routing、Top-K Expert、Router、DeepSeek V2 讲清 MoE 的核心矛盾:总参数变大但激活参数受控,Router 决定 Expert 路径,工程收益体现在推理成本、吞吐和模型服务选型,而不是一句“专家混合”就结束。

这道题到底在考什么:MoE 是能力扩展还是成本优化

很多人第一次接触 MoE(Mixture of Experts,混合专家)的时候,最容易掉进的一个坑是:把 MoE 等同于“参数多”。这个直觉不能说完全错,但它只描述了现象的皮毛,没抓到 MoE 在工程层面真正想解决的问题。

三组容易被混淆的概念

在展开 MoE 架构之前,我们需要先理清楚三组在面试中频繁出现、但极易混淆的概念:总参数量(Total Parameters)、激活参数量(Active Parameters)和推理成本(Inference Cost)。

总参数量 指的是模型在磁盘上存储的所有权重参数之和。以 DeepSeek-V2 为例,它的总参数量约为 2360 亿(236B),这个数字决定了模型文件的体积(大约 470GB 的 FP16 权重),也决定了训练时梯度需要更新的规模。总参数量大,意味着模型有更多的知识存储空间,可以容纳更多的世界知识和技能组合,但这本身不等于推理快。

激活参数量 指的是在一次前向传播中实际参与计算的那些权重参数。Dense 模型(稠密模型)的激活参数量等于总参数量——每层每个参数都会被调用。但 MoE 模型通过专家路由机制,只激活部分专家网络的参数。以 DeepSeek-V2 为例,它有 128 个专家节点,但每次前向只激活 8 个,激活参数量约为 210 亿(21B)。这意味着虽然模型“记住”了 236B 参数的知识,但在做推理的时候,消耗的计算资源和存储带宽只相当于一个 21B 的 Dense 模型。

推理成本 是一个更宽泛的概念,它不只是算力的函数,还受显存带宽、KV Cache 规模、批处理吞吐量、设备间通信开销等因素影响。在实际生产环境中,推理成本通常用“每 token 的平均计算量”和“每秒能处理的 token 数(Throughput)”来衡量。MoE 的核心工程价值,恰恰体现在:总参数量可以很大(容纳更多知识),但激活参数量保持可控(推理成本低)。

面试中一个经典的陷阱题是这样出的:

“MoE 模型的总参数是 1000 亿,那它的推理成本是不是比 100 亿的 Dense 模型贵 10 倍?”

标准答案是:不一定。如果 MoE 模型的激活参数也是 100 亿级别(比如说 8 个专家 × 12.5B/专家 = 100B),那么在激活参数的计算量上,两者是相当的。贵出来的部分主要是:

  1. 多专家网络的显存占用:128 个专家的权重需要全部加载到显存中,即使每次只用到 8 个,显存容量需求仍然是 128 个专家的总量。 2. 路由计算的开销:Router 网络需要额外的矩阵运算来决定 token 走哪个专家,这部分开销在传统 Dense 模型中不存在。 3. 通信开销(分布式场景):如果专家分布在不同的计算设备上,跨设备的数据传输会带来延迟。

但这些额外开销,相比于把模型总参数从 100B 扩大到 1000B 所带来的知识容量提升,收益往往是划算的。这也是 DeepSeek 选择 MoE 架构的核心工程逻辑。

另一个高频混淆点是:很多人以为 MoE 是 2017 年 Transformer 之后才出现的新技术。实际上,MoE 的概念最早可以追溯到 1991 年 Jordan 和 Jacobs 的混合专家模型 [^1],是一种经典的机器学习范式。2017 年 Shazeer 等人将 MoE 思想引入循环神经网络 [^2],2020 年 Lepikhin 等人在 TPU 集群上实现了大规模 MoE Transformer(Google Switch Transformer)[^3],2023 年 Mixtral 8×7B 的发布让 MoE 在 LLM 领域真正火了起来 [^4]。DeepSeek-V2/V3 在此基础上做了大量架构创新,包括 MLA(Multi-head Latent Attention)和 DeepSeekMoE 本身,成为 2024 年最受关注的 MoE 实现之一。

推理成本不只是参数量

在面试中,面试官真正想考察的往往不是你知道几个概念,而是你对推理系统的全貌有认知。当一个候选人能把“参数量”和“推理成本”分开讨论,并且能说出它们之间的关系和例外情况,这本身就是加分项。

举一个具体的数字对比(数据基于公开论文和社区基准 [^5]):

模型总参数量激活参数量相对推理成本
DeepSeek-V2 (MoE)236B~21B1×(基准)
DeepSeek-V2 (Dense 等效)21B21B
LLaMA 2 70B (Dense)70B70B~3.3×
GPT-4 (推测 MoE)~1.8T~200B~10×

从这个表格可以看出,DeepSeek-V2 的激活参数量约为 21B,与一个 21B 的 Dense 模型推理成本相当,但它的总参数量是 236B——是激活参数的 11 倍。这意味着 DeepSeek-V2 用相当于 21B 模型的推理成本,获得了接近 236B 模型的知识容量和任务表现。

但推理成本的构成远比这张表格复杂。在实际服务场景中,以下因素会显著影响单位 token 的推理成本:

显存带宽瓶颈(Memory Bandwidth Bottleneck):当 GPU 的算力(TFLOPS)远高于显存带宽时,模型的瓶颈不在计算,而在把数据从显存读到计算单元。对于大模型推理,KV Cache 的访存开销往往是主要瓶颈。MoE 模型由于激活参数少,单次前向的 KV Cache 访问量也相应减少,这在长上下文场景下优势更明显。

批处理吞吐量(Batch Throughput):在做并发推理时,GPU 的算力可以被多个请求共享。MoE 模型由于激活参数量固定,增加专家数量不会线性增加每次推理的计算量,因此在高并发场景下,吞吐量提升接近专家数量的倍数(假设路由均衡)。

量化压缩收益:MoE 模型的专家权重可以更激进地量化,因为不同专家负责不同类型的知识,量化误差的分布更加分散。以 DeepSeek-V2 为例,其 236B 模型可以量化到 INT4 存储,推理时再解压,显存占用大幅降低,而同级别的 Dense 模型量化后质量损失更明显。

理解了这些,你再回头看 DeepSeek 为什么在 V2 和 V3 中强调 MoE 架构,就不是一句“追赶 GPT-4”能概括的了——它是 DeepSeek 在有限算力预算下,做出能力最强模型的结构性选择。


Dense vs MoE:参数如何参与计算

如果说第一章帮你建立了概念分层的认知框架,第二章我们要深入到计算图(Computation Graph)层面,看看 Dense 模型和 MoE 模型在前向传播中,参数到底是“全员出动”还是“按需上岗”。

Dense Transformer 的前向传播

标准的 Transformer 架构中,每个 token 在经过每一层 Self-Attention 和 FFN(前馈网络)时,所有参数都会被激活。以一个 70B 参数的 Dense 模型为例:

  1. Self-Attention 部分:假设隐藏维度 dmodel = 8192,注意力头数 h = 80,每个头的维度 dk = dv = 128。Q、K、V 的投影矩阵各为 [8192,8192][8192, 8192],输出投影矩阵为 [8192,8192][8192, 8192],加上位置编码投影,总参数量约 4 × 81922 approx 268M。

  2. FFN 部分:经典 FFN 通常是两层线性层,维度展开为 dmodel to dff to dmodel。以 SwiGLU 为例,维度通常是 81922867281928192 \to 28672 \to 8192,这一层的参数量约为 4 × dmodel × dff,约 2.3B。

  3. LayerNorm 和残差连接:参数量相对较小,忽略不计。

对于 70B 模型,每一层的 FFN 参数量约占该层总参数量的 70-80%。当一个 token 流经第 LL 层时,FFN 层所有 dffd_{ff} 的参数都需要参与矩阵乘法,这就是 Dense 模型“每层全激活”的含义。

数学上,一次前向传播中,token 经过 FFN 的计算可以表示为:

textFFN(x) = W2 · σ(W1 · x)

其中 W1 in mathbbRdmodel × dff,W2 in mathbbRdff × dmodel,每个 token 都会触发这两个矩阵乘法的完整计算。当上下文长度为 NN 时,计算量为 O(Ndmodeldff)O(N \cdot d_{model} \cdot d_{ff}),与序列长度线性增长。

MoE Transformer 的前向传播

MoE 模型的核心改动发生在 FFN 层。传统的 FFN 被替换为 MoE FFN,包含两个关键组件:一组并行的专家网络(Experts)一个路由模块(Router)

以 DeepSeekMoE 为例,假设有 E<svgclass="mathformulamathformulainline"xmlns="http://www.w3.org/2000/svg"width="315"height="32"viewBox="0031532"role="img"arialabel="个专家(DeepSeekV2"datarenderer="textosvg"><rectx="0"y="0"width="100E<svg class="math-formula math-formula--inline" xmlns="http://www.w3.org/2000/svg" width="315" height="32" viewBox="0 0 315 32" role="img" aria-label="个专家(DeepSeek-V2 中" data-renderer="tex-to-svg"><rect x="0" y="0" width="100%" height="100%" rx="10" fill="#f6faff"/><text fill="#1f3f75" font-size="18" font-family="Menlo,Consolas,Monaco,monospace"><tspan x="18.0" y="22" font-size="18">个</tspan><tspan x="29.2" y="22" font-size="18">专</tspan><tspan x="40.3" y="22" font-size="18">家</tspan><tspan x="51.5" y="22" font-size="18">(</tspan><tspan x="62.6" y="22" font-size="18">D</tspan><tspan x="73.8" y="22" font-size="18">e</tspan><tspan x="85.0" y="22" font-size="18">e</tspan><tspan x="96.1" y="22" font-size="18">p</tspan><tspan x="107.3" y="22" font-size="18">S</tspan><tspan x="118.4" y="22" font-size="18">e</tspan><tspan x="129.6" y="22" font-size="18">e</tspan><tspan x="140.8" y="22" font-size="18">k</tspan><tspan x="151.9" y="22" font-size="18">-</tspan><tspan x="163.1" y="22" font-size="18">V</tspan><tspan x="174.2" y="22" font-size="18">2</tspan><tspan x="185.4" y="22" font-size="18"> </tspan><tspan x="196.6" y="22" font-size="18">中</tspan></text></svg>E = 128),每个专家 ii 都有自己的 FFN 参数 W1(i)W_1^{(i)}W2(i)W_2^{(i)}。对于输入 token xx,路由模块首先计算它应该被分配给哪些专家:

textTopK = textTopK(textSoftmax(Wr · x))

其中 Wr 是路由器的可学习参数矩阵,输出维度为 EE(专家总数)。TopK 操作选择得分最高的 K<svgclass="mathformulamathformulainline"xmlns="http://www.w3.org/2000/svg"width="315"height="32"viewBox="0031532"role="img"arialabel="个专家(DeepSeekV2"datarenderer="textosvg"><rectx="0"y="0"width="100K<svg class="math-formula math-formula--inline" xmlns="http://www.w3.org/2000/svg" width="315" height="32" viewBox="0 0 315 32" role="img" aria-label="个专家(DeepSeek-V2 中" data-renderer="tex-to-svg"><rect x="0" y="0" width="100%" height="100%" rx="10" fill="#f6faff"/><text fill="#1f3f75" font-size="18" font-family="Menlo,Consolas,Monaco,monospace"><tspan x="18.0" y="22" font-size="18">个</tspan><tspan x="29.2" y="22" font-size="18">专</tspan><tspan x="40.3" y="22" font-size="18">家</tspan><tspan x="51.5" y="22" font-size="18">(</tspan><tspan x="62.6" y="22" font-size="18">D</tspan><tspan x="73.8" y="22" font-size="18">e</tspan><tspan x="85.0" y="22" font-size="18">e</tspan><tspan x="96.1" y="22" font-size="18">p</tspan><tspan x="107.3" y="22" font-size="18">S</tspan><tspan x="118.4" y="22" font-size="18">e</tspan><tspan x="129.6" y="22" font-size="18">e</tspan><tspan x="140.8" y="22" font-size="18">k</tspan><tspan x="151.9" y="22" font-size="18">-</tspan><tspan x="163.1" y="22" font-size="18">V</tspan><tspan x="174.2" y="22" font-size="18">2</tspan><tspan x="185.4" y="22" font-size="18"> </tspan><tspan x="196.6" y="22" font-size="18">中</tspan></text></svg>K = 8),然后只有这 KK 个专家的 FFN 会被激活。

最终 MoE FFN 的输出为:

textMoE-FFN(x) = sumi in textTopK(x) textFFNi(x) · textWeighti

这里 textWeighti 是专家 ii 的加权系数,通常是 Router 输出的概率值(归一化后)。

关键点:当 K = 1 时,MoE FFN 退化为一个标准 FFN(只是 Router 决定用哪个专家的“子网络”);当 K = E 时,MoE FFN 激活所有专家,等价于 Dense 模型但计算量暴增。通常 KK 设置为远小于 EE 的值(如 1-16 之间),以保持激活参数的可控性。

参数利用率与计算效率的对比

用一个具体例子来说明 Dense 和 MoE 的计算差异。假设我们有一个 DeepSeek-V2 规模的模型:

  • 总参数量:236B - 专家数量 E<svgclass="mathformulamathformulainline"xmlns="http://www.w3.org/2000/svg"width="330"height="32"viewBox="0033032"role="img"arialabel="128每次激活专家数"datarenderer="textosvg"><rectx="0"y="0"width="100E<svg class="math-formula math-formula--inline" xmlns="http://www.w3.org/2000/svg" width="330" height="32" viewBox="0 0 330 32" role="img" aria-label="**:128 - **每次激活专家数" data-renderer="tex-to-svg"><rect x="0" y="0" width="100%" height="100%" rx="10" fill="#f6faff"/><text fill="#1f3f75" font-size="18" font-family="Menlo,Consolas,Monaco,monospace"><tspan x="18.0" y="22" font-size="18">*</tspan><tspan x="29.2" y="22" font-size="18">*</tspan><tspan x="40.3" y="22" font-size="18">:</tspan><tspan x="51.5" y="22" font-size="18">1</tspan><tspan x="62.6" y="22" font-size="18">2</tspan><tspan x="73.8" y="22" font-size="18">8</tspan><tspan x="85.0" y="22" font-size="18"> </tspan><tspan x="96.1" y="22" font-size="18">-</tspan><tspan x="107.3" y="22" font-size="18"> </tspan><tspan x="118.4" y="22" font-size="18">*</tspan><tspan x="129.6" y="22" font-size="18">*</tspan><tspan x="140.8" y="22" font-size="18">每</tspan><tspan x="151.9" y="22" font-size="18">次</tspan><tspan x="163.1" y="22" font-size="18">激</tspan><tspan x="174.2" y="22" font-size="18">活</tspan><tspan x="185.4" y="22" font-size="18">专</tspan><tspan x="196.6" y="22" font-size="18">家</tspan><tspan x="207.7" y="22" font-size="18">数</tspan></text></svg>K<svg class="math-formula math-formula--inline" xmlns="http://www.w3.org/2000/svg" width="260" height="32" viewBox="0 0 260 32" role="img" aria-label="**:8 - **隐藏维度" data-renderer="tex-to-svg"><rect x="0" y="0" width="100%" height="100%" rx="10" fill="#f6faff"/><text fill="#1f3f75" font-size="18" font-family="Menlo,Consolas,Monaco,monospace"><tspan x="18.0" y="22" font-size="18">*</tspan><tspan x="29.2" y="22" font-size="18">*</tspan><tspan x="40.3" y="22" font-size="18">:</tspan><tspan x="51.5" y="22" font-size="18">8</tspan><tspan x="62.6" y="22" font-size="18"> </tspan><tspan x="73.8" y="22" font-size="18">-</tspan><tspan x="85.0" y="22" font-size="18"> </tspan><tspan x="96.1" y="22" font-size="18">*</tspan><tspan x="107.3" y="22" font-size="18">*</tspan><tspan x="118.4" y="22" font-size="18">隐</tspan><tspan x="129.6" y="22" font-size="18">藏</tspan><tspan x="140.8" y="22" font-size="18">维</tspan><tspan x="151.9" y="22" font-size="18">度</tspan></text></svg>d_{model}<svg class="math-formula math-formula--inline" xmlns="http://www.w3.org/2000/svg" width="360" height="32" viewBox="0 0 360 32" role="img" aria-label="**:7168 - **FFN 扩展维度" data-renderer="tex-to-svg"><rect x="0" y="0" width="100%" height="100%" rx="10" fill="#f6faff"/><text fill="#1f3f75" font-size="18" font-family="Menlo,Consolas,Monaco,monospace"><tspan x="18.0" y="22" font-size="18">*</tspan><tspan x="29.2" y="22" font-size="18">*</tspan><tspan x="40.3" y="22" font-size="18">:</tspan><tspan x="51.5" y="22" font-size="18">7</tspan><tspan x="62.6" y="22" font-size="18">1</tspan><tspan x="73.8" y="22" font-size="18">6</tspan><tspan x="85.0" y="22" font-size="18">8</tspan><tspan x="96.1" y="22" font-size="18"> </tspan><tspan x="107.3" y="22" font-size="18">-</tspan><tspan x="118.4" y="22" font-size="18"> </tspan><tspan x="129.6" y="22" font-size="18">*</tspan><tspan x="140.8" y="22" font-size="18">*</tspan><tspan x="151.9" y="22" font-size="18">F</tspan><tspan x="163.1" y="22" font-size="18">F</tspan><tspan x="174.2" y="22" font-size="18">N</tspan><tspan x="185.4" y="22" font-size="18"> </tspan><tspan x="196.6" y="22" font-size="18">扩</tspan><tspan x="207.7" y="22" font-size="18">展</tspan><tspan x="218.9" y="22" font-size="18">维</tspan><tspan x="230.0" y="22" font-size="18">度</tspan></text></svg>d_{ff}:约 18432(4×hidden)

如果用 Dense 方式计算,每层 FFN 的计算量(FLOPs)为:

textFLOPsDense = 2 × dmodel × dff × textsequence_length

对于 DeepSeek-V2,如果激活 FFN 参数量约 21B(对应 128 层中的每层 FFN 的一部分),Dense 方式的计算量将对应约 168B 参数参与每层计算。

在 MoE 方式下,每层只有 K = 8 个专家被激活,假设每个专家的参数量与标准 FFN 相当,则每层的激活参数量约为:

textActive_ParamsMoE = fracKE × textTotal_FFN_Params = frac8128 × textTotal_FFN_Params = frac116 × textTotal_FFN_Params

这就是 MoE 能够将激活参数量降低到 1/16 左右的数学依据。

实际工程收益(基于 DeepSeek-V2 公开技术报告 [^6]):

指标DeepSeek-V2 MoEDense 等效(21B)提升倍数
激活参数量~21B21B
每 token 推理 FLOPs~42T FLOPs~42T FLOPs
KV Cache 需求较低(MLA 优化)较高~50% 降低
吞吐(batch=1)~2-3×
吞吐(batch=64)极高~5-8×

注意,这里的“推理 FLOPs 相近”不是说 MoE 没有节省算力,而是 DeepSeek-V2 的 21B 激活参数量是相对于 DeepSeek 自身架构设计的,其他厂商的 21B Dense 模型可能参数量相当但架构效率不同。

为什么不是把所有 FFN 都换成 MoE

你可能会问:既然 MoE FFN 这么高效,为什么不把所有 FFN 层都换成 MoE?这里涉及一个工程上的权衡:路由开销和负载均衡问题

每增加一个专家,Router 需要额外学习“什么时候用哪个专家”,这本身就是一种知识压缩。如果专家数量过多(如 Switch Transformer 的 2048 或 8192 个),会导致以下问题:

  1. 路由崩溃(Router Collapse):模型倾向于始终选择同一个或少数几个专家,而不是均匀分配到所有专家,导致大部分专家沦为“摆设”。 2. 训练不稳定:Router 的梯度信号可能在早期就陷入局部最优,使得某些专家永远不被激活。 3. 通信开销:在多设备分布式部署中,如果专家分布在不同 GPU,频繁的跨设备路由会带来巨大的通信延迟和带宽消耗。

DeepSeek-V2 采用了 128 个专家 + Top-8 激活的配置,这是一个经过大量实验验证的折中点:既保持了足够大的知识容量(128 个专家可以存储不同领域、不同语言的专有知识),又避免了路由开销过大。后续的 DeepSeek-V3 进一步优化了专家共享和细粒度专家划分策略 [^7]。

理解了 Dense 和 MoE 在参数参与方式上的根本差异,下一章我们将深入 Router 的内部机制,看看它是如何做出“走哪个专家”的决策的。

Top-K Expert 路由:Router 如何决定走哪个 Expert

Router 本质:轻量级 token 级分类器

Router 在 MoE 架构中扮演交通枢纽的角色,其核心职责是为每个 token 动态决定应该路由到哪一个或哪几个 Expert。理解 Router 的第一步是认清它的数学本质:Router 本质上是一个轻量级的 token 级分类器。

具体实现上,假设当前层有 N 个 Expert,记为 E1, E2, ..., EN,每个 Expert 对应一个前馈网络(通常是两层全连接网络,遵循 FFN 的“扩展-压缩”结构)。对于输入 token x<svgclass="mathformulamathformulainline"xmlns="http://www.w3.org/2000/svg"width="630"height="32"viewBox="0063032"role="img"arialabel="(在Attention计算后的隐状态),Router首先通过一个线性层"datarenderer="textosvg"><rectx="0"y="0"width="100x<svg class="math-formula math-formula--inline" xmlns="http://www.w3.org/2000/svg" width="630" height="32" viewBox="0 0 630 32" role="img" aria-label="(在 Attention 计算后的隐状态),Router 首先通过一个线性层" data-renderer="tex-to-svg"><rect x="0" y="0" width="100%" height="100%" rx="10" fill="#f6faff"/><text fill="#1f3f75" font-size="18" font-family="Menlo,Consolas,Monaco,monospace"><tspan x="18.0" y="22" font-size="18">(</tspan><tspan x="29.2" y="22" font-size="18">在</tspan><tspan x="40.3" y="22" font-size="18"> </tspan><tspan x="51.5" y="22" font-size="18">A</tspan><tspan x="62.6" y="22" font-size="18">t</tspan><tspan x="73.8" y="22" font-size="18">t</tspan><tspan x="85.0" y="22" font-size="18">e</tspan><tspan x="96.1" y="22" font-size="18">n</tspan><tspan x="107.3" y="22" font-size="18">t</tspan><tspan x="118.4" y="22" font-size="18">i</tspan><tspan x="129.6" y="22" font-size="18">o</tspan><tspan x="140.8" y="22" font-size="18">n</tspan><tspan x="151.9" y="22" font-size="18"> </tspan><tspan x="163.1" y="22" font-size="18">计</tspan><tspan x="174.2" y="22" font-size="18">算</tspan><tspan x="185.4" y="22" font-size="18">后</tspan><tspan x="196.6" y="22" font-size="18">的</tspan><tspan x="207.7" y="22" font-size="18">隐</tspan><tspan x="218.9" y="22" font-size="18">状</tspan><tspan x="230.0" y="22" font-size="18">态</tspan><tspan x="241.2" y="22" font-size="18">)</tspan><tspan x="252.4" y="22" font-size="18">,</tspan><tspan x="263.5" y="22" font-size="18">R</tspan><tspan x="274.7" y="22" font-size="18">o</tspan><tspan x="285.8" y="22" font-size="18">u</tspan><tspan x="297.0" y="22" font-size="18">t</tspan><tspan x="308.2" y="22" font-size="18">e</tspan><tspan x="319.3" y="22" font-size="18">r</tspan><tspan x="330.5" y="22" font-size="18"> </tspan><tspan x="341.6" y="22" font-size="18">首</tspan><tspan x="352.8" y="22" font-size="18">先</tspan><tspan x="364.0" y="22" font-size="18">通</tspan><tspan x="375.1" y="22" font-size="18">过</tspan><tspan x="386.3" y="22" font-size="18">一</tspan><tspan x="397.4" y="22" font-size="18">个</tspan><tspan x="408.6" y="22" font-size="18">线</tspan><tspan x="419.8" y="22" font-size="18">性</tspan><tspan x="430.9" y="22" font-size="18">层</tspan></text></svg>W_r 计算原始分数:

z = Wr · x + br

这里的 Wr 是一个 dmodel × N 的矩阵,zz 是一个长度为 N 的一维向量,表示 Router 对该 token 分配给每个 Expert 的原始偏好程度。随后,对 zz 取 softmax 得到归一化的路由概率:

pi = fracexp(zi)sumj=1N exp(zj)

值得注意的是,这个 Router 线性层在参数规模上相比 FFN 层是极其轻量的。以 DeepSeek V2 为例,其每个 Router 层的参数量仅为隐状态维度的 N 倍,而一个 FFN Expert 的参数量则是隐状态维度乘以中间维度(通常是 4倍隐状态维度)。这意味着 Router 的计算开销和存储开销在整个 MoE 层中几乎可以忽略不计,路由决策的成本远低于 Expert 本身的计算成本。

在面试中,经常有候选人混淆 Router 与 Attention 的 Query-Key 计算,需要明确指出:Router 的线性层和 Attention 中的 WQ, WK 是两个完全独立的参数矩阵,前者用于 Expert 选择,后者用于 token 间信息交互,两者在计算图中是并行关系,最终的输出是各 Expert 输出的加权和(根据 Router 给出的概率或 Top-K 掩码)。

Top-K 选择:从软混合到硬稀疏

Router 给出概率分布后,下一步是决定如何激活 Expert。这里存在两种范式:软混合(Soft Mixture)和硬稀疏(Hard Sparse,Top-K)。

软混合是最直觉的做法:让每个 Expert 都参与计算,然后按照 Router 给出的概率分布进行加权求和。这种方式的输出公式为:

y = sumi=1N pi · Ei(x)

软混合的优点是梯度计算连续且稳定,每个 Expert 都能接收到来自最终 loss 的梯度信号。但致命的问题在于:软混合要求所有 N 个 Expert 都必须完成前向计算,这完全违背了 MoE“稀疏激活”的初衷——当 N 很大时(如 64 个或 128 个 Expert),计算量与一个 Dense 模型相差无几,稀疏性的收益几乎为零。

Top-K 硬稀疏是目前工业界和学术界的主流选择。其核心思路是:对于每个 token,Router 只选择概率最高的 K 个 Expert,其余 Expert 完全不参与计算。具体操作流程为:首先从 Router 的概率分布中取出 Top-K 的索引,然后只对这些 Expert 执行前向计算,最后将各 Expert 的输出按其对应的 Router 概率值加权求和(有时会用更激进的“硬门控”:直接将未选中 Expert 的权重置零,用 1/K 或原始 pi 归一化后的值作为权重)。

为什么选择 Top-K 而不是 Top-1?Top-K 引入了有限的多样性:单个 token 可以同时获得多个 Expert 的专长,模型在处理复杂语义时不会因为单一 Expert 的能力上限而受限。同时,K 通常取一个较小的值(如 K=1 或 K=2),这保证了稀疏性——对于 N=8 的配置,K=2 意味着只有 25% 的 Expert 被激活,推理时的计算量相比全激活减少 75%。

需要强调的是,Top-K 的选择过程本身是一个离散的 argmax 操作,这在反向传播中是不可导的。工程实践中通常采用两种策略规避这个问题:第一种是在训练时使用软松弛(soft relaxation),通过 Gumbel-Softmax 或Straight-Through Estimator(STE)使 Top-K 选择过程可导;第二种是在推理时可以完全切换为硬选择(hard routing),因为推理阶段不需要梯度。面试官可能会追问这两种策略的区别,候选人应能解释 STE 的核心思想:用前向时的硬选择结果作为反向时的梯度代理,即 fracpartial Lpartial x approx fracpartial Lpartial haty,其中 y^\hat{y} 是硬选择后的输出。

主流实现对比:GShard / Switch Transformer / Mixtral

理解了 Router 和 Top-K 的基础原理后,有必要通过对比主流实现方案来把握工程实践中的设计权衡。以下按时间线梳理三个代表性工作:

**GShard(2020)**是 Google 在 MoE 规模化方向的重要尝试,其核心创新是在机器学习模型并行框架中引入了 MoE 层的概念。GShard 的 Router 采用了 Top-2 策略,但有一个关键约束:同一个 token 不能被路由到同一个 Expert 两次(no-repeat 约束)。此外,GShard 首次在工业级大规模分布式训练中验证了 MoE 层的可行性,但其 Router 实现相对简单,缺乏显式的负载均衡机制。在面试中,GShard 的意义在于它是“大规模分布式 MoE”的先驱,证明了 MoE 可以在保留 Transformer 核心架构的同时显著扩展模型容量。

**Switch Transformer(2021)**是 Google 在 GShard 基础上的进一步优化,其最显著的特点是将 Router 简化为 Top-1 选择。Switch Transformer 的核心假设是:一个足够强大的 Expert 应该能够独立处理大多数任务,而 Top-1 路由可以最大化该 Expert 的训练样本量,从而让每个 Expert 更快地收敛到专精状态。然而,Top-1 路由也带来了更严重的负载均衡问题——某些 Expert 可能收到远超平均水平的流量,而另一些 Expert 则几乎闲置。为解决这个问题,Switch Transformer 引入了辅助负载均衡损失(Auxiliary Load Balancing Loss),这成为后续几乎所有 MoE 实现的标配组件。

**Mixtral 8x7B(2023)**是 Mistral AI 发布的开源 MoE 模型,也是第一个在开源社区产生重大影响的 MoE 大语言模型。Mixtral 的配置是 8 个 Expert,Top-K=2,即每个 token 从 8 个 Expert 中选择 2 个参与计算。从架构角度看,Mixtral 相对简洁:每个 Expert 是独立的 FFN 层,Router 是一个简单的线性层+softmax+Top-2 选择,没有引入复杂的辅助损失设计。Mixtral 的意义在于它证明了 MoE 可以用相对简单的设计实现接近 Dense 模型质量的能力,同时在推理时只激活 25% 的 FFN 参数量。在 DeepSeek V2 出现之前,Mixtral 8x7B 是最被广泛讨论和复现的 MoE 开源基座。

实现方案Expert 数量Top-K负载均衡机制特点
GShard多个(可扩展)Top-2隐式(分布式容错)分布式训练框架集成
Switch Transformer可扩展Top-1显式辅助损失最大化 Expert 专精
Mixtral 8x7B8Top-2未显式使用开源社区影响力最大

负载均衡:为什么 Router 需要辅助目标

负载均衡是 MoE 训练中最核心的工程问题之一,也是面试中被高频追问的知识点。其核心矛盾在于:如果任由 Router 自主学习,很可能会出现“赢者通吃”(winner-takes-all)现象——少数 Expert 因为更早被激活、接收到更多梯度更新而变得更强,进而吸引更多 token 路由到它们,形成正反馈循环。最终结果是一个或少数几个 Expert 承担了绝大部分的计算负载,而其余 Expert 几乎没有被训练,成为“摆设”。

在推理时,这种负载不均衡会导致严重的资源浪费:即使模型理论上拥有 N 个 Expert 的容量,但由于只有少数 Expert 实际参与计算,模型的真实能力上限被大幅压缩。更糟糕的是,被频繁激活的 Expert 会在部署时产生计算热点(compute hotspot),成为推理服务的瓶颈,而闲置的 Expert 则浪费了显存和计算资源。

为解决这个问题,MoE 训练中普遍引入辅助负载均衡损失。其设计思想是:为 Router 施加一个正则化约束,迫使其在 Expert 之间更均匀地分配流量。形式化地,假设当前 batch 中有 B 个 token,Router 对第 i 个 Expert 的路由概率均值为 barPi = frac1B sumb=1B pb,i,那么辅助损失可以定义为:

Lload = α · N · sumi=1N barPi · barfi

其中 barfi 是第 i 个 Expert 实际接收到的 token 比例(可以通过软统计或硬统计获得),α 是超参数用于平衡主损失与辅助损失。这个形式的本质是鼓励 Router 概率分布的均值 Pˉ\bar{P} 与 Expert 实际负载分布 fˉ\bar{f} 尽可能一致。当两者完全一致时(理想均衡状态),barPi = barfi = 1/N,辅助损失达到最小值。

为什么这个辅助损失是必要的?因为原始的 Router 训练目标(最小化主任务 loss)只关心 Expert 的输出质量,不关心 Expert 之间的流量分配。Router 通过学习可能发现“让 Expert 1 处理所有简单样本,让 Expert 2-8 处理复杂样本”是一个有效的策略(这正是赢者通吃的来源),主任务的 loss 仍然会下降,但负载均衡的维度被完全忽略了。辅助损失正是填补了这个空缺——它告诉 Router:“不仅要保证质量,还要让每个 Expert 都有足够的训练样本。”

训练稳定性:Expert 塌缩与梯度问题

理解了负载均衡的必要性后,还需要进一步探讨它带来的训练稳定性挑战。Expert 塌缩(Expert Collapse)和梯度问题是两个最常被问到的子问题。

Expert 塌缩是指在训练过程中,部分 Expert 逐渐失去表达能力,最终沦为几乎恒定输出的“死节点”。这种塌缩通常发生在辅助负载均衡损失过强的情况下:当 α 设置得太大时,Router 被强制将流量分散到所有 Expert,但某些 Expert 可能初始表达能力较弱,或者收到的样本本身就不足以让它学习到有效的表示。在这种情况下,Router 的概率分布被强制“拉平”,但 Expert 本身并没有获得足够的梯度更新来提升质量。结果是每个 Expert 都在执行一个平庸的转换,整体模型能力反而退化。

解决 Expert 塌缩的策略包括:第一,将辅助损失的超参数 α 设为较小的值(如 0.01-0.05),让主任务 loss 仍然是主导目标,负载均衡只作为辅助正则;第二,引入 Expert 容量约束(Expert Capacity),限制每个 Expert 在一个 batch 中最多处理的 token 数量,超出容量的 token 被路由到次优 Expert 或直接丢弃;第三,使用 Expert 初始化策略,让每个 Expert 在初始化时就具有多样性(如不同的初始化种子或 Perturbed Initialization)。

梯度问题是 Top-K 硬稀疏路由带来的另一个挑战。由于 argmax 操作在反向传播时梯度不可导(或者说,梯度是离散的——Top-K 选中的 Expert 接收到梯度,未选中的 Expert 梯度为零),每个 Expert 在训练中接收到的梯度信号是稀疏的和不均衡的。具体表现为:被频繁选中的 Expert 持续接收到梯度更新,而未被选中的 Expert 几乎收不到梯度,长此以往 Expert 之间的能力差距会进一步扩大,加剧赢者通吃。

缓解梯度问题的常见方法包括:第一,使用 Gumbel-Softmax 或 Straight-Through Estimator 在训练阶段为 Router 提供近似的连续梯度;第二,在 Router 的 softmax 温度上引入噪声或可学习参数,以增加路由的多样性;第三,周期性重新设置 Router 参数或对 Expert 进行扰动,打破已有的路由惯性。

DeepSeek V2 的细粒度专家拆分策略在这个背景下显得尤为精妙。DeepSeek V2 没有简单地增加 Expert 数量或调整 Top-K 值,而是将 Expert 的粒度进一步细化——将原来粗粒度的 Expert 按输出维度拆分为更小的子模块。这种细粒度拆分有两个直接好处:一是在相同的 Top-K 值下,细粒度的 Expert 子模块组合提供了更丰富的表达能力组合空间;二是 Router 的选择粒度变细后,更容易实现各子模块之间的负载均衡,因为细粒度模块更容易被分散到不同的 token 路径中。此外,DeepSeek V2 还引入了共享 Expert 机制:将一部分 Expert 固定为所有 token 必须经过的处理路径,这相当于为所有 Expert 提供了一个共同的“基座能力”,有效防止了完全的 Expert 塌缩,同时降低了 Router 的决策难度。

在面试回答这个部分时,关键是要展现出对“稀疏激活=节省推理成本,但代价是训练复杂度和稳定性挑战”这一核心矛盾的理解。候选人应该能够从 Router 设计、负载均衡、梯度传播三个维度完整阐述问题,而不是只背诵单一答案。

DeepSeek V2/V3 为什么强调 MoE

理解了 Router 机制和训练稳定性问题后,我们终于可以回答那个真正让面试官感兴趣的问题:DeepSeek V2/V3 为什么要强调 MoE?它的 MoE 实现和 Mixtral 有什么区别?为什么说它的架构选择直接决定了推理成本的量级差异?

DeepSeekMoE 与标准 MoE 的核心差异

DeepSeek V2 提出的 DeepSeekMoE 架构并非对标准 MoE 的简单复刻,而是在两个关键维度上做了精细化改进。第一是 Fine-Grained Expert 分组,将传统的完整 FFN 专家拆解为更细粒度的子专家;第二是引入 Shared Expert 共享机制,将某些跨任务通用的知识抽取逻辑固化为所有 token 都要经过的固定路由。这两个设计看似简单,却直接影响了模型的表达能力上限和推理时的计算密度。

标准 MoE(如 Switch Transformer、Mixtral)采用的是 Single FFN Expert 结构:每个 Expert 都是一个完整的 FFN 层,包含 up-projection、gate-projection 和 down-projection 三组权重。对于 Mixtral 8x7B,总参数量为 46.7B,激活参数约为 12B(8 个 Expert 中激活 2 个),每个 Expert 的大小与标准 Dense 模型的 FFN 层完全一致。这意味着 Expert 内部的计算量与传统 FFN 无异,节省的只是部分 Expert 的激活,而非 Expert 内部的计算密度。

DeepSeekMoE 的第一个改变是将每个 Expert 进一步细分为 m 个 Fine-Grained Expert。以 DeepSeek V2 为例,总 Expert 数量从传统的 8 个增加到 64 个,但每次只激活 K 个 Fine-Grained Expert。这里需要区分一个关键指标:传统 Mixtral 每次激活 2 个完整 FFN Expert,而 DeepSeek V2 可能激活 6 个 Fine-Grained Expert 中的 2 个。这两者的计算量差异在哪里?我们来算一笔账。

假设隐层维度为 7168,中间层维度扩展为 4 倍(28672),标准 FFN Expert 的参数量约为 7168 × 28672 × 2 ≈ 411M 参数。Mixtral 激活 2 个 Expert 时,单层 FFN 计算量为 2 × 411M × seq_len × batch_size 的矩阵乘法运算量。DeepSeek V2 将每个 Expert 拆分为 8 个 Fine-Grained Expert 后,每个 Fine-Grained Expert 的参数量约为 411M / 8 ≈ 51M。如果每次激活 2 个 Fine-Grained Expert,单层 FFN 计算量仅为 2 × 51M × seq_len × batch_size,相较 Mixtral 减少了约 4 倍。但这里存在一个工程上的trade-off:Fine-Grained Expert 数量增加后,Router 需要从更多候选中选择,这对 Router 的精度和负载均衡都提出了更高要求。

Fine-Grained Expert 分组策略

Fine-Grained Expert 的设计动机来源于一个直观假设:知识的分布在不同粒度上具有异质性。粗粒度的完整 FFN Expert 可能在某些任务上表现出跨领域的知识混杂——同一个 Expert 既负责处理数学推理,又参与自然语言生成,这导致 Expert 的专业化和表达能力受限。将 Expert 拆解为更细粒度的子单元后,每个 Fine-Grained Expert 可以专注于更窄的知识范围,从而在相同激活参数预算下实现更精细的知识路由。

DeepSeek V2 的具体配置是:总共 64 个 Fine-Grained Expert,每次激活 2 个(Top-2 路由)。但这里存在一个容易被忽略的细节:如果每次只激活 2 个 Fine-Grained Expert,而每个 Fine-Grained Expert 的容量大幅缩减,那么总激活参数是否反而减少了?答案是肯定的。DeepSeek V2 的设计目标并非单纯增加总参数量,而是在保持激活参数与 DeepSeek 7B( Dense 模型)相当的前提下,通过增加 Expert 数量提升知识的专业化程度。

这种策略的效果可以从两个角度理解。从表达能力角度:更多的 Expert 候选池意味着 Router 有更丰富的选择空间,可以更精准地将 token 映射到最适合处理当前语义的 Expert 组合。从参数效率角度:Fine-Grained Expert 的参数量更小,但数量更多,Router 可以通过组合多个小 Expert 实现与单个大 Expert 等价甚至更强的表达能力。

在实际面试中,如果被问到「为什么 DeepSeek V2 需要这么多 Expert 而每次只激活 2 个」,标准答案是:Fine-Grained Expert 的核心价值在于提升 Expert 的专业化和组合灵活性,而非简单地增加激活参数量。通过将知识空间划分为更细粒度的单元,模型可以在相同激活预算下实现更精细的知识路由。

Shared Expert 共享专家机制

DeepSeekMoE 的第二个关键设计是 Shared Expert 机制。在传统 MoE 中,所有 Expert 都是可选的——每个 token 根据 Router 的输出决定经过哪些 Expert,没有任何 Expert 是强制必须经过的。DeepSeek V2 引入了一组 Shared Expert(通常是 2 个),这组 Expert 的输出会直接加到最终 FFN 输出中,而无需经过 Router 选择。

Shared Expert 的设计哲学是:某些知识是跨领域、跨任务共享的,比如基础的语义表示、语法结构、位置关系等。这些通用知识不应该被 Router 随机分配到不同的 Expert 中,而是应该被显式地固化为所有 token 的必经之路。通过将这部分知识抽取能力抽取为 Shared Expert,模型可以在保持通用能力的同时,将有限的激活参数预算更多地分配给任务特定的知识处理。

从计算角度,Shared Expert 带来了确定的计算开销:每次前向传播都必须计算 Shared Expert 的输出,无法像可选 Expert 那样通过稀疏激活节省计算。但这个开销是值得的。DeepSeek V2 的实验表明,引入 Shared Expert 后,模型在保持相同激活参数规模的情况下,在知识密集型任务(如 MMLU、GSM8K)上的表现显著提升。

面试时常见的追问是:Shared Expert 和普通 Expert 有什么区别?它们的梯度是如何更新的?答案在于:Shared Expert 虽然每次都被激活,但它们的输出只是加到最终结果中,并不参与 Router 的选择决策。梯度从最终 loss 反向传播到 Shared Expert 时,会经过所有使用该 Expert 输出的 token,这意味着 Shared Expert 的梯度实际上是多任务梯度的混合,这与普通 Expert 的梯度来源是一致的。

Multi-Head Latent Attention 对推理的优化

DeepSeek V2 的另一项关键创新是 Multi-Head Latent Attention(MLA)。与标准 Multi-Head Attention(MHA)相比,MLA 通过低秩投影技术显著降低了 Key-Value 缓存的显存占用,这在长序列推理场景下尤为关键。

标准 MHA 的问题是:每个注意力头都有独立的 Key 和 Value 向量,对于 LLaMA 70B 这样的大型模型,KV 缓存的显存占用随序列长度线性增长,成为长上下文推理的瓶颈。GQA 和 MQA 通过让多个 Query 头共享 KV 头来缓解这个问题,但改进空间仍然有限。

MLA 的做法是:先将 Key 和 Value 通过低秩矩阵投影到一个更小的隐空间(Latent Space),在这个隐空间中进行注意力计算,然后通过另一个投影矩阵将结果恢复到原始空间。具体而言,假设原始 Key 向量维度为 d_k × n_heads,MLA 将其投影到 d_c 维的隐空间(其中 d_c < d_k × n_heads),然后在隐空间计算注意力后再投影回来。这个投影过程引入了额外的矩阵乘法,但由于 d_c 可以设置得远小于原始维度,总计算量反而可能降低,更重要的是显著减少了需要缓存的 KV 数据量。

DeepSeek V2 报告的 MLA 配置是:每个 token 的 KV 缓存只需要约 4MB(相比标准 MHA 减少了约 60%),这直接转化为推理时更低的显存占用和更高的 batch size。面试中如果被问到 MLA 的工程收益,可以从三个维度回答:显存占用降低(支持更长上下文)、吞吐量提升(更大的 batch size)、延迟改善(减少显存带宽压力)。

激活参数对比与工程收益量化

理解了 DeepSeekMoE 的设计细节后,我们需要量化它的工程收益。DeepSeek V2 的关键参数如下:总参数量为 21B,激活参数约为 2.4B,Fine-Grained Expert 数量为 64,Shared Expert 数量为 2,Top-K 路由为 2。对比同期的 Dense 模型:DeepSeek 7B 的总参数量和激活参数量均为 7B。

从参数量角度看,DeepSeek V2 的 21B 总参数量是 DeepSeek 7B 的 3 倍,但激活参数仅为 2.4B,比 7B 还少。这带来了两个直接收益:第一,在推理时每次前向传播的计算量约为 2.4B 参数的 Dense 模型,远小于 21B 参数的 Dense 模型;第二,总参数量更大意味着模型的知识容量更大,可以在更广泛的领域表现出更好的泛化能力。

从成本角度粗略估算:如果使用云端 GPU 进行推理,A100 GPU 的峰值算力约为 312 TFLOPS(FP16),Dense 模型 7B 的推理吞吐量约为 X tokens/s,而 DeepSeek V2 的推理吞吐量约为 1.8X tokens/s(因为激活参数减少到约 1/3)。这意味着在相同的硬件和时间预算下,DeepSeek V2 可以服务更多的并发请求,或者在服务相同并发量时使用更少的 GPU 资源。

DeepSeek V3 进一步将这个思路推向极致:总参数量扩展到 236B,激活参数约为 21B,Fine-Grained Expert 数量达到 256,Shared Expert 数量为 1。激活参数与总参数量的比例从 V2 的约 11% 进一步压缩到约 9%。这意味着在推理时,DeepSeek V3 的计算密度约为一个 21B 的 Dense 模型,但其知识容量相当于一个 236B 的 Dense 模型。

项目里怎么说:MoE 对模型选型和推理服务的影响

理解 DeepSeek 的架构设计后,我们需要将目光转向实际的模型选型和推理服务部署。MoE 的引入对工程实践产生了深远影响,这些影响在面试中往往比算法细节更容易触及候选人的实际经验。

成本预算与模型规模选型

在实际的模型选型中,MoE 的成本结构与传统 Dense 模型有本质差异。传统 Dense 模型的推理成本与模型参数量近似成正比:70B 模型的推理成本大约是 7B 模型的 10 倍,这个比例在不同服务提供商之间相对稳定。MoE 模型的成本结构则更加复杂:总参数量决定了模型存储和加载的成本,激活参数决定了实际推理计算的成本,两者之间存在一个需要权衡的「参数性价比」问题。

以 DeepSeek V2(21B 总参数、2.4B 激活参数)和 LLaMA 3 70B 为例进行比较。在相同的推理硬件上,LLaMA 3 70B 的单次推理成本约为 DeepSeek V2 的 3-4 倍(假设激活参数比例约为 1:3)。但这个比较忽略了一个关键变量:相同任务下,两个模型需要达到相同输出质量时的 token 消耗。如果 DeepSeek V2 需要生成更多的 token 才能达到与 LLaMA 3 70B 相同的回答质量,那么实际成本优势可能会缩小甚至反转。

面试中常见的陷阱问题:「DeepSeek V2 的推理成本是不是只有 LLaMA 3 70B 的 1/10?」标准回答应该是:从激活参数角度确实是这个量级,但实际成本比较需要考虑任务完成质量、token 生成效率、硬件利用率等多个维度,单纯比较参数量是片面的。

在实际项目选型中,MoE 模型的适用场景通常具有以下特征:第一,任务类型多样且复杂,需要大知识容量;第二,对推理成本敏感,但可以接受稍高的实现复杂度;第三,部署环境有足够的显存带宽但算力有限。这些特征与 DeepSeek V2 的设计目标高度吻合。

延迟敏感场景 vs 吞吐优先场景

MoE 模型的延迟特性与 Dense 模型存在显著差异,这种差异在面试中容易被忽略。在延迟敏感场景(如实时对话、交互式推理)中,MoE 的稀疏激活特性可能反而带来不利影响。

原因在于:虽然 MoE 的单次推理计算量更少,但 Router 的引入增加了额外的决策开销和数据依赖。在自回归生成场景中,每个 token 的生成都依赖于前一个 token 的 Router 输出,这意味着 Router 的延迟会直接叠加到每个 token 的生成延迟上。相比之下,Dense 模型的前馈计算虽然更耗时,但它是确定的、可预测的,不存在额外的分支决策开销。

具体而言,假设 Router 的计算延迟为 T_router,单个 Expert FFN 的计算延迟为 T_ffn。对于 Dense 模型,每个 token 的生成延迟为 T_ffn(加上 Attention 部分的计算)。对于 MoE 模型,每个 token 的生成延迟为 T_router + K × T_ffn(K 为激活的 Expert 数量)。当 K=2 且 Router 延迟不可忽略时,MoE 的端到端延迟可能比 Dense 模型更高。这个现象在短序列生成场景下尤为明显。

在吞吐优先的场景(如批量文档处理、离线推理)中,MoE 的优势则更为明显。当 batch size 足够大时,多个 token 可以并行经过不同的 Expert,GPU 的并行计算能力得到充分利用,Router 的延迟被分摊到更多的 token 上。此时 MoE 的稀疏激活特性可以显著提升 GPU 的算力利用率。

面试时如果被问到「MoE 在什么场景下延迟反而更高」,应该从 Router 延迟的串行特性、Expert 并行度的充分利用程度、以及 batch size 对延迟分摊的影响三个角度分析。

并发服务架构的设计考量

MoE 模型的部署架构与 Dense 模型也有显著差异。在 Dense 模型部署中,通常采用单 GPU 加载模型、多 GPU 并行推理的模式,模型的不同层可以分布在不同 GPU 上,但每个 token 都会经过所有 GPU(管道并行)或所有层(张量并行)。

MoE 的稀疏激活特性为并行部署带来了新的可能性,但也带来了新的挑战。DeepSeek V2 采用了 Expert 并行(Expert Parallelism)的部署策略:将 64 个 Fine-Grained Expert 分布在多个 GPU 上,每次激活的 Expert 可能位于不同的 GPU 上,需要通过集合通信(如 NCCL all-to-all)进行跨 GPU 数据传输。这种部署模式的优势是:每个 GPU 只需要存储部分 Expert 的权重,显存压力大幅降低;劣势是:跨 GPU 通信增加了延迟和带宽压力。

在实际服务架构设计中,需要权衡三个因素:显存容量(决定能加载多少 Expert)、通信带宽(决定跨 GPU 传输的效率)、计算密度(决定 GPU 算力的利用率)。DeepSeek V2 的部署策略是:将 Attention 部分采用张量并行,FFN 部分的 MoE 层采用 Expert 并行,通过精细的通信调度最小化跨 GPU 通信的开销。

对于面试官而言,询问 MoE 的部署架构设计可以有效区分候选人是「纸上谈兵」还是「真刀真枪」做过项目。如果候选人提到 NCCL、集合通信、流水线并行与 MoE 并行的结合、以及通信与计算的 overlap 等细节,说明他有实际的工程经验。

质量评估:MoE 的能力边界

最后一个需要讨论的问题是:MoE 模型的能力边界在哪里?它是否在所有任务上都优于 Dense 模型?

从目前的实证研究来看,MoE 模型的优势主要体现在以下几个方面:第一,知识密集型任务(如问答、阅读理解、科学推理),MoE 的专家路由机制可以更有效地激活与任务相关的知识模块;第二,多任务场景,MoE 在不同任务之间切换时表现出更好的适应性;第三,领域泛化,当测试集的领域分布与训练集存在差异时,MoE 的稀疏激活机制提供了更好的灵活性。

然而,MoE 模型也存在已知的劣势:第一,在需要「精确记忆」的任务上(如低频实体名称、数字序列),MoE 的表现可能不如 Dense 模型,因为相关知识可能被分散到多个 Expert 中,Router 难以准确激活;第二,在简单重复性任务上,MoE 的额外路由开销可能不值得;第三,训练不稳定性问题(已在第三章讨论)可能导致最终模型在某些边界情况下的行为不可预测。

在面试中,如果被问到「DeepSeek V2 和 Dense 模型哪个更好」,标准答案是:取决于具体任务场景和评估指标。DeepSeek V2 的 MoE 设计目标是在保持或提升模型能力的前提下显著降低推理成本,这个目标在知识密集型任务和多任务场景下得到了验证;但在某些特定场景下,Dense 模型的简单性和稳定性可能是更优选择。

典型追问与易错边界

能把 Router 的公式默写出来,不代表你真的理解了 MoE 的工程边界。面试官最后那一句「那你说说 MoE 有什么坑」,往往才是真正的区分题。本节把面试中最高频的追问和最容易踩的认知陷阱全部摊开,让你不仅能回答「是什么」,更能回答「什么时候不灵」和「工程上怎么绕过去」。

专家塌缩:为什么有些 Expert 从来没被激活过

专家塌缩(Expert Collapse)是 MoE 训练中最经典的稳定性问题,表现为训练过程中部分 Expert 的激活频率趋近于零,而少数 Expert 垄断了大多数 token 的路由权。

根因分析: 当 Router 的输出倾向于少数 Expert 时,这些 Expert 得到更多梯度更新而变得更强,进一步强化了 Router 对它们的偏好,形成正反馈循环。同时,被冷落的 Expert 由于缺乏梯度更新,能力退化,最终完全不被 Router 选中。这种马太效应在初始化不当或学习率过高时尤为明显。

判断标准: 在训练日志中监控每个 Expert 的激活频率分布。如果 Top-K=2 时某 Expert 的激活率长期低于 1%,基本可以判定为塌缩前兆。DeepSeekMoE 的论文中使用香农熵来量化 Expert 分布的均匀程度,熵值过低是塌缩的强信号。

主流解决方案:

  • 辅助负载均衡损失(Auxiliary Load Balancing Loss): 在主损失之外额外加入一个正则项,惩罚 Expert 激活频率的不均衡分布。这是 GShard 和 Switch Transformer 最早采用的方法。 - 噪声路由(Noisy Top-K Routing): 在 Router 打分时加入高斯噪声,使排名靠后的 Expert 也有一定概率被选中,打破正反馈循环。Mixtral 8x7B 采用此策略。 - Expert 能力均衡初始化: 在训练初期强制所有 Expert 的 Router 输出权重接近,防止少数 Expert 先行建立优势。DeepSeekMoE 采用了改进版的专家级偏置调整机制。 - 容量因子动态调整: 动态调整每个 Expert 的容量上限,对激活率低的 Expert 提高容量,对垄断 Expert 降低容量,间接实现负载再平衡。

需要特别强调的是,辅助损失只是缓解手段,不是根治方案。在实际项目中,往往需要组合使用上述多种策略,并对训练日志进行持续监控。

负载均衡的数学本质:辅助损失不只是防塌缩

很多候选人把负载均衡损失理解为「防止专家塌缩的技巧」,这个理解过于表层。从数学上看,负载均衡损失的本质是一个均匀分布正则化项

GShard 中定义的辅助损失为:

Laux = α · sumi=1N fi · Pi

其中 fi 是第 ii 个 Expert 的激活频率,PiP_i 是 Router 对第 ii 个 Expert 的平均概率输出。目标是最小化频率与概率的加权和,使得 Router 在所有 Expert 上均匀分配负载。

这个公式为什么有效: 当 fi 分布不均匀时(少数 Expert 被过度使用),即使 Router 打分本身是合理的,辅助损失也会通过惩罚 fi 项来推动 Router 调整策略,间接使 Router 降低对垄断 Expert 的偏好。整个优化过程在主损失和辅助损失之间做权衡,找到能力提升与负载均衡的 Pareto 前沿。

实践中容易被忽略的两个细节:

  • 权重 α 的敏感性: α 过小则均衡效果不明显,α 过大则主损失优化被压制,模型收敛变慢甚至性能退化。Switch Transformer 的实验表明,α 在 0.001~0.01 区间内效果最佳,需要根据具体模型规模和任务类型调参。 - 专家数量 N 与 Top-K 的比例关系: 当 N 很大(如 64 或 128)而 Top-K 很小(如 2)时,均衡难度显著增加。因为每个 token 只能激活极少比例的 Expert,大量 Expert 处于长期闲置状态。此时需要配合更激进的噪声路由策略。

稀疏激活不等于零成本:GPU 内存与通信开销

「MoE 激活参数少,所以推理成本低」——这句话在理论上是正确的,但在实际部署中有几个重要的隐藏成本。

GPU 内存瓶颈: 虽然每次前向只激活 Top-K 个 Expert,但所有 Expert 的权重都必须加载到显存中。一个包含 64 个 Expert 的 MoE 层,每个 Expert 的 FFN 权重矩阵(如 4096×4096)在 FP16 下需要约 128MB,64 个 Expert 合计超过 8GB。这对于多卡推理场景是不可忽视的显存占用。DeepSeek V2 的 MLA 机制在注意力层面进一步压缩了 KV cache 的显存压力,但 MoE 层的 Expert 权重始终是内存墙。

All-to-All 通信开销: 在分布式推理中,不同 token 被路由到不同 Expert,而这些 Expert 可能分布在不同的 GPU 或节点上。Token 需要从本地路由到的 Expert 所在节点获取中间激活,完成计算后再返回。这个 All-to-All 集合通信在节点内通过 NVLink 尚可接受,但跨节点通信会引入显著延迟。在 MoE 领域通常称为 expert parallel(EP),是 2023 年后大模型推理框架(如 FasterTransformer、TGI v2)的核心优化点。

Expert 容量与溢出处理: 每个 Expert 有容量上限(Capacity Factor),当某个 Expert 被路由的 token 数量超过容量时,需要将溢出的 token 丢弃或重路由。容量因子设置过低会导致 token 丢弃率上升,设置过高则浪费计算资源。这是 MoE 推理系统中需要精细调参的核心参数。

实际工程建议: 在选型阶段,不要只看「总参数量」和「激活参数」两个数字,还要评估 Expert 权重在目标硬件上的显存占用、跨 GPU 通信带宽需求,以及容量因子的调参空间。对于显存受限的消费级 GPU(如单卡 24GB),MoE 模型的 Expert 数量和 FFN 维度需要做更保守的裁剪。

MoE 与注意力机制演进:MLA 是如何叠加在 MoE 上的

DeepSeek V2/V3 的一个关键创新是把 Multi-Head Latent Attention(MLA) 与 MoE 结合。这里需要理解为什么两者组合是工程上合理的,而不仅是学术上的叠加。

注意力机制的演进脉络: 标准 Multi-Head Attention(MHA)在每个 head 维护独立的 Q、K、V 投影,参数量随 head 数线性增长。MQA 让所有 head 共享 K 和 V,大幅降低 KV cache 显存但可能损害模型质量。GQA 作为折中,让 K 和 V 按组共享。DeepSeek V1 引入的 MLA 则更进一步,通过低秩分解将 KV 压缩到低维潜在空间:

vc = Wdownh, quad kc = Wupvc

这种设计使 KV cache 从 O(dmodel × nhead) 降低到 O(dc × nhead),其中 dc ll dmodel。

为什么 MLA + MoE 是互补的: MoE 解决的是 FFN 层的计算效率问题,MLA 解决的是注意力层的显存效率问题。在深层层叠中,每一层的计算包括注意力计算和 FFN 计算两部分。MoE 压缩了 FFN 的激活计算量,MLA 压缩了注意力层的 KV cache 显存占用,两者从不同维度降低推理资源消耗,组合使用时有乘数效应。

面试回答模板: 「MoE 解决 FFN 层的激活稀疏性问题,MLA 解决注意力层的 KV cache 压缩问题。DeepSeek V2 的核心贡献是把两者在同一模型架构中协同设计:MoE 层使用细粒度 Expert 分组和共享 Expert 机制保证参数利用率,MLA 层通过低秩潜在空间压缩降低注意力计算的显存带宽。在推理时,MoE 减少了单位 token 的 FFN 计算量,MLA 减少了单位 token 的 KV cache 显存占用,两者叠加使得 DeepSeek V2 能在远小于 Dense 模型显存需求的前提下保持相近的模型能力。」

项目表述的正确姿势:别把 MoE 说成万能药

在面试中描述自己使用 MoE 的项目经验时,有一个高频误区:把 MoE 模型当作「能力更强」的模型来描述。实际上 MoE 的核心价值是在给定推理成本约束下的能力扩展,而不是无条件的质量提升。

正确的项目表述框架:

  • 选型动机: 在什么推理成本或吞吐约束下,标准的 Dense 模型无法满足需求;为什么需要更大参数规模但不能线性增加激活计算。 - 技术选型: 选用了哪个 MoE 架构(标准 MoE / DeepSeekMoE / 其他);Expert 数量、Top-K 设置、辅助损失权重、容量因子的依据是什么。 - 训练稳定性处理: 是否遇到 Expert 塌缩,采用何种均衡策略,调参过程中踩了哪些坑。 - 推理部署: Expert 并行策略、All-to-All 通信优化、显存占用评估、容量因子调参结果。 - 效果评估: 在相同激活参数预算下与 Dense 基线模型的困惑度(Perplexity)对比、首 token 延迟和吞吐对比。

需要主动承认的边界:

  • MoE 模型在特定任务上的表现可能低于同等激活参数的 Dense 模型,尤其当任务需要 Expert 之间的协同推理时。 - 训练稳定性和调参复杂度显著高于 Dense 模型,项目的隐性成本需要诚实评估。 - 当 batch size 较小或序列长度较短时,MoE 的稀疏优势可能被通信开销抵消,此时 Dense 可能更高效。

面试最后追问的预判清单

根据对历年大模型岗位面试题目的统计,以下追问在 MoE 相关问题中出现频率最高,提前准备好答案能显著提升面试表现:

追问一:「如果 Expert 塌缩了,你怎么发现?发现了怎么修复?」

回答要点:监控训练日志中每个 Expert 的激活频率分布;发现后可通过增加噪声路由强度、调高辅助损失权重、调整 Expert 初始化策略进行修复;若塌缩严重,需要从检查点重新训练或调整学习率调度。

追问二:「MoE 的通信开销具体在哪个环节产生的?你怎么优化?」

回答要点:All-to-All 通信发生在 token 被路由到不同节点上的 Expert 时;优化方向包括 Expert 亲和性调度(让相关 token 尽可能路由到同节点 Expert)、通信与计算重叠(使用流水线隐藏延迟)、梯度压缩(减少通信数据量)。

追问三:「MoE 和 LoRA 能一起用吗?有什么冲突?」

回答要点:可以结合使用,MoE 的 Expert FFN 层可以应用 LoRA 进行轻量微调;需要注意的是 MoE 的稀疏性使部分 Expert 在下游任务中可能完全没有被激活,导致 LoRA 适配效果受限;建议对所有 Expert 应用同等配置的 LoRA,避免能力不对称。

追问四:「为什么 DeepSeek 的 MoE 能打下来成本,但 GPT-4 的 MoE(如果有)没有强调这个?」

回答要点:DeepSeek 作为开源模型,需要通过工程效率建立竞争力,因此明确量化推理成本节省有其商业动机;闭源模型的定价策略不一定透明,且规模更大、路由策略更复杂,可能在部署层面有其他考量;核心判断标准始终是「激活参数与总参数的比率」和「实际推理部署的吞吐量增益」。

追问五:「如果让你从头设计一个 MoE 系统,你最关心的三个工程指标是什么?」

回答要点:① Expert 激活频率分布的均匀度(直接影响模型容量利用率);② All-to-All 通信延迟与计算延迟的比率(决定并行策略的有效性);③ 每 token 平均显存占用与激活参数的乘积关系(决定能否在目标硬件上部署)。

面试时不要被追问的数量吓到,面试官追问的目的是验证你「不仅知道怎么用,更知道什么时候不能用、哪里会出问题」。MoE 作为一个仍处于快速演进中的架构,保持对工程边界问题的诚实和好奇,本身就是加分项。


核心参考文献:


延伸入口


文末收口图

参考文献

[1] 原始资料[EB/OL]. www.w3.org/2000/svg". (2026-05-22). [2] 原始资料[EB/OL]. arxiv.org/abs/2006.16…. (2026-05-22). [3] 原始资料[EB/OL]. arxiv.org/abs/2101.03…. (2026-05-22). [4] 原始资料[EB/OL]. arxiv.org/abs/2401.04…. (2026-05-22). [5] 原始资料[EB/OL]. arxiv.org/abs/2401.06…. (2026-05-22). [6] 原始资料[EB/OL]. arxiv.org/abs/2405.04…. (2026-05-22). [7] 原始资料[EB/OL]. arxiv.org/abs/1911.02…. (2026-05-22). [8] 原始资料[EB/OL]. arxiv.org/abs/2305.13…. (2026-05-22).