【LLM推理与Serving⑪】MoE推理与MLA:DeepSeek-V3架构下的显存与通信权衡

【LLM推理与Serving⑪】MoE推理与MLA:DeepSeek-V3架构下的显存与通信权衡

本系列博客专注于LLM推理与Serving的核心技术,从基础概念到工程实践,循序渐进。本篇是第11篇,我们深入MoE(混合专家)模型的推理系统,结合DeepSeek-V3的架构设计,探讨专家并行、MLA(Multi-head Latent Attention)等关键技术如何在显存与通信之间找平衡。


一、MoE推理为什么独特?总参数巨大但激活参数很小

在聊MoE推理之前,先回顾一下MoE是什么。

传统的Transformer是"密集模型"(Dense Model)------每个token进来,所有层的所有参数都要参与计算。而MoE(Mixture of Experts,混合专家)模型把FFN层拆成N个"专家",每个token只路由到其中Top-K个专家(通常K=1或K=2)。

一句话概括:总参数量很大,但每个token只激活很小一部分参数。

以DeepSeek-V3为例,它有671B总参数,但每个token只激活37B参数(大约是总参数的5.5%)。这带来了一个很反直觉的现象:

训练时,MoE的瓶颈是算力------因为要把所有专家的参数都"过一遍"(虽然每个token只激活少数专家,但batch内所有token激活的专家并集可能覆盖全部)。

推理时,MoE的瓶颈是显存容量------因为所有专家的权重都得放在显存里,虽然每次只用少数,但你得全部存着。

举个具体的对比:

模型 总参数量 激活参数量 FP16权重显存
Llama-3-70B(Dense) 70B 70B ~140GB
DeepSeek-V3-671B(MoE) 671B ~37B ~1342GB

看到了吗?DeepSeek-V3的激活参数量只有37B,比70B密集模型还小,但权重显存是70B的近10倍!这就是MoE推理最核心的矛盾------算力很富余,显存装不下。

所以,MoE推理系统的设计,本质上就是在和"显存容量"和"通信开销"这两件事做斗争。


二、MoE推理的第一瓶颈:显存容量而非算力

我们以DeepSeek-V3为例,来拆解一下显存都花在哪了。

DeepSeek-V3的架构参数(公开信息整理):

  • 层数:61层
  • 隐藏维度:7168
  • 专家总数:256个(每层)
  • 每个token激活专家数:Top-8
  • 注意力头数:128(GQA,共享16组KV头)
  • 中间FFN维度:每个专家是标准FFN

2.1 权重要占多少显存?

权重主要分两部分:注意力层 + FFN专家层。

注意力层权重:是共享的(所有token都用同一套attention参数),所以和密集模型一样:

Wattn≈2×h2×L=2×71682×61≈6.3B 参数≈12.6GB (FP16)W_{attn} \approx 2 \times h^2 \times L = 2 \times 7168^2 \times 61 \approx 6.3\text{B 参数} \approx 12.6\text{GB (FP16)}Wattn≈2×h2×L=2×71682×61≈6.3B 参数≈12.6GB (FP16)

FFN专家层权重:256个专家,每个专家是标准的up+gate+down三层:

Wffn≈Nexpert×3×h×dff×LW_{ffn} \approx N_{expert} \times 3 \times h \times d_{ff} \times LWffn≈Nexpert×3×h×dff×L

假设每个专家的中间维度是常规比例(比如d_ff = 2.7h ≈ 19200左右),那么单层FFN专家总参数大约是:

Wffn_per_layer=256×3×7168×19200≈105B 参数W_{ffn\_per\_layer} = 256 \times 3 \times 7168 \times 19200 \approx 105\text{B 参数}Wffn_per_layer=256×3×7168×19200≈105B 参数

乘以61层,总FFN参数量极其庞大。这就是为什么MoE模型"看起来很大"。

好消息是,推理时每个token只激活8个专家,所以计算量并不大------8/256 ≈ 3%的专家被激活,和一个30B左右的密集模型计算量相当。

坏消息是,所有256个专家的权重都得存在显存里------因为你不知道下一个token会路由到哪些专家,总不能现用现从CPU加载吧?那延迟就爆炸了。

2.2 所以瓶颈是什么?

总结一下MoE推理的资源画像:

  • 显存容量:紧张!权重本身就大,还要加上KV Cache
  • 显存带宽:还好。激活的专家少,实际搬的权重数据不多
  • 算力:很富余。37B激活参数,H100轻轻松松
  • 通信:很大!这是我们下一节要讲的专家并行(EP)带来的

这和密集模型很不一样------密集模型的瓶颈通常是显存带宽(Decode阶段)或算力(Prefill阶段),而MoE推理的第一瓶颈是能不能把模型塞进显存。


三、专家并行EP原理:dispatch/combine两次all-to-all

既然单个GPU装不下所有专家,那就把专家分散到多张GPU上。这就是专家并行(Expert Parallelism, EP)。

3.1 EP的基本思路

假设我们有8张GPU,模型有256个专家。每张GPU放32个专家(256/8=32)。当一个token需要路由到Top-8专家时:

  1. 如果这8个专家都在同一张GPU上,那好办,直接在本地算
  2. 如果这8个专家分布在不同GPU上,那就需要把token的"代表"(hidden state)发送到持有对应专家的GPU上,算完再把结果收回来

这就是EP的核心:token在GPU之间"搬家",去找对应的专家。

3.2 Dispatch / Combine 两次all-to-all

EP的每一层FFN包含两次全局通信:

第一次:Dispatch(分发)

  • 输入:每张GPU上有一批token的hidden state

  • 操作:根据路由结果,把每个token发送到持有其目标专家的GPU上

  • 通信模式:all-to-all(每个GPU都要给其他每个GPU发数据)

    GPU0 的 token A → 专家3 → 在 GPU1 上 → 发给 GPU1
    GPU0 的 token B → 专家7 → 在 GPU2 上 → 发给 GPU2
    ...

第二次:Combine(聚合)

  • 输入:每张GPU上,本地专家算完了各自的输出
  • 操作:把算好的结果发回token原来所在的GPU
  • 通信模式:又是一次all-to-all

两次all-to-all,一去一回,构成了EP一层完整的通信。

3.3 通信量估算

我们来算一下一层EP的通信量有多大。

假设:

  • 全局batch size(token数):B
  • 隐藏维度:h
  • Top-K激活专家数:K
  • 每个token的hidden state大小:h × 2字节(FP16)

每个token要被发送K次(去K个专家),然后K个结果要回来。注意回来的也是K个hidden state,大小一样。

所以单层EP的全局通信量是:

Comm=2×B×K×h×2 字节\text{Comm} = 2 \times B \times K \times h \times 2 \text{ 字节}Comm=2×B×K×h×2 字节

系数2是因为dispatch + combine各一次。最后那个2是FP16的字节数。

代入DeepSeek-V3的数字(h=7168, K=8):

Comm_per_token=2×8×7168×2≈229KB / token / 层\text{Comm\_per\_token} = 2 \times 8 \times 7168 \times 2 \approx 229\text{KB / token / 层}Comm_per_token=2×8×7168×2≈229KB / token / 层

61层的话,每个token的通信总量约为:229KB × 61 ≈ 14MB / token

这个量其实相当大。所以EP对GPU之间的互联带宽要求非常高------这也是为什么NVLink在MoE推理中这么重要。

3.4 EP与TP/DP的组合策略

实际生产中,不会只单独用EP,而是和张量并行(TP)、流水线并行(PP)、数据并行(DP)组合使用。常见的组合策略:

策略一:EP + TP

把FFN专家按EP切,注意力层按TP切。适合单节点内(NVLink高速互联)。

DeepSeek-V3的推理推荐配置就是这种------节点内用高速NVLink做EP + TP,通信开销可以接受。

策略二:EP + DP

跨节点之间用DP(数据并行),节点内用EP。跨节点的DP通信量(all-reduce)相对较小(只传梯度/更新,推理时甚至不需要),而EP的all-to-all通信量大,放在节点内用NVLink扛。

策略三:EP + TP + PP + DP 四维并行

超大规模模型(比如万亿参数以上)可能需要四维并行一起上。工程复杂度极高,一般只有头部公司才有能力做。

对于MoE推理,一个经验法则是:EP的粒度尽量放在高速互联域内(比如同一个DGX节点的8张卡之间),跨节点尽量只做DP。


四、Decode阶段专家负载不均问题

Prefill阶段还好------batch里有很多token,路由到各个专家的数量比较均匀。但到了Decode阶段,每个请求一个token,batch size小的时候,专家负载可能严重不均。

4.1 为什么会不均?

举个极端例子:batch里只有1个token,它激活Top-8专家。如果这8个专家全在同一张GPU上,那其他GPU上的专家就全闲着,利用率 = 1/8 = 12.5%。

即使batch稍大一些,由于路由的随机性和数据的偏态分布,也可能出现某些GPU上专家被激活得多、某些GPU上少的情况。

这就是专家负载不均(Expert Load Imbalance)问题,它会导致:

  • 部分GPU空闲,整体吞吐下降
  • 木桶效应------最慢的那张GPU决定了整层的延迟

4.2 三种工程解法

解法一:冗余专家(Redundant Experts)

把同一个专家复制到多张GPU上。token路由到这个专家时,可以选负载较轻的那张GPU去算。

代价是:权重显存增加了(重复存储),而且需要额外的负载均衡调度逻辑。

解法二:EPLB(Expert Parallel Load Balancing)

EPLB是一种动态负载均衡策略------在dispatch阶段,不严格按照"专家在哪个GPU就发给哪个GPU",而是允许一部分token被"迁移"到其他GPU上对应的冗余专家副本,或者在允许的范围内调整路由选择,让各GPU的计算量尽量均衡。

具体实现上,可以在路由时加一个"负载感知"的调整:如果某个专家所在的GPU已经很忙,而另一个GPU上有这个专家的副本(或者有一个排名接近的备选专家),就把token导过去。

解法三:Bias调整(路由偏置)

在训练时就给路由函数加一个"负载均衡bias",让路由结果天然更均匀。这样推理时各专家的负载就比较平衡,不需要推理侧做太多调度。

典型做法是在router的logits上加一个aux loss,惩罚专家负载不均。这是训练侧的优化,但直接影响推理侧的效率。


五、DeepEP:为MoE而生的all-to-all通信库

聊到MoE推理的通信优化,就不得不提 DeepEP------DeepSeek团队开源的、专门为MoE推理优化的all-to-all通信库。

5.1 为什么需要专门的通信库?

普通的all-to-all(比如NCCL的alltoall)是通用的,假设每个进程给每个其他进程发的数据量都差不多。但MoE的all-to-all有特殊性:

  • 每个GPU发送的数据量取决于路由结果,可能不均匀
  • 数据是按token组织的,每个token有自己的目标专家
  • 通信和计算可以重叠(一边发,一边算已经到达的token)

DeepEP就是针对这些特点做的深度优化。

5.2 DeepEP的核心优化点

1. NVLink 感知优化

DeepEP针对NVLink的拓扑做了专门的调度,充分利用多对多同时传输的能力。在DGX H100这样的全互联节点上,NVLink带宽利用率可以做得很高。

2. 双模式(Dual Mode)

DeepEP支持两种工作模式:

  • Token-based模式:以token为单位调度,适合batch较小、负载不均的情况
  • Batch-based模式:以批次为单位,适合batch较大、负载较均匀的情况

推理系统可以根据当前batch size和负载情况自动切换模式。

3. 通信计算重叠(Overlap)

这是最关键的优化------不需要等所有数据都收完才开始算,而是收到一部分就先算一部分,计算和通信流水线化。

具体来说:

  • Dispatch阶段:边收token,边把已经收到的token喂给本地专家计算
  • Combine阶段:边算边发结果,不用等所有专家都算完

这样可以把通信时间"藏"在计算时间里,端到端延迟显著降低。

4. 低延迟调度

针对Decode阶段batch小、延迟敏感的特点,DeepEP做了细粒度的调度优化,减少启动开销和等待时间。

DeepEP的开源地址:https://github.com/deepseek-ai/DeepEP,有兴趣的同学可以去看看源码,对理解MoE通信很有帮助。


六、MLA原理:从存全部head K/V到存低秩latent

聊完了MoE的FFN部分,我们再来聊聊DeepSeek-V3的另一个创新------MLA(Multi-head Latent Attention,多头潜在注意力)。这是对注意力机制本身的改造,目标是进一步减少KV Cache的显存占用。

6.1 为什么需要MLA?

普通MHA(Multi-Head Attention)中,每个注意力头都有自己独立的K和V:

Attention(Q,K,V)=softmax(QKT/dk)V\text{Attention}(Q, K, V) = \text{softmax}(QK^T/\sqrt{d_k})VAttention(Q,K,V)=softmax(QKT/dk )V

假设有H个head,每个head维度是d_k,那么KV Cache的总大小是 2 × H × d_k × seq_len × 2字节(FP16)。

后来有了GQA(Grouped Query Attention)和MQA(Multi-Query Attention)------让多个query head共享同一组KV head,减少KV Cache。DeepSeek-V2/V3用的MLA走得更远。

6.2 MLA的核心思想

MLA的直觉是:不同head的K/V之间存在冗余,可以用更低的秩来表示。

具体做法是这样的:

1. 压缩KV到低秩latent

不直接存每个head的K和V,而是存一个低维的"潜在表示"(latent)。这个latent向量比原始K/V的总维度小得多。

公式上,MLA引入了一个压缩矩阵 WkvW_{kv}Wkv,把key和value"压缩"到低维空间:

ht(kv)=Wkv⋅kt;vth_t^{(kv)} = W_{kv} \cdot k_t; v_tht(kv)=Wkv⋅kt;vt

其中 kt;vtk_t; v_tkt;vt 是原始K/V的拼接,维度很高;ht(kv)h_t^{(kv)}ht(kv) 是压缩后的latent,维度很低。

2. 用吸收矩阵技巧恢复

推理时,从latent恢复出每个head需要的K/V,靠的是吸收矩阵(Absorption Matrix)技巧。

具体来说,把Q投影矩阵和K/V的解压缩矩阵合并------在Q端做一次线性变换,相当于在K端做了逆变换。这样,虽然KV被压缩了,但Q乘以"压缩后的K的转置"效果和原来差不多。

更准确地说,MLA的注意力计算变成了:

Attn=softmax(Q′⋅(Wk_latent⋅ht(kv))T/dk)⋅(Wv_latent⋅ht(kv))\text{Attn} = \text{softmax}\left(Q' \cdot (W_{k\latent} \cdot h_t^{(kv)})^T / \sqrt{d_k}\right) \cdot (W{v\_latent} \cdot h_t^{(kv)})Attn=softmax(Q′⋅(Wk_latent⋅ht(kv))T/dk )⋅(Wv_latent⋅ht(kv))

其中 Q′=Q⋅WQ′Q' = Q \cdot W_Q'Q′=Q⋅WQ′ 是经过吸收矩阵调整后的Q。

关键洞察 :因为 Wk_latentW_{k\latent}Wk_latent 和 Wv_latentW{v\_latent}Wv_latent 是权重(和token无关),可以和Q的投影矩阵合并------于是Q侧多了一点计算,但KV侧省了大量存储空间。

6.3 MLA 与 TP 的矛盾 → DP Attention

MLA有一个"副作用":它和**张量并行(TP)**不太兼容。

为什么?因为TP通常是按head切分的------每张GPU存一部分head的KV。但MLA的latent是"全局压缩"的,各个head的信息混在一起了,没法干净地按head切。

DeepSeek的解决方案是:用DP Attention代替TP Attention------即注意力层不用张量并行,改用数据并行(或者说"序列并行"的某种变体)。具体来说,把序列维度切到多张卡上,每张卡算自己那段序列的注意力,然后通过ring attention之类的方式通信。

这是一个很有意思的架构tradeoff:用MLA省KV Cache显存 + 用DP Attention做并行,替代了传统的TP方案。两者各有优劣,但对于超长上下文场景,MLA+DP的组合往往更优。


七、MHA/GQA/MQA/MLA定量对比

说了这么多,我们来做一个定量对比,看看各种注意力方案的KV Cache到底差多少。

7.1 每token KV Cache字节数

计算公式(FP16存储):

KV_per_token=2×Hkv×dk×2 字节\text{KV\_per\token} = 2 \times H{kv} \times d_k \times 2 \text{ 字节}KV_per_token=2×Hkv×dk×2 字节

其中:

  • 系数2:K和V各一份
  • HkvH_{kv}Hkv:KV head的数量
  • dkd_kdk:每个KV head的维度
  • 最后那个2:FP16每个元素2字节

我们以DeepSeek-V3的配置为参考基准来对比:

注意力方案 KV head数 每head维度 总KV维度 每token KV Cache(FP16) 相对大小
MHA 128 128 16384 64 KB 1x
GQA(16组) 16 128 2048 8 KB 1/8x
MQA 1 128 128 0.5 KB 1/128x
MLA(latent) - - 512(latent维) ~2 KB ~1/32x

(注:MLA的数字是示意,实际latent维度根据模型配置不同而不同)

可以看到:

  • MQA最省,但精度损失也最大
  • GQA是精度和效率的折中(目前最主流)
  • MLA比GQA还省好几倍,同时精度损失比MQA小很多

7.2 128k上下文对比

我们来算一下128k上下文长度下,单个请求的KV Cache占多少显存:

方案 每token KV 128K上下文KV总大小 可放的请求数(80GB显存,假设占20%给KV)
MHA 64 KB 8 GB ~2个
GQA(16组) 8 KB 1 GB ~16个
MQA 0.5 KB 64 MB ~256个
MLA ~2 KB 256 MB ~64个

这个差距是非常惊人的。同样80GB的A100,用MHA只能同时服务2个128K上下文的请求;用MLA可以服务64个;用MQA甚至可以服务256个。

当然,实际系统中KV Cache不是唯一的显存开销(权重、激活、临时工作区都要占显存),而且MQA的精度损失在很多场景下是不可接受的。MLA的价值就在于------在比GQA更省显存的同时,保持接近MHA的精度。


八、vLLM/SGLang的MoE与MLA支持现状

讲了这么多理论,最后我们来看看主流推理框架的支持情况。

8.1 vLLM

vLLM是目前最流行的开源推理框架之一,对MoE的支持一直在迭代:

  • MoE支持:vLLM从v0.4开始逐步完善MoE支持,目前已经支持Mixtral、Qwen2MoE、DeepSeekMoE等主流MoE模型
  • 专家并行(EP):支持通过NCCL进行EP通信,节点内效果不错
  • 量化:支持AWQ、GPTQ等量化方式配合MoE
  • MLA支持:vLLM已经在适配DeepSeek-V2/V3的MLA注意力,社区有对应的PR

8.2 SGLang

SGLang是另一个快速发展的推理框架,在某些场景下性能优于vLLM:

  • MoE支持:SGLang对MoE的支持很积极,DeepSeek-V2/V3是其重点优化对象
  • RadixAttention + MoE:SGLang的RadixAttention(前缀缓存)和MoE结合,可以进一步提升长上下文场景的效率
  • MLA支持:SGLang较早支持了MLA,并且做了针对性的kernel优化
  • DeepEP集成:SGLang在探索和DeepEP的集成,以进一步降低MoE通信开销

8.3 给infra学习者的建议

如果你想动手实践MoE推理,建议的路径是:

  1. 先跑通Mixtral-8x7B:这是最经典的MoE模型,社区支持最好,各种框架都能跑
  2. 再试DeepSeek-V2-Lite:体量适中,包含MoE + MLA的核心设计
  3. 读SGLang的MoE相关代码:SGLang的代码质量不错,MoE部分的实现比较清晰
  4. 做性能实验:对比不同EP粒度、不同batch size下的吞吐和延迟,建立直觉

九、小结与思考

9.1 小结

MoE推理是大模型推理领域最有挑战性也最有意思的方向之一。我们这篇博客覆盖了:

  1. MoE推理的独特性:总参数巨大但激活参数很小,瓶颈是显存而非算力
  2. 专家并行EP:dispatch/combine两次all-to-all,通信量巨大,对互联带宽要求高
  3. 负载不均问题:Decode阶段尤其严重,解法包括冗余专家、EPLB、bias调整
  4. DeepEP:专门为MoE优化的通信库,NVLink感知、双模式、通信计算重叠
  5. MLA原理:把KV压缩成低秩latent,用吸收矩阵技巧恢复,大幅省KV Cache
  6. MLA与TP的矛盾:MLA不适合TP,改用DP Attention
  7. 定量对比:MHA/GQA/MQA/MLA四种方案的KV Cache差距可达上百倍
  8. 框架支持:vLLM和SGLang都在快速迭代MoE与MLA支持

整个MoE推理系统的设计哲学可以概括为:在显存容量和通信开销之间找最优平衡点。 EP用通信换显存,MLA用少量计算换显存,DeepEP用更聪明的通信减少延迟------一切都是tradeoff。

相关推荐
github_is_geeksKai25 分钟前
50 个 AI 与开源工具怎么选:从实际用途到实现边界
人工智能
IT_陈寒33 分钟前
Vite的HMR把我整不会了:一个生产环境的热更新坑
前端·人工智能·后端
github_is_geeksKai35 分钟前
浏览器 AI 小工具怎么选?40 个项目与 5 类商业任务的参考指南
人工智能
styshoo37 分钟前
[snapshot]7-placeholder与恢复流程
人工智能
这个DBA有点耶1 小时前
库内计算推理:一条SQL背后的算子融合,和外挂方案差了几次网络往返
数据库·人工智能·sql
SelectDB1 小时前
AI Agent 的分析数据存在哪里?Trace、Prompt 与会话数据的存储选型
人工智能
SelectDB2 小时前
京东 Apache Doris 湖仓查询优化实践:从多引擎统一到百万级查询
人工智能
伞伞悦读2 小时前
【第81期】特征缩放怎么选:标准化、MinMax 与 Robust 的原理、泄漏对照和完整实验
人工智能·python·深度学习·机器学习
网易云信2 小时前
销冠跑了,经验留下:AI Agent 如何进入医美机构的日常工作?
人工智能