概述
DeepSeek V3 的 MoE(Mixture of Experts)模块是其核心组成部分,采用 Shared + Routed Expert 架构。本文基于 vLLM 代码库,深入分析其计算流程、通信模式、量化方案以及性能优化策略。
整体架构
DeepSeek V3 MoE 层的代码入口为 DeepseekV2MoE,整体结构如下:
DeepseekV2MoE
├── GateLinear → 路由 logits 生成
├── SharedExperts → 所有 token 共享的 dense MLP
└── FusedMoE → 稀疏 routed expert 计算
├── ExpertMapManager → 专家映射(global → local)
├── Router (GroupedTopK) → top-k 专家选择
└── MoERunner → 执行引擎(dispatch → 计算 → combine)
核心设计思想:所有 token 先经过一个共享的 dense MLP,再经路由选择少量专家计算,两者结果相加。
shared_out = shared_experts(hidden_states) # 所有 token 都计算
final = shared_out + routed_out # 两者相加
Gating 与 Routing
GateLinear
GateLinear 将 hidden_states 映射到 n_routed_experts 维的 logits 向量,采用三级 GEMM 调度:
- DSV3 专用 kernel(SM90+, batch ≤ 16)— 最低延迟
- cuBLAS bf16 → fp32(SM90+, bf16 权重)
- 标准
F.linear兜底
若 topk_method == "noaux_tc",gate 额外携带 e_score_correction_bias(per-expert 可学习偏置),用于无辅助 loss 的负载均衡。
Grouped Top-k Routing
DeepSeek V3 采用独有的两级路由策略,先选 group 再选 expert:
router_logits → sigmoid/softmax → scores
→ 每 group 取 top-2 scores 之和 → 选 topk_group 个 group
→ mask 掉未选中 group → 从剩余 expert 中选 top_k 个
→ renormalize → * routed_scaling_factor
→ topk_weights, topk_ids
关键设计:若 e_score_correction_bias 存在,selection 用 biased scores(实现负载均衡),weights 用 original unbiased scores(保证精度),两者分离。
路由计算结果被后续 expert 计算和通信层使用:
topk_ids:每个 token 选中的 expert 编号topk_weights:每个选中 expert 的权重(用于 combine 阶段的加权求和)
通信模式
DeepSeek V3 MoE 的通信发生在三个维度:TP(Tensor Parallel)、DP/EP(Expert Parallel)、PCP(Pipeline Cross-Parallel)。
通信流水线
Forward Input (全量 token)
│
▼
Sequence Parallel Chunk (if is_sequence_parallel)
│
▼
Dispatch (AllGather / All2All)
│ token 按 expert 路由分散到对应 EP rank
▼
Expert Compute (各 EP rank 计算本地 expert)
│
▼
Combine (ReduceScatter / All2All)
│ 结果归集回各 rank
▼
All-Reduce (final, 若 combine 未做 reduction)
│
▼
Sequence Parallel AllGather (恢复完整序列)
│
▼
Final Output
通信后端
vLLM 提供了丰富的 all2all 通信后端,在 all2all_utils.py 中统一管理:
| 后端 | 适用场景 | 特点 |
|---|---|---|
| DeepEP High-throughput | 大 batch | 高吞吐,异步 dispatch/combine |
| DeepEP Low-latency | 小 batch | 支持 FP8 dispatch,通信量减半 |
| FlashInfer NVLink Two-sided | NVLink | 双向 NVLink 通信 |
| FlashInfer NVLink One-sided | NVLink | 支持 nvfp4/mxfp8 dispatch |
| AllGather + ReduceScatter | 通用兜底 | 朴素 AG+RS,无需特殊库 |
| NIXL EP | RDMA 跨节点 | 支持 FP8 dispatch |
| MORI | ROCm | AMD AITER 后端 |
模块化内核(Modular Kernel)框架
vLLM 的 MoE 采用 Modular Kernel (MK) 框架,核心目的是解耦通信和计算,避免通信后端 × 计算后端的组合爆炸。
设计思想
传统方案的问题:若有 M 个计算后端 × N 个通信后端,需要 M×N 个组合实现。
模块化解法:
FusedMoEKernel
├── prepare_finalize: 通信层
│ prepare(): 量化 + dispatch (all2all/ag)
│ finalize(): 权重应用 + reduce (all2all/rs)
└── fused_experts: 计算层
w13 → activation → w2 (matmul)
只需要 M + N 个实现即可,通过 FusedMoEKernel 编排流水线 prepare → compute → finalize。
核心类层次
通信层(Prepare/Finalize):
FusedMoEPrepareAndFinalizeModular— 接收路由后结果(topk_weights,topk_ids),做量化 + all2all dispatch 和 combineFusedMoEPrepareAndFinalizeMonolithic— 接收原始 logits,内部 fused 路由
计算层(Experts):
FusedMoEExpertsModular— 执行w13 → act → w2,不关心通信,只处理已 dispatch 到本地的 tokenFusedMoEExpertsMonolithic— 内部自己做 routing + compute
编排层(Kernel):
FusedMoEKernel— 对外统一接口,根据 impl 类型 dispatchFusedMoEKernelModularImpl— 编排流水线_prepare → _fused_experts → _finalize
Oracle 模式
Oracle 是智能后端选择器 + 内核工厂,在 oracle/ 目录下,每种量化类型对应一个文件:
oracle/
├── fp8.py → select_fp8_moe_backend() + make_fp8_moe_kernel()
├── int8.py → select_int8_moe_backend()
├── nvfp4.py → select_nvfp4_moe_backend()
├── mxfp4.py → select_mxfp4_moe_backend()
└── unquantized.py → select_unquantized_moe_backend()
两阶段决策:
- Phase 1:
select_*_backend()— 按优先级检查各后端是否支持当前配置(SM 版本、batch 大小、EP/DP 配置等),返回最优可用后端 - Phase 2:
make_*_kernel()— 组合prepare_finalize(通信层)+experts(计算层)为完整的FusedMoEKernel
两条路径对比
MoE 的计算与通信有两个独立且互斥的路径,通过 do_naive_dispatch_combine 切换:
do_naive_dispatch_combine = dp_size > 1 and not supports_internal_mk
Path 1: _maybe_dispatch + _maybe_combine | Path 2: prepare_finalize (MK 内部) | |
|---|---|---|
| 触发条件 | DP>1 且 kernel 不支持 MK | kernel 是 MK 框架 |
| 位置 | _forward_impl 中 quant 方法前后 | FusedMoEKernelModularImpl 内部 |
| 操作对象 | 路由前的 hidden_states + router_logits | 路由后的 hidden_states + topk_weights + topk_ids |
| 通信方式 | AllGather / ReduceScatter | DeepEP / FlashInfer / NIXL / AgRs |
| 处置维度 | DP(复刻 token) | EP(按 topk_ids 分发) |
执行流程
_forward_impl 中的完整执行流
_forward_impl:
_maybe_dispatch(hidden_states, router_logits)
├── [Path 1] DP>1 && !supports_internal_mk → all_gatherv
└── [Path 2] 否则 → no-op
_apply_quant_method(hidden_states, router_logits)
├── routing: select_experts() → topk_weights, topk_ids
└── apply(x, topk_weights, topk_ids)
└── [Path 2] MK 内核:
prepare_finalize.prepare() # all2all dispatch
fused_experts.compute() # 专家前向
prepare_finalize.finalize() # all2all combine
_maybe_combine(shared_out, hidden_states)
├── [Path 1] → reduce_scatterv()
└── [Path 2] → no-op
完整调用链
_apply_quant_method() # moe_runner.py
└── quant_method.apply(x, topk_weights, topk_ids, ...)
└── self.moe_kernel.apply(x, w1, w2, ...) # modular_kernel.py
└── FusedMoEKernelModularImpl.apply()
├── _prepare()
│ └── prepare_finalize.prepare() / prepare_async()
├── _fused_experts() # w13 → act → w2
└── _finalize()
└── prepare_finalize.finalize() / finalize_async()
异步机制
MoE 的 async 机制利用 dispatch all2all 通信时间去做 shared expert 计算,通过 hook + receiver 解耦通信发起和结果等待。
单次 forward 内的 stream overlap
prepare_async():
1. 切到通信流
2. buffer.dispatch(x, topk_ids, ...) ← 发起 all2all (不阻塞)
3. 记录 handle
4. 切回计算流
5. return lambda: _receiver(event, ...)
_receiver():
1. event.current_stream_wait() ← 等 dispatch 完成
2. 修正 topk_ids (local→global)
3. return (a1q, a1q_scale, ...)
调用方先做 shared expert,需要 dispatch 结果时再调 receiver() 阻塞。
DBO(Dynamic Batching Overlap)
DBO 在 async 的基础上增加 micro-batch 粒度的调度,让通信和计算在更细粒度上重叠:
无 DBO: prepare_async → hook(shared expert) → receiver(wait) → compute → finalize
有 DBO: ubatch 0 prepare → dbo_yield → ubatch 1 compute ←→ ubatch 0 receiver
↑ ubatch 0 的 dispatch 和 ubatch 1 的计算被交错
async_finish = self.async_prepare and not dbo_enabled() 控制 DeepEP 内部是否自主管理同步。DBO 启用时,由 DBO 调度器接管同步控制。
量化方案
DeepSeek V3 FP8
DeepSeek V3 使用 FP8 block 量化(E4M3 数据,UE8M0 scale):
{
"quant_method": "fp8",
"fmt": "e4m3",
"scale_fmt": "ue8m0",
"weight_block_size": [128, 128]
}
权重量化是真正的 2D block quant:输出通道每 128 一组 × 输入通道每 128 一组。
激活(activation)量化在 prepare 阶段进行,使用 per-token per-group 方式(沿 hidden dim 每 128 一组),而非 2D block。这是因为 activation 按 token 独立量化,block_shape 的 [128, 128] 只用到第二个维度作为 group_size。
FP8 Dispatch
DeepEP Low-latency 后端支持 FP8 dispatch:在通信阶段将 BF16 数据量化为 FP8,传输后再恢复,通信量减半。
无量化: a1: BF16 → all2all BF16 → 2 bytes/element
FP8: a1: BF16 → quant FP8 → all2all FP8 → 1 byte/element
量化时机决策树:
prepare 中是否做 input quantization?
├─ FP8 block quant → dispatch 前量化(DeepEP 支持)
└─ 其他情况 → dispatch 后量化(DeepEP 不支持 per-tensor FP8 dispatch)
这与精度无关(量化是逐元素的),仅取决于 DeepEP 对 dispatch 数据格式的支持能力:DeepEP 只支持 block FP8 格式做 FP8 dispatch,不支持 per-tensor/per-channel。
DeepSeek V4 MXFP4(可选)
DeepSeek V4 额外支持 MXFP4(W4A8 OCP MX 标准):
| 组件 | 方案 | 细节 |
|---|---|---|
| 权重 | MXFP4(静态) | uint8 打包两个 FP4,block_size=32 |
| 激活 | MXFP8(动态) | per-tensor 动态 scale |
| 兜底 | FP8 或 BF16 | 取决于后端支持 |
专家映射与负载均衡
ExpertMapManager
管理 global expert ID ↔ physical/local expert ID 的映射。包含三个路由表:
global_to_physical:全局 expert ID → 物理 expert ID(所有 EP rank 拼接后的绝对位置)physical_to_global:物理 expert ID → 全局 expert ID(反向查找)local_global:local index → 全局 expert ID(当前 rank 的本 expert 编号)
放置策略
Linear(默认):
rank0: experts 0,1 | rank1: experts 2,3 | rank2: experts 4,5
映射关系 trivial,routing_tables = None。
Round-robin:
rank0: experts 0,4 | rank1: experts 1,5 | rank2: experts 2,6
需要 routing_tables 查表定位,用于 DeepEP LL 等后端的发送端寻址。
EPLB(弹性负载均衡)
通过冗余 expert 副本 + Triton kernel 动态负载重分布,消除 EP 热点,吞吐提升 20-30%。
性能优化汇总
| 优化点 | 收益 | 适用场景 |
|---|---|---|
| FP8 量化 (128×128 block) | 计算吞吐 +2x, 显存 -2x | SM90+ |
| FP8 Dispatch | 通信带宽 -2x | DeepEP LL / NIXL |
| DeepEP all2all | 比 AG+RS 延迟低 3-5x | NVLink 互联 |
| Async prepare/finalize | 通信完全 overlap | DeepEP / FlashInfer |
| Grouped topk | 路由计算量 -50%+ | DeepSeek V3 特有 |
| EPLB | 消除 EP 热点,吞吐 +20-30% | 负载不均衡场景 |
| Workspace 复用 | 显存节省 30%+ | 所有场景 |
| Weight 重排 | kernel 吞吐 +15-30% | Cutlass/DeepGemm |
| Sequence Parallel | MoE 计算量 / tp_size | TP > 1 |
总结
DeepSeek V3 的 MoE 模块在 vLLM 中的实现体现了高度工程化的设计:
- 分组路由:两级 top-k 选择,配合
e_score_correction_bias实现无辅助 loss 的负载均衡 - 通信-计算解耦:Modular Kernel 框架将通信和计算拆分为可独立替换的策略,避免组合爆炸
- 多层次并行:TP/EP/DP/SP/PCP 多维度并行,配合 async prepare/finalize 和 DBO 实现通信-计算重叠
- 极致量化:FP8 block quant 配合 FP8 dispatch,减少通信量一倍
- Oracle 智能选择:自动选择当前硬件和配置下的最优后端组合