type
Post
status
Published
date
May 4, 2026
slug
DeepSeek-v4-Parallel-comp-comm-overlap
summary
最近模型从 Dense 切到了 MoE,MFU 也相应地暴跌了,大家直觉上觉得 Expert 被切的很小,所以计算强度上不去,但实际切分完的维度至少也有 1024,MFU 暴跌的原因一定不来自这里。深入理解这个问题,就是理解 GPU 的分布式并行计算,要在计算和访存 bound 之外,引入通信 bound,而解决吞吐和 MFU 的问题的手段,就是设计合理的 GPU并行策略,做好 GPU 计算和通信的遮掩(overlap)。
DeepSeek 的 H800 和昇腾卡,8 卡 nvlink 高速互联,跨节点都是 IB(InfiniBand)低速网络,我们手里虽然有 B200,但实际也也没用上 NVL72,所以DeepSeek 的并行策略有普适的借鉴意义——硬件基础相似,低成本方案,新的 MoE 的方案也做了开源。
tags
Transformer
LLM
category
LLM
icon
password
priority
3
最近模型从 Dense 切到了 MoE,MFU 也相应地暴跌了,大家直觉上觉得 Expert 被切的很小,所以计算强度上不去,但实际切分完的维度至少也有 1024,MFU 暴跌的原因一定不来自这里。深入理解这个问题,就是理解 GPU 的分布式并行计算,要在计算和访存 bound 之外,引入通信 bound,而解决吞吐和 MFU 的问题的手段,就是设计合理的 GPU并行策略,做好 GPU 计算和通信的遮掩(overlap)。
DeepSeek 的 H800 和昇腾卡,8 卡 nvlink 高速互联,跨节点都是 IB(InfiniBand)低速网络,我们手里虽然有 B200,但实际也没用上 NVL72,所以DeepSeek 的并行策略有普适的借鉴意义——硬件基础相似,低成本方案,新的 MoE 的方案也做了开源。
DeepSeek 的并行策略
V4 重点讲了 EP 策略的计算和通信遮掩,没有细讲它的并行策略,它是延续DeepSeek-V3 的。
Our training framework is built upon the scalable and efficient infrastructure developed for DeepSeek-V3. In training DeepSeek-V4, we inherit this robust foundation
V3 披露的硬件是 2048 张 H800,8 卡节点内 nvlink 互联,并行策略是16-way PP × 64-way EP × ZeRO-1 DP。
这里先说下nvlink和 IB 的差异,nvlink下的 8 卡内速度可以到 900GB/s,而节点间的 IB 速度为50GB/s。EP 跨节点占用了 IB 带宽,这里是主要的通信bound,这里的每一份通信安排都至关重要,这也造就了 DeepSeek 的精妙的并行策略选择。
在展开更多细节之前,先搞清楚什么是GPU并行策略?
最朴素的并行策略就是 DP(Data Parallel,数据并行),每一张卡保存了全部参数,读不同的数据,做不同的计算,最后合并梯度做更新。在模型参数不大的年代里,这是最自然的并行方式。
模型开始变大,GPU 的显存装不下了,就要考虑怎么拆分存储,计算用的 inputs 和 weights不在一块 GPU 上,那么就要进行通信。
多大模型的参数,就要考虑做拆分了?几百B 的模型自然装不进一张 H100(80GB),那 10B 的模型呢?这就是一个经典问题,训练时模型的显存占用有多大。

显存里要放哪些东西?答案是参数/梯度/优化器状态/激活值。
一个 10B 的模型,在FP16混合精度下,参数是 2字节,那么就是 20GB 的存储;而梯度也是 FP16,那么又是 20GB 的存储;优化器的状态就复杂了,以 经典AdamW 为例子,一阶矩和二阶矩两个状态都要用 FP32 存,这就要2x4x10=80GB 了,再加一个 Master Weights,以 FP32 存储,那就是 4x10=40GB。所以,在不考虑任何激活值和系统占用的情况下,光是参数/梯度/优化器就 10x16=160GB 了。
再考虑上激活值,一个模型 3~5B 就要思考它在 朴素DP 之外的分布式并行策略了。

几种常见的策略:
- DP 基础上,计算不变,把存储拆分到多个 GPU 卡上,每卡只存一部分。如果只把优化器状态(约占参数 12 倍存储)做了拆分,这就是 ZeRO-1(Zero Redundancy Optimizer);把梯度也做了拆分,这就是 ZeRO-2;如果把模型参数也做了拆分,那这就是 ZeRO-3,也叫 FSDP(Fully Sharded Data Parallel)。
- TP(Tensor Parallel),是按参数的Tensor 做切分,放在不同的 GPU 上存储和计算。这里经常出现的混淆是,FSDP 也切分了参数,它和 TP 有什么区别?答案是FSDP 只是切分了存储,没有切分计算,它本身还是 DP,需要做前向计算的时候先把其他 GPU 上的参数 shard 拉回来,组成完整的 Tensor,和朴素 DP 一样做前向的计算,而 TP 则是同时也拆分了计算,不同的 GPU 读的是相同的数据,做了不同 shard Tensor 的计算,再通信合并计算结果。TP 的特点是通信量大,适合放在 nvlink 域内。
- PP(Pipeline Parallel),它是最好理解的,Transformer 的不同 Layers 拆到不同 GPU 上做计算,这些 GPU 形成一条流水线,这就自然地按层拆分了存储和计算。它的通信量小,适合跨节点。
- EP(Expert Parallel),它是 MoE 模型的标配。它实际和 TP 有一点像(都是参数拆分存储和计算),Expert 是天然拆分的,放在不同的 GPU 上存储参数,在计算时,token 路由到对应的 GPU 完成Expert 的计算,然后再把结果 Combine 回来。通信量也重,DeepSeek 的关键优化就是怎么能在 IB 网络上把 EP=64 跑明白。
- CP(Context Parallel),在Attention 内部沿 seq 切激活,每张卡算一段的 QKVO,Attention 的时候做跨 GPU 通信。V3 中没有提到,V4 中1M 上下文装不下,做了 sequence 维度的切分,一般出现在预训练的 long context 阶段或 post-train 中。
多种并行策略可以叠加吗?
如果你有 N 块 GPU,上面的各种并行策略是正交的,它们可以叠加,比如基础的 3D 并行是 DP x TP x PP,并且是 DP x TP x PP = N。EP特殊,它可以寄生在 DP 之上,就是可以共用卡。比如一个 5D 并行:N=DP_total x TP x PP x CP, 其中 DP_total = EP x DP_replica, DP_replica代表模型权重完全复制的组数。
再看下 DeepSeek 的例子,2048 张 GPU,PP = 16,EP = 64,实际 DP_total = 128,DP_replica = 2. 就是模型实际就 2 个完整副本,内部做 EP,GBS(global batch size) = MBS(micro-batch size) x DP_total x grad_accum_steps。
EP 能和 DP 共用卡,是个特例。EP 是唯一一个"在 forward pass 内部把 token 重新换主"的并行维度——它通过 all-to-all 让 token 临时离开自己的 DP rank、被另一组卡处理、再送回来。
假如教室是 GPU,每个学生(数据)有自己的教室,每个班主任(Expert)有自己的教室,它同时作为选修课老师给所有教室的学生上课,那就是上课的时候让学生重组下教室,下课的时候他们再回去。TP 为什么不行,它实际要求所有老师合上一节课,又不能离开自己的教室,学生必须要分身去上课了;EP 可以是因为它的MoE稀疏性和 Expert 的独立性。
先让 EP 在 IB 网络上跑起来
EP 策略包括 dispatch、Expert 计算、Combine 三个串行流程,dispatch 是把 token 通过 all-to-all 给到所在专家的 GPU 上,完成计算后,Combine把结果用 all-to-all 传回来。为了使得节点间通信不爆炸,它在做专家选取的时候,限制只能在平均最优的4个节点内选8个专家,使得跨节点通信次数减少,但这并不是最优的专家选择,而在V4中则取消了这个限制。
为什么这么做可以限制 IB 上的通信量呢?如果 top-k=8,然后这8个专家又恰好在8个不同的节点里,那么所有的通信走的都是IB 网络。限制了最多4个节点,那么平均每个节点要路由到2个 GPU,它可以在 IB 网络上归并传输的信息,先交给目标节点里的一块 GPU,再由它通过 NVlink 转发到对应的GPU,把 IB通信量转成 NVlink 通信量,就是降低了通信的时长,这里争取的通信时长越低,后续 EP 的计算通信遮掩就变得越容易。
DP ZeRO-1 和 EP/PP 的组合

因为 Transformer 是天然分层的,DP 的计算和通信天然可以遮掩。ZeRO 本质是切参数,计算都发生在当前 GPU 上,这是天然可遮掩的条件。
- DP:反向传播时,在计算前一层的同时,可以把当前层刚算出的梯度做 all-reduce。
- ZeRO-1/2,因为优化器和梯度是分片的,做reduce-scatter把自己梯度 shard 做更新,然后更新优化器状态,权重更新后做一次 all-gather更新权重。
- ZeRO-3/FSDP,是每次前向都做一个 all-gather,但可以在算上一层的时候,all-gather 拉下一层的参数。
DP 选择了 ZeRO-1,而非 FSDP/ZeRO-3 或 ZeRO-2,这背后的考量是避免和 EP 抢占 IB 带宽。首先 ZeRO-3 每次前向都要all-gather 取到权重参数,一次 micro-batch 的通信量就是参数量(GB 级别),这和 EP 的 forward 直接形成了 IB 带宽抢占。ZeRO-2 GPU只保留部分梯度,那梯度累积的时候就不能像 ZeRO-1 那样只是本 GPU 累加,而是要reduce-scatter通信,通信量也是参数量(GB 级别),和 EP 的 backward 抢占 IB 带宽。
而 ZeRO-1,在非优化器step 是没有通信的,这和DDP 一样;优化器步骤做更新只能更新本 GPU 的参数,因而需要做一次 all-gather 才能拿到正确的参数。由于 DP 和 ZeRO 本来就要在优化器步做一次all-reduce把梯度累加,all-reduce 可以拆成reduce-scatter和all-gather,那在reduce-scatter后每一个shard 优化器对应的梯度都是对的了,完成参数更新后,再 all-gather 一次参数即可,那么原本梯度的 all-gather 替换成了更新后的参数 all-gather,ZeRO-1 的通信量和普通 DP 一模一样,却省了接近12倍参数的显存,这就是 ZeRO-1 是近乎免费的原因。DeepSeek 选择把宝贵的 IB 带宽留给了 EP 的通信。

EP 的 all-to-all 操作, 通信量是 B x L x seq_len x top-k x hidden_size x 4。其中 forward 和 backward 分别有两次 all-to-all。这个几乎把 IB 通信占住了,通信量打到了 IB 带宽的同量级。
选 PP 也很自然,H800 是 8 卡互联,跨节点通信速度从 900GB/s 的 nvlink 降低到 50GB/s 的 InfiniBand,PP 的通信量小(B x seq_len x hidden_size x 2),适合跨节点,也避免了抢IB 带宽。
综合看,PP+EP+DP ZeRO-1,没用 TP,没有 ZeRO-2/3,避开了在每一个 micro-batch 上去抢占EP 的 宝贵 IB带宽,使得整体的并行策略能够在低配硬件下顺利进行。
PP 的气泡挤压
PP 的通信量很小,所以不存在遮掩问题;它真正的问题是要等反向计算而产生的流水线气泡。上图为最朴素的 PP——GPipe,这个方案已经废弃了,只是为了说明气泡问题。

1F1B(1 Forward 1 Backward) 的策略是在做完 F0,直接接一个 B0,开始交替一次 forward 一次 backward,实际并不能减少气泡,但是由于激活可以更早丢掉,那么显存占用更小,可以增大 micro-batch数M变相增大了计算比例,挤压了气泡。GPipe 和 1F1B 的气泡占比都是 (P-1) / (M+P-1),P 是 PP 数,M 是一个 step 的 micro-batch 数。
ZB1P(Zero Bubble PP)的解决方案是在 1F1B 基础上,把每一层反向计算做一个拆解,反向计算是根据 dy 来计算 dx 和 dw 的过程,前一层之所以不能开始计算,是因为它依赖 dx,那么先把 dx 计算出来,往回挤压气泡,把 dw 的计算留到气泡产生时发生。但也因为要延迟计算 dW = x^T · dy,它依赖的输入 x(也就是激活值)不能立即释放,相当于用一些显存的占用换了计算。
DualPipe:挤压气泡同时搞定 EP 的通信计算遮掩

DeepSeek-V3 就引入了 DualPipe 方案,它是在ZB1P基础上,在 PP 上形成两条反向的 micro-batch,使得 Forward 和 Backward 恰好把计算和通信错开,挤压气泡的同时把 EP 的通信遮掩到了计算背后。
EP 的计算和通信的流程是串行的,forward 的时候通过一次 all-to-all 把 token 的 hidden 路由到对应专家的 GPU(dispatch),完成计算,然后把结果用一次 all-to-all 再发回原GPU(combine),也是天然不可遮掩。EP 吃了最大头的 IB带宽, DeepSeek V3 和 V4 都在讲它的通信和计算时间接近 1:1,能不能把通信遮掩到计算背后就成了关键。
每一个 rank 持有两份参数,也就是 micro-batch 可以从 rank0 流到 rank3,反之也可以从 rank3 流到 rank0. 每一个 step 开始,双向做 forward,当双向第一个 Backward 到来后,它与逆向的 forward 发生了交叠。交叠处,一个正向的 [attention, dispatch, MLP, combine] 与一个逆向的同样四步发生了计算和通信的相互遮掩。DualPipe 的副作用就是显存占用增加了一倍,PP+EP+ZeRO-1 已经把显存占用切到很小了,V3 paper 说这可以接受。

具体的实现上,H800 共 132 个 SM,划出 20 个 SM 专门做通信,剩下的给计算。传统 NCCL 的工作模式是 SM-shared:通信 kernel 和计算 kernel 共享 SM 池,每个 kernel 启动时按需占用一些 SM。这 20 个 SM 跑的是 DeepSeek 自己写的 PTX 级通信 kernel,不是 NCCL。
V4 的 Waved-EP 通信计算遮掩
Waved-EP 是 DeepSeek-V4 提出的新 EP 计算通信遮掩方案,一个 kernel 直接在 MoE 层解决问题,不再依赖 PP 调度了,它思路很简单:直接把 Expert 切成几个 wave,在不同 wave 之间做通信遮掩。
既然DualPipe 已经能够遮掩掉EP 阶段的 all-to-all 通信,那为什么还要做Waved-EP的新 kernel 呢?论文给的答案是,在小 batch 的RL 或推理情况下,DualPipe 就不够用了。原理上推理就没有 Backward,那也就无法和 Forward 做相互一一对应的通信遮掩了。所以对比baseline(Comet),RL 场景下1.96x加速,通用场景下1.50 ~ 1.73×。当然,论文并没有对比 DualPipe 的遮掩,因为V3 也是 100% 遮掩,大 batch 场景下应该差不多。

为什么 DualPipe 依赖大 Batch?PP 在 1F1B 基础上做交叠,可以大致分成 3 个阶段:warmup,全 F,没有 B 配对;稳态,F+B overlap;cooldown,是纯 B/W 排空。warmup 阶段只有 F,cooldown 阶段只有 B,那就无从遮掩通信,F和F/B和B 交叠下,通信和计算没法交错,也无法遮掩。
DualPipe 的Forward 和 Backward 遮掩,就发生在稳态阶段,稳态的长度依赖于 M(micro-batch 的数量),batch size=M x micro-batch x DP。所以RL或 Long Context这种小 batch 下,M 过小,稳态过短,遮掩的效果就大打折扣。
DeepSeek V4 的方法,是一个 kernel 直接在 MoE 层解决问题,不再依赖 PP 调度了。它是把 Expert 分成几组,每组一个 wave,dispatch 确保第一个 wave 通信完成,就开启计算,同时第二个 wave的 dispatch 也在进行,算完了就直接 Combine,每一个 wave 内串行,但 wave 间的 dispatch/L1+Act+L2 计算/Combine 就可以并行起来了。他是 kernel 级别的方案,那么就无所谓训练还是推理,大 Batch 还是小 Batch,更多地依赖于细粒度专家的模型设计,wave 过少第一个dispatch 和最后一个 Combine 暴露无法遮掩。

这个 kernel 是用 TileLang 框架完成的,这么精细化的通信和计算的控制,triton 是很难完成的。以下是 Claude 的评价:
Triton 不是为通信和计算融合设计的,它的核心抽象是「单 GPU 内部的高性能 GEMM/element-wise kernel」,对跨 GPU 通信原语(nvshmem、IB send/recv)支持很差或没有。Waved-EP 这种 mega-kernel 要把 dispatch (NVSHMEM put/get) + GEMM + combine 融在一个 kernel 里,Triton 根本写不出来。 TileLang 的优势不只是「更容易控制通信遮掩」,而是 它能写出 Triton 写不出来的 kernel。这是质的差别,不是程度差别。 TileLang 是 V4 论文 §3.2 自己介绍的工具(论文引用 Wang et al., 2026)。它的设计哲学跟 Triton 不一样 —— 既要 Triton 那样的高生产力 DSL,也要保留 PTX/CUDA 级的底层控制权。
DeepSeek 会通过极致的并行策略设计和 kernel 级别的通信遮掩,8 卡节点+IB 网络也能玩转 1T 以上模型,甚至建议厂商不要一味地堆通信带宽,而是看GPU 在计算和通信遮掩时的总功率是否能支撑,导向是硬件对计算和通信并行做更好的支撑。
而Nvidia 的发展路径就是通过 NVlink 连接更多的卡,GB200 是 72 卡互联,明年 Rubin 的 Ultra 是NVL576。让 GPU 并行时更容易做出 5D 并行,带宽足够快,把 N 块 GPU 当成一个整体来用。
我也很感慨,上次看到评论区有人瞧不上 LLM 的“力大砖飞”,实际上我觉得在这种极致的工程能力下,在计算和通信上的平衡堪称艺术,比那种模型结构的奇技淫巧要牛的多。
还有一些没写到的
- 引入Muon 后,ZeRO-1 没法切元素了,如何按矩阵做拆分。
- DualPipe-V,虽然 DeepSeek-V4 没明确引入,这个方法可以把 DualPipe 冗余的参数去掉,把激活值恢复到 1F1B 的 1 倍量。
- CP 没讲,这在 V4 里和 Attention 压缩(MLA/NSA 等)是配合使用的。