Lecture 8:从 DDP 到 4D 并行
Stanford CS336 Language Modeling from Scratch | Spring 2026 | Lecture 8: Parallelism,时长 01:20:10。
为什么需要并行化:计算与内存的双重瓶颈#
大规模语言模型训练面临两个根本性瓶颈,正是这两个瓶颈驱动了我们对多 GPU、多节点乃至多数据中心并行化的需求。
计算瓶颈:单块 GPU 的算力远不足以支撑前沿模型的训练需求。当今最快的超级计算机拥有 exaFLOPS 级的总算力,而单块 GPU 距离这个数字差距巨大。要在合理的时间内完成训练,必须将大量机器连接在一起,聚合它们的计算能力。
内存瓶颈:模型规模已经远超单卡显存容量。一个模型的参数本身只是内存占用的一部分——使用 Adam 优化器时,还需要存储梯度、FP32 master weights、一阶矩估计和二阶矩估计。粗略估算,每个参数大约需要 16 字节(约 5 份权重拷贝)的存储空间。这意味着即使不考虑激活值,一个 7.5B 参数的模型仅优化器状态就需要约 120GB 内存——已经超出了单卡 80GB 的 A100。
这两个瓶颈共同决定了并行化不是可选项,而是大规模训练的必要条件。
在多机并行的场景下,一个关键的概念性区分是 节点内并行(intranode)与 节点间并行(internode)。节点内的 GPU 通过 NVLink 等高速互连紧密连接,通信带宽极高,因此可以承受通信密集型的并行策略。而节点间通信则依赖 InfiniBand 等相对较慢的网络,必须使用对带宽更友好的并行方案。
现代并行训练的核心思想:新的计算单元不再是单块 GPU,而是整个数据中心。我们需要同时控制可用的内存总量和可用的计算总量,并且所有这些资源的利用都应当是”无损”的——充分利用每一份硬件资源。
所有并行策略的讨论都建立在集合通信原语(collective communication primitives)的层面上——all-reduce、reduce-scatter、all-gather 等操作。一个贯穿全文的重要等价关系是:
all-reduce≡reduce-scatter+all-gather
这个等价性意味着两者的通信代价相同,而这一看似简单的数学事实将在后续的 ZeRO 优化中扮演核心角色——它使得若干内存优化策略在通信层面完全”免费”。
硬件网络拓扑:TPU 环形网格 vs GPU 胖树 vs 华为 Ascend#
尽管并行算法本身大多是硬件无关的,但不同硬件的网络拓扑结构会深刻影响最优的并行策略选择。
TPU:Toroidal Mesh#
Google 的 TPU 采用的是环形网格(toroidal mesh)拓扑。可以将其想象为一个网格(grid),其中边缘节点首尾相连,形成环面结构。实际上是一个 3D 的拓扑,但核心思想很简单:每个芯片只与固定数量的近邻通信,且无论网络规模多大,每个节点的邻居数量保持不变。
这种设计的优势在于可以非常简单地无限扩展——增加节点不会改变单个节点的连接复杂度。每条连接都可以做得更”粗壮”(更高带宽),因为不需要支持全连接。但代价是,如果通信模式是随机的、不可预测的(如 MoE 中的 token 路由),这种拓扑就不太高效。
GPU:Fat Tree(胖树)#
NVIDIA GPU 集群采用的是胖树拓扑,体现的是一种 all-to-all 的设计哲学。在最底层,同一节点内的 GPU 通过 NVLink 以极高带宽直连;节点之间通过 InfiniBand leaf switches 互联;更上层则有 spine switches 连接不同的 pod。

这种树状结构的优势是灵活性——任意两个 GPU 都可以通信。但随着节点数增长,树越来越大,通信代价也越来越高,或者拓扑变得越来越复杂。
设计哲学的分歧与趋势:TPU 擅长近邻通信场景(如 tensor parallel 中可预测的矩阵分区通信),GPU 擅长随机通信场景(如 MoE 中 token 路由到不同 expert)。Bill Dally(NVIDIA)和 Jeff Dean(Google)都曾讨论过这一差异:GPU 更适合 MoE 等通信模式不确定的工作负载,TPU 更适合稠密模型的可预测分区。
然而,一个有趣的趋势是趋同演化。就在这堂课的当天早晨(2026 年 4 月 22 日),Google 发布了 TPU v8i 和 v8t。令人意外的是,TPU v8i 采用了树形拓扑——这与传统 TPU 的 mesh 设计截然不同,向 GPU 的 all-to-all 哲学靠拢。原因很直接:现代语言模型大多是 MoE,推理时需要大量不可预测的 token 路由通信,all-to-all 连接在这种场景下更高效。训练芯片 TPU v8t 也引入了名为 Virgo 的更高层网络栈,跨机架连接同样更接近 GPU 的 all-to-all 风格。
华为 Ascend 910:暴力全连接的极端案例#

如果把 all-to-all 的思路推到极致——把所有芯片都用高速光纤全连接——就得到了华为 Ascend 910 的设计方案。这里有一个有趣的类比:之前 GPU 讲座中有人问”SRAM 这么好为什么不全用 SRAM?“——答案是 Grok,它确实这么做了,效果也不错。同理,“全连接这么好为什么不全连接?“——答案就是华为 Ascend 910。单看芯片规格,Ascend 910C 在 matmul 速度上显著弱于 NVIDIA H200(BF16 仅有 0.3x),HBM 容量和带宽也不占优。但通过将 384 块芯片在一个大型机柜内用光纤交换机全连接,华为选择用更多的弱芯片来弥补单卡性能的不足。
代价是惊人的:整个系统的功耗约为等价 NVIDIA 系统的 4 倍。这揭示了一个深刻的硬件设计权衡——如果愿意付出功耗代价,可以暴力解决通信问题,实现更激进的 scale-out。这与之前 SRAM vs HBM 的讨论异曲同工:追求极致效率会落在一个设计点,追求暴力堆叠会落在完全不同的设计点。
数据并行(DDP):最朴素的并行策略#
数据并行是最简单直观的并行化方案。假设使用朴素 SGD(暂不考虑 Adam),有一个大小为 B 的 batch,参数更新公式为:
θt+1=θt−η∑i=1B∇f(xi)
最朴素的并行化方式是:将 batch 切分到 M 台机器上,每台机器处理 B/M 个样本,各自计算梯度,然后通过 all-reduce 同步梯度求和。
计算扩展:完美线性扩展。只要每块 GPU 上的样本数量足够,计算效率与单卡一致。
通信开销:每个 batch 需要通信 2×∣θ∣(参数量)的数据。这是一次 all-reduce 操作的代价——将所有 GPU 的梯度求和后广播回每块 GPU。当 batch 足够大时,通信可以被计算掩盖。
内存扩展:完全没有。每块 GPU 都持有完整的模型副本——参数、梯度、优化器状态全部复制。内存消耗与 GPU 数量无关。
这就是 DDP(DistributedDataParallel)的本质。它解决了计算瓶颈,但完全没有触及内存瓶颈。一个 7.5B 的模型在使用 Adam 时需要约 120GB 的 per-GPU 内存(16 字节/参数),单卡 80GB 的 A100 根本装不下。
数据并行的核心限制:解决了计算扩展问题,但内存占用不随 GPU 数量降低——每个 GPU 仍然需要完整存储所有参数、梯度和优化器状态。
ZeRO 优化:从 Stage 1 到 FSDP 的免费午餐#
朴素数据并行的内存问题源于冗余——每块 GPU 都存储了完整的参数、梯度和优化器状态。ZeRO(Zero Redundancy Optimizer)的核心洞察是:通过 reduce-scatter 与 all-gather 的等价性,可以将这些冗余数据分片存储到不同 GPU 上,而不增加额外的通信代价。

上图展示了从 Baseline 到 ZeRO Stage 3 的内存变化。以 K=12、Ψ=7.5B、Nd=64 为例:Baseline 需要 120GB,而 ZeRO Stage 3 仅需 1.9GB/GPU。三种颜色分别代表参数(蓝)、梯度(橙)、优化器状态(绿),可以清楚看到优化器状态占据了内存的大头。
ZeRO Stage 1:分片优化器状态#
Stage 1 的想法最简单:只将优化器状态分片到不同 GPU 上。每块 GPU 负责更新一个参数切片——GPU 0 只维护第一个切片的一阶矩、二阶矩和 master weights。
工作流程如下:(1) 每块 GPU 在自己的数据上计算完整梯度;(2) 通过 reduce-scatter 将梯度分发——每块 GPU 只接收自己负责的参数切片对应的梯度之和;(3) 各自更新负责的参数切片;(4) 通过 all-gather 收集更新后的参数,使每块 GPU 恢复完整参数。
关键问题:通信代价是多少?朴素 DDP 做了一次 all-reduce,代价为 2∣θ∣。ZeRO Stage 1 做了一次 reduce-scatter 加一次 all-gather。但根据前面提到的等价关系 all-reduce≡reduce-scatter+all-gather,两者的通信代价完全相同。
ZeRO Stage 1 是免费的内存优化——用 reduce-scatter + all-gather 替换 all-reduce,通信量不变,但优化器状态的内存从 K⋅Ψ 降到了 K⋅Ψ/Nd。
ZeRO Stage 2:分片梯度#
Stage 2 进一步将梯度也分片存储。难点在于:前面依赖”先计算完整梯度再分发”,现在连完整梯度都不想存了。
解决方案是一个系统层面的 trick:在反向传播过程中,每计算完一层的梯度,就立刻通过 reduce 将该层梯度发送给负责的 worker,然后释放本地的梯度内存。换言之,梯度是增量计算、增量发送的,而不是全部计算完再一次性同步。增量处理和一次性处理的总通信量完全相同,因此 ZeRO Stage 2 依然是免费的。
ZeRO Stage 3 / FSDP:分片一切#
最激进的方案是连参数也分片——每块 GPU 只持有参数的一个切片。这就是 ZeRO Stage 3,也称为 FSDP(Fully Sharded Data Parallel)。
此时每块 GPU 在任意时刻只能看到参数、梯度和优化器状态的一个切片。前向和反向计算都需要”按需获取”参数:
- 前向:对每一层,先 all-gather 该层的参数 → 计算前向 → 释放参数
- 反向:再次 all-gather 该层参数(因为前向时已释放)→ 计算反向 → reduce-scatter 梯度 → 释放参数
- 更新:在本地更新负责的参数切片
总共做了两次 all-gather 和一次 reduce-scatter,比朴素 DDP 多了一次 all-gather(∣θ∣ 的额外通信)。看起来代价不低——而且每一层都需要通信,似乎开销会很大。
但 FSDP 利用了两个关键机制使其在实践中几乎免费:
机制一:增量处理与即时释放。与 Stage 2 相同,逐层处理并立即释放不再需要的数据。
机制二:通信与计算重叠(communication-computation overlap)。这是 FSDP 性能的核心。

上图展示了 FSDP 的实际执行时序。GPU 有两个独立的流:计算流(GPU Comp. Stream)和通信流(GPU Comm. Stream)。在计算第 i 层的前向时,通信流同时在 all-gather 第 i+1 层的参数。只要通信速度快于计算速度(即模型每层的计算量足够大),通信就可以被完全掩盖在计算之下。
实践中的表现非常惊人:FSDP 的 GPU 利用率可以非常接近单卡性能。在 8 卡 A100 80GB 上,Baseline 甚至无法装下 7B 模型,而 ZeRO Stage 3 可以装下 50B+ 参数的模型。
通信代价汇总#
| 策略 | 通信量 | 内存(per GPU) |
|---|---|---|
| 朴素 DDP | $2 | \theta |
| ZeRO Stage 1 | $2 | \theta |
| ZeRO Stage 2 | $2 | \theta |
| ZeRO Stage 3 / FSDP | $3 | \theta |
Stage 1 和 2 在通信上是字面意义上的免费;Stage 3 多了 ∣θ∣ 的通信,但通过 overlap 可以基本抵消。FSDP 的内存节省则是压倒性的——从 120GB 降到 1.9GB/GPU(Nd=64 时)。
课程作业要求实现一个 FSDP wrapper:对任意 PyTorch module 做 all-gather → compute → free → 反向时再 all-gather → reduce-scatter → free 的循环。概念上并不复杂,但实现上需要仔细处理内存管理和通信调度。
Pipeline Parallel:按深度切分模型与消除 Bubble#
FSDP 虽然优雅,但它有两个无法回避的局限。第一,数据并行消耗的是 batch size 这一宝贵资源——如果 batch size 只有 8,最多只能用 8 块加速器;而 batch size 不能无限增大,因为存在 critical batch size,超过这个临界点后,增加 batch 元素带来的收益不如多做一步 SGD。

上图展示了训练速度(纵轴)随 batch size(横轴,归一化到 noise scale)的变化:在 critical batch size 之前是 perfect scaling(线性加速),之后进入 ineffective scaling 区域(收益递减)。这意味着数据并行的扩展能力受限于优化动力学。
第二个局限是 FSDP(尤其是 Stage 1/2)不减少激活内存。即使参数和优化器状态被分片了,每块 GPU 仍然需要存储完整的前向激活值用于反向传播。
这两个问题共同推动了模型并行的引入——将模型本身切分到不同 GPU 上。与数据并行不同,模型并行传递的是激活值而非参数。
朴素 Pipeline Parallel 与 Bubble 问题#
Pipeline parallel 的思路极其简单:把模型按层切开,不同层放到不同 GPU 上。前向时依次传递激活值,反向时依次传递梯度。
但朴素实现会导致灾难性的低利用率:以 4 块 GPU 为例,GPU 0 处理完第一层后就空闲了,等待 GPU 1、2、3 依次处理完。反向传播时同理。大部分时间里,GPU 处于闲置状态——这些空闲区域叫做 bubble。
解决方案是微批次流水线(micro-batching):将一个大 batch 切成多个 micro-batch,一个处理完就立刻开始下一个,同时将前一个传递给下一个 stage。

上图展示了 4 个 stage、4 个 micro-batch 的流水线调度。Fi,j 表示第 i 个 stage 处理第 j 个 micro-batch 的前向,Bi,j 表示反向。bubble 区域被大幅压缩——bubble 比例约为:
bubble ratio≈nmicronstages−1
因此需要大 batch size 来生成足够多的 micro-batch,从而将 bubble 压到接近零。这再次印证了 batch size 是一种宝贵资源——它可以被”花费”在 pipeline parallel 上来提升利用率。
Pipeline Parallel 的通信优势#
Pipeline parallel 的一个重要优势是通信量小且是点对点的。每次通信只传递一层的激活值,大小为 b×s×h(batch × sequence length × hidden dim),这几乎总是远小于传递整个参数矩阵。而且通信只发生在相邻 stage 之间(point-to-point),不是 all-to-all。
因此在实际部署中,pipeline parallel 通常被分配到最慢的网络链路上——跨 pod、跨数据中心的慢速连接。因为它对带宽的需求最低,能最好地适应慢速链路。
Zero-Bubble Pipelining#
业界进一步发展出了更精巧的调度策略来进一步缩小 bubble。其中最精妙的想法来自对反向传播结构的深入分析。
反向传播在每个计算节点实际上做两件事:(1) 将偏导数向计算图的前方传播(propagate partials)——这是 pipeline 中的关键路径,下一个 stage 必须等待这个信号;(2) 计算当前权重的梯度(compute ∇W)——这是一个叶子节点操作,可以在任何时候做。
Zero-bubble pipelining 的核心思想是将这两个操作解耦。把反向传播拆成 B(propagate backwards,关键路径)和 W(compute weight gradients,可延迟)两个阶段。优先执行所有 B 操作以尽快释放 pipeline 中的下游 stage,然后在空闲时间填入 W 操作。这样可以几乎完全填满 pipeline,大幅减少甚至消除 bubble。
实现上这比标准 pipeline parallel 复杂得多,但效果非常显著。DeepSeek 的 V3 训练就使用了类似的精巧调度策略。
Tensor Parallel:按宽度切分矩阵乘法#
如果说 pipeline parallel 是按深度切分模型(切层),那么 tensor parallel 就是按宽度切分——将单个矩阵乘法分解为多个更小的矩阵乘法。
核心原理#
矩阵乘法天然支持分块计算:将矩阵 X 按列切分为 X1,X2,对应矩阵 A 也按行切分为 A1,A2,则 Y=X⋅A=X1⋅A1+X2⋅A2。每个子矩阵乘法可以在不同 GPU 上独立计算,最后对部分和做 all-reduce 即可。

Transformer 中的 Tensor Parallel#
在实际的 Transformer block 中,tensor parallel 的切分遵循特定模式。以 MLP 为例(z=GeLU(xA)⋅B):
- 列切分(column-wise)应用于上投影矩阵 A:将 A 按列切成 A1,A2,输入 x 被复制到两块 GPU 上。每块 GPU 独立计算 GeLU(x⋅Ai)。这里有一个精巧之处——GeLU 是逐元素非线性,可以在 split 之后独立应用,不需要全局通信。
- 行切分(row-wise)应用于下投影矩阵 B:将 B 按行切分为 B1,B2,每块 GPU 计算部分结果,最后通过 all-reduce 求和得到最终输出 z。
对于 attention 层类似:QKV 投影是列切分,输出投影是行切分。注意力头天然可以按头分到不同 GPU。
前向-反向的对偶性#
Tensor parallel 中存在一个重要的前向-反向对偶关系。定义两个算子 f 和 g:
- 前向:f 是 identity(复制输入),g 是 all-reduce(合并输出)
- 反向:fˉ 是 all-reduce(合并梯度),gˉ 是 identity(直接传递梯度)
即前向时在输出端做 all-reduce,反向时在输入端做 all-reduce。这种对偶在实现 tensor parallel 时必须正确处理。
通信代价与适用场景#
Tensor parallel 的通信非常密集:每个 matmul 操作都伴随一次 all-reduce(前向或反向),通信量是激活大小 a×b×s×h(a 是每个 transformer block 中的 matmul 数量)。这是 all-to-all 通信,而不是点对点。

上图清楚展示了 TP 度超过 8 后吞吐量的急剧下降:TP=8 相对 TP=2 下降 10.8%,TP=16 下降 42.7%,TP=32 下降 65.6%。原因很直观:TP=8 对应同一节点内 8 块 GPU 通过 NVLink 通信(~900 GB/s),而 TP=16 需要跨节点通过 InfiniBand 通信(~50-100 GB/s),带宽落差一个数量级。
经验法则:Tensor parallel 限制在 NVLink 域内(通常 TP ≤ 8)。超出单节点后,应使用 pipeline parallel 而非增加 TP。
TPU 的例外#
TPU 是个有趣的例外。由于 TPU 的 mesh 拓扑在所有连接上提供相对均匀的带宽(没有 NVLink 内/InfiniBand 外 的断崖),TPU 用户可以将 tensor parallel 扩展到远超 8 的规模。这也是为什么 Google 的模型(如 Gemma 2)往往只用 FSDP + tensor parallel,不需要 pipeline parallel。
Tensor Parallel vs Pipeline Parallel 对比#
两者都是模型切分策略,都能节省参数内存和激活内存,但特性截然不同:
| Tensor Parallel | Pipeline Parallel | |
|---|---|---|
| 切分方式 | 按宽度(切矩阵) | 按深度(切层) |
| 通信量 | a×b×s×h(all-reduce) | b×s×h(point-to-point) |
| 通信模式 | All-to-all | Point-to-point |
| 利用率 | 无 bubble,但需快速网络 | 有 bubble,需大 batch 消除 |
| 实现复杂度 | 低(只是切 matmul) | 高(调度逻辑复杂) |
| 适用链路 | 最快互连(NVLink) | 较慢互连(跨节点/跨 pod) |
Sequence Parallel 与激活内存的精细控制#
激活内存:被低估的内存大户#
很多人对深度学习中的内存有一个朴素认知:内存 ≈ 参数。但实际情况远比这复杂。

上图是一次真实训练的 PyTorch memory profiler 输出。底层绿色是参数(静态),黄色是优化器状态(静态),但上方巨大的红色波峰是激活值——在前向传播中积累、在反向传播中逐步消耗。蓝色波峰是梯度。内存的峰值发生在前向结束后开始反向时——此时激活值还没释放,梯度已经开始累积。
对于较大的模型和较长的序列长度,激活内存会远超参数内存。因此任何内存优化策略如果不处理激活,效果都是有限的。
激活内存的精确计算#
不做任何并行时,每个 Transformer 层的激活内存为:
Activation=sbh(34+5has)
其中 s 是序列长度,b 是 batch size,h 是 hidden dimension,a 是注意力头数。第一项 34sbh 来自 MLP 和 attention 中的各种中间结果(输入、输出、残差等),第二项 5has⋅sbh 来自注意力的二次项(softmax 矩阵和 dropout mask)。
Tensor Parallel 对激活的影响#
Tensor parallel 能有效降低部分激活内存。MLP 的中间激活(占 34 中的 24)和 attention 头的激活(5as/h 项)都可以被 TP 度 t 除以——因为这些计算本身就被分到了不同 GPU 上。
但有一个棘手的残余:layer norm 的输入、attention/MLP 模块的输入等需要作为残差连接保留的激活值,tensor parallel 不会减少它们。这些”逐点操作”的激活占据了 34 中的 10,无法被 TP 分片。
这意味着即使有 1000 块 GPU 做 tensor parallel,每块 GPU 仍然需要承担 10⋅sbh 的不可约减激活内存。
Sequence Parallel:分片不可约减的激活#
Sequence parallel(注意:这个名字容易与 context parallel 混淆,后者是完全不同的概念)是解决上述残余激活的方案。
思路与 FSDP 类似:既然 layer norm 等操作的激活需要保留但不立即使用,那就将它们沿序列轴分片存储到不同 GPU 上,需要时再 all-gather 取回。
具体地,在 tensor parallel 的并行区域之间(即 layer norm、残差连接等非并行操作),将激活沿序列维度切分到 t 块 GPU 上。进入 tensor parallel 区域前做 all-gather 恢复完整激活,退出时做 reduce-scatter 重新分片。
与 tensor parallel 类似,这里也存在前向-反向对偶:前向时 g 是 all-gather(恢复完整激活),gˉ 是 reduce-scatter;反向时相反。
激活内存优化的完整图景#
将各种策略叠加后的激活内存变化:
| 配置 | 激活内存 / 层 |
|---|---|
| 无并行 | sbh(34+5has) |
| Tensor parallel | sbh(10+t24+5htas) |
| Tensor + Sequence parallel | sbh(t34+5htas) |
| Tensor + Selective recomputation | sbh(10+t24) |
| Tensor + Sequence + Recomputation | sbh⋅t34 |
最后一行 sbh⋅34/t 是实践中可以合理达到的激活内存下界。selective activation recomputation 通过在反向时重新计算 attention 的 softmax(而不是存储),消除了 5as/(ht) 项。MLP 的重计算代价太高(相当于前向再算一遍),通常不做。
sbh⋅34/t 是估算模型能否装进 GPU 的关键公式。加上参数内存(2Ψ/Nd with FSDP)和优化器状态内存(KΨ/Nd),就能大致判断给定配置下的内存需求。
Expert Parallel:MoE 时代的并行新范式#
现代前沿模型大多采用 Mixture of Experts(MoE)架构,这为并行化带来了新的机会和挑战。Expert parallel 可以类比为 tensor parallel——都是将 FFN 组件分到不同设备上——但 MoE 的稀疏路由特性使其在系统行为上有显著不同。
为什么优先用 EP 而非 TP#
Megatron(NVIDIA 的并行化库)的官方指南明确建议:对于 MoE 模型,优先使用 expert parallel 而非 tensor parallel。理由有三:
- 矩阵尺寸:Tensor parallel 将矩阵切得更小,GPU 利用率会下降——GPU 的 matmul 效率在矩阵足够大时才能充分发挥。EP 不切矩阵,每个 expert 仍然是完整的 matmul。
- 通信效率:MoE 天然只需要路由被选中 expert 的 token 激活(稀疏的),而 tensor parallel 需要通信完整的稠密激活。路由稀疏 token 比通信稠密矩阵更高效。
- 避免冗余计算:如果已经有 MoE,expert 自然分布在不同设备上,额外做 TP 反而把已经分好的矩阵又切碎了。
EP 的系统挑战#
EP 的核心难度在于 all-to-all 通信的延迟敏感性。每次经过 MoE 层,token 需要被路由到可能位于任意 GPU 上的 expert,计算完后再路由回来。这是高频的 all-to-all dispatch,计算在等待 token 到达才能开始,因此减少 dispatch 延迟至关重要。
两个值得关注的系统实现:
DeepSeek DPP 库:DeepSeek V3 时代开发的 expert parallel dispatch 库。为了榨干最后一丝性能,DeepSeek 的工程师甚至找到并使用了未文档化的 PTX 指令(GPU 机器码层面的指令)来加速网络通信。这展示了前沿 MoE 训练的工程强度。
NVIDIA Hybrid EP 库:同样致力于低层级硬件优化的 expert parallel dispatch 实现。
EP 与 TP 的冲突#
一个微妙的复杂性在于:MoE 只改变 MLP,不改变 attention。这导致 expert parallel 对模型的作用是不均匀的——MLP 被 EP 分片了,但 attention 没有。
如果想并行化 attention,需要用 tensor parallel。但高 TP 和高 EP 叠加会把 MLP 的矩阵切得极碎,利用率很差。因此出现了一个矛盾:attention 需要高 TP,MLP 需要低 TP。
解决方案是解耦 attention 和 MoE 层的并行度。Megatron 的 MoE Parallel Folding 方案允许 attention 层使用一套并行配置(TP × CP × DP × PP),MoE 层使用另一套(ETP × EP × EDP × PP)。这增加了系统复杂度,但实现了更优的资源利用。
EP 与 DP 的约束#
朴素的 EP+DP 实现中,EP 的 replica 和 DP 的 replica 是同一组 GPU——先按 DP 分数据,再在 DP 内部按 EP 分 expert。这导致 EP 的最大并行度受限于 DP 组的大小。
现代方案打破了这个约束,允许 EP 跨 DP 组分片,但代价是更复杂的通信模式。DeepSeek V3 的 64-way expert parallel(跨 8 台机器)就是这种激进方案的代表——它借鉴了 pipeline parallel 的 pipelining 技巧来掩盖 EP 的通信延迟。
Context Parallel / Ring Attention#
最后简要提及 context parallel(也叫 ring attention):将长序列的激活沿序列轴分片到不同加速器,以环形传递的方式完成 attention 计算。它特别适合长上下文扩展阶段和模型服务。概念上与前面讨论的思路一致(按需获取、计算、传递),在 TPU 的 mesh 拓扑上尤其自然。
4D 并行组合策略与实践原则#
前面分别介绍了数据并行(DDP/FSDP)、pipeline parallel、tensor parallel、expert parallel 和 context parallel。没有任何一种策略是全局最优的——每种都有各自的优势和代价。实际的大规模训练需要将它们组合使用,这就是所谓的 3D 或 4D 并行。
没有绝对优势的策略#
FSDP 优雅高效,但不减少激活内存,且消耗 batch size 资源。Tensor parallel 不消耗 batch size 且能降低激活内存,但需要高速互连、通信密集。Pipeline parallel 通信最轻量,但有 bubble 问题、实现复杂。Expert parallel 对 MoE 模型效果好,但引入稀疏通信的额外复杂性。
批次大小是关键资源#
理解并行策略组合的关键在于认识到 batch size 是一种可消耗的资源。它可以被”花费”在:(1) 数据并行——更多 GPU 分摊数据;(2) pipeline parallel——更多 micro-batch 减小 bubble。两者竞争同一资源。

上图展示了一个 4×4×4 mesh 上三种策略组合的效率曲线。纵轴是 FLOPS time / Comms time(>1 即 compute-bound,是好的)。虚线是 computation bound 边界。
关键观察:batch size 足够大时(>850),纯 FSDP 就够了——通信完全可以被计算掩盖。当 batch size 减小到 400-850 之间,需要引入 MP(tensor parallel)来保持 compute-bound。当 batch size < 400 时,没有任何策略能实现 compute-bound——这是硬上限。
简单的实践处方#
尽管概念上看起来复杂,实际的并行化策略选择遵循一个非常清晰的处方:
Step 1:让模型装进内存。使用 tensor/expert parallel(限于 NVLink 域,通常 ≤ 8)和 pipeline parallel / FSDP 来切分模型,直到每块 GPU 上的份额能装进显存。
Step 2:用数据并行消耗剩余 GPU。模型能装下后,剩下的 GPU 全部用于数据并行。
Step 3:如果 per-GPU batch size 太小,使用 gradient accumulation 来增大有效 batch size,提升 GPU 利用率。
Megatron 的官方指南将这个处方细化为 5 条规则:
- 最小化模型并行,最大化数据并行
- Tensor/Expert parallel 保持在 NVLink 域内(单机 8 卡)
- 跨节点用 pipeline parallel
- MoE 模型优先用 expert parallel 替代 tensor parallel
- 长序列用 context parallel
3D 并行的实证验证#

Megatron 的经典论文(NVIDIA,与 Stanford 的 Matei 和 Deepak 合作)提供了大量定量实验。上图对比了 PTD-P(3D 并行:Pipeline + Tensor + Data)和纯 ZeRO-3 的扩展性。PTD-P 在 768-1920 GPU 范围内保持几乎平坦的 per-GPU 吞吐量(~150-170 TFLOP/s),而 ZeRO-3 的吞吐量随 GPU 数增加显著下降(从 ~150 降到 ~50 TFLOP/s)。
这种稳定的扩展性是大规模数据中心建设的基础——正是因为并行策略足够高效,即使数万块 GPU 的集群也能保持良好的利用率。
论文还提供了两个重要的实证结论:
Tensor parallel 在 8 处断崖下降。TP=2 到 TP=8 的性能下降是温和的,但 TP=8 到 TP=16 出现跨节点导致的剧烈性能损失。
Activation recomputation 可以反直觉地提升整体性能。通过重计算释放激活内存 → 能容纳更大 batch size → 更好的 GPU 利用率和 pipeline 效率。做更多计算反而更快,因为释放的内存被转化为 batch size 资源。
DP/TP/PP 随规模的动态演进#
Megatron 论文中的参数扫描揭示了各并行维度随 GPU 数量的动态演变路径:数据并行最先被最大化;tensor parallel 增长到 TP=8 后停止(NVLink 域上限);此后 pipeline parallel 接管增长,持续增大。在最大规模下,DP 反而被压缩到 6——因为 TP 和 PP 占用了大量 GPU 配额以满足模型拆分的需求,剩余的 GPU 才用于 DP。
Loop Transformer 对 FSDP 的影响#
一个有趣的讨论涉及 loop transformer(循环 Transformer,同层权重反复使用)对并行策略的影响。FSDP 的核心范式是”取权重 → 计算 → 丢弃权重”循环往复,但 loop transformer 的权重在多轮计算中持续使用,不能丢弃。这意味着 FSDP 的策略在这种架构下需要根本性的调整。另一方面,loop transformer 的参数效率更高(同一组参数被复用),可能减少对模型并行的需求。
前沿训练案例分析:从 OLMo 到 Qwen 3#
理论框架就绪后,以下通过具体的训练案例来验证这些原则在实践中的应用。
OLMo(AI2):纯 FSDP 的 7B 模型#
AI2 的 OLMo 7B 模型完全使用 FSDP 训练,没有任何模型并行。这验证了一个重要结论:对于 7B 级别的”小”模型,FSDP 单独就能扩展到大量 GPU。FSDP 的通信可以被计算充分掩盖,不需要引入复杂的 pipeline 或 tensor parallel。许多 7B 量级的模型都采用纯 FSDP 策略。
DeepSeek V1 → V3:从稠密到 MoE 的演进#
DeepSeek V1(稠密模型)使用了经典的三件套:ZeRO Stage 1 数据并行 + tensor/sequence parallel + pipeline parallel。这是标准的 DP + TP + PP 组合。
DeepSeek V3(MoE 模型)的配置则截然不同:用 expert parallel 替换了 tensor parallel,并且 EP 的规模非常激进——达到 64-way,横跨 8 台机器。为了支撑如此大规模的 EP,DeepSeek 借鉴了 pipeline parallel 的 pipelining 技巧来掩盖 EP 的通信延迟,并开发了前面提到的 DPP 库来优化底层 dispatch。
这个演进完美体现了”MoE 时代用 EP 替代 TP”的原则。
Yi(中国 open weights):经典三件套#
Yi 使用 ZeRO Stage 1 + tensor parallel + pipeline parallel,是标准的稠密模型配置。到了 MoE 版本(Yi-Large MoE),tensor parallel 被替换为 expert parallel——与 DeepSeek 的演进方向一致。
Llama3 405B:最完整的公开配置#

Llama3 405B 是少数完整公开了各训练阶段并行配置的模型。主预训练阶段使用 TP=8、CP=1、PP=16、DP=128,总共 16,384 块 GPU。这完美遵循了实践处方:TP 限制在 8(NVLink 域),PP=16 负责跨节点的模型切分,剩余 GPU 全部用于数据并行。
长上下文扩展阶段的配置变化耐人寻味:CP 从 1 升到 16,DP 从 128 降到 8。长序列带来的巨大激活内存需要 context parallel 来分摊,而这消耗了大量 GPU 配额,数据并行相应缩减。
一个值得注意的数字:Llama3 405B 训练期间 GPU 发生了 148 次故障。大规模训练不仅是并行化问题,更是分布式系统的可靠性工程。
由于 Llama3 405B 是稠密模型而非 MoE,它使用的是 tensor parallel 而非 expert parallel。
Gemma 2(Google):TPU 的极简方案#
Google 的 Gemma 2 仅使用 FSDP + tensor parallel + sequence parallel,完全没有 pipeline parallel。这体现了 TPU mesh 拓扑的优势:由于 TPU 的 toroidal mesh 在各方向提供相对均匀的带宽,tensor parallel 可以扩展到远超 8 的规模,不需要依赖 pipeline parallel 来处理慢速跨节点链路。
Nemotron 3 Super#
NVIDIA 的 Nemotron 3 Super 遵循 DeepSeek V3 模型架构,使用 expert parallel 加 context parallel(用于长上下文扩展),展示了 EP+CP 组合的实际应用。
Mixtral 8x22B / Qwen 3(MoE 新范式)#
NVIDIA 的 Megatron Bridge 仓库(一个包含大量推荐训练配置的开放资源)提供了具体的并行化方案。以 Mixtral 8x22B 为例:EP=8、PP=4、TP=4(attention 层)。Qwen 3 遵循 DeepSeek V3 的路线:EP=32(激进的 expert parallel)、PP=8、TP=2(仅用于 attention)。
总结性观察#
综合所有案例,几个一致的模式浮现:
- 数据并行总是最大化的——所有模型都尽可能把 GPU 用于 DP
- Tensor parallel 几乎不超过 8——唯一例外是 TPU 上的 Google 模型
- 稠密模型用 TP+PP,MoE 模型用 EP+PP——两条路线清晰分离
- EP 的规模在增长——从早期的 8 到 DeepSeek/Qwen 的 32-64,部分归功于 DPP 等系统工程的进步
- 不同训练阶段使用不同配置——预训练、长上下文扩展、对齐各有最优策略
部分内容可能已过时