第 21 章 分布式训练与并行
第 21 章 分布式训练与并行
第 19、20 章都在单个 GPU 内部做优化。当模型本身有几千亿参数、或单卡吞吐远不能满足需求时,唯一的出路是把工作切开分给多个设备——代价是设备之间必须通信,而通信比计算贵得多。
学习目标
读完本章,你应当能够:
- 说出驱动并行化的四大约束(显存容量、显存带宽、算力、通信),并判断某场景真正卡在哪一项。
- 写出六种集合通信原语的语义与通信量(每个元素被搬运的次数),并把 All-Reduce 拆解为 Reduce-Scatter + All-Gather。
- 对比 NVLink/NVSwitch 与 PCIe、InfiniBand 与以太网的带宽数量级,解释为什么高频通信的并行必须留在 NVLink 域内。
- 描述 DP/DDP 的梯度同步流程,说明通信量为何与参数量同阶,以及 DDP 的 bucket 与通信计算重叠机制。
- 推导 Megatron 风格张量并行"第一个线性层按列切、第二个按行切"的方案,说明为什么这样只需一次 All-Reduce,并给出每层前向/反向的通信次数。
- 推导流水线并行的 bubble 比例公式,估算 1F1B 与虚拟流水线的收益。
- 量化估算 ZeRO 三个阶段的显存节省,说明它与 FSDP 的关系。
- 解释专家并行(EP/MoE)的稀疏激活、All-to-All 通信、容量因子与负载均衡。
- 用决策树为给定模型规模与集群拓扑选出并行策略。
前置知识检查
| 你需要知道 | 在哪一节补齐 |
|---|---|
| 显存占用由权重/梯度/优化器状态/激活构成 | 第 19 章 19.4、19.9;本章 21.6 会给出完整账本 |
| 矩阵乘法与转置的维度账本 | 第 1 章、第 15 章 |
| 链式法则与反向传播的维度对应 | 第 12 章 |
| Adam 的优化器状态构成(一阶/二阶矩) | 第 6 章;本章 21.6 会重述为存储量 |
| 集合通信原语(本章 21.2 从零讲起) | 本章 21.2 |
| 算子的算术强度与 GEMM 复用率 | 第 19 章 19.2 |
| MoE 与稀疏激活的基本概念 | 本章 21.7 |
21.1 为什么需要并行:四大约束
单卡做不了大模型训练,原因不止一个。分清楚是哪一项在卡,决定了该用哪种并行:
| 约束 | 表现 | 靠什么缓解 | 对应并行 |
|---|---|---|---|
| 显存容量 | 权重+梯度+优化器状态+激活放不下 | 把状态切片存到不同卡 | DP+ZeRO/FSDP、TP、PP |
| 显存带宽 | decode / 小 batch 时算力闲置(见第 19 章 19.3) | 把数据搬多份,提高算术强度 | DP、continuous batching |
| 算力 | 单卡 FLOP/s 不足以在可接受时间内算完 | 把计算切成多块并行执行 | TP、PP、EP |
| 通信 | 加卡后反而变慢 | 提高计算通信比、减少通信次数 | 并行策略选型与拓扑匹配 |
关键认识:前三项是"收益",第四项是"成本"。并行化的全部工程内容,就是在"获得前三项收益"与"付出第四项成本"之间找平衡点。
这也解释了为什么并行策略的选择不只取决于模型,还取决于集群拓扑:同样的 8 卡 TP,放在 NVLink 全连接域内和放在 8 台机器上,效果能差一个数量级。这一点会在 21.3 与 21.5 中反复出现。
21.2 集合通信原语
并行训练的一切通信都可以归结为几个集合通信原语(collective communication primitives)。理解它们的关键不是名字,而是每个元素被搬运了几次。
设 N 为设备数(rank 数),D 为单个分片的数据量(元素数或字节数)。以下分析都基于环(ring)算法的朴素实现。
21.2.1 六种原语的语义
| 原语 | 语义 | 通信量(每设备) | 典型用途 |
|---|---|---|---|
| Broadcast | 一个 rank 的数据发给所有 rank | D 发送 | 分发初始权重、分发输入 |
| Scatter | 一个 rank 的 N 个分片各发给一个 rank | D 发送 | 分片分发 |
| Gather | 各 rank 的数据汇聚到一个 rank | D 接收 | 收集结果 |
| Reduce | 各 rank 的数据按算子(sum/max)归约到一个 rank | D 接收 | 汇总指标、Loss |
| All-Gather | 各 rank 的数据汇聚并广播给所有 rank | D·(N−1)/N ≈ D 接收 | 收集分片(ZeRO-3 前向) |
| Reduce-Scatter | 各 rank 归约后,每 rank 只留一个分片 | D·(N−1)/N ≈ D 发送 | 梯度分片归约(ZeRO-2) |
| All-Reduce | 各 rank 归约,所有 rank 都得到完整结果 | 2D·(N−1)/N ≈ 2D | DP 梯度同步(最常用) |
| All-to-All | 每个 rank 向每个其他 rank 发一段专属数据 | D 发送 + D 接收 | MoE 的 token 分发 |
重要
记住两个数字:All-Reduce 的通信量约为 2D(N 大时趋近),All-Gather 与 Reduce-Scatter 各约为 D。这一点是 ZeRO 通信量分析的全部依据,也是 21.6 的基础。所有集合通信的通信量都与 N 无关(趋近常数倍的 D)——这是环算法的核心优点,也是它能扩展到上千卡的原因。
21.2.2 All-Reduce = Reduce-Scatter + All-Gather
All-Reduce 可以精确拆成两步,这两步恰好是"归约并分片"与"汇聚并广播":
| |
为什么这个拆解很重要:如果某一个后续步骤本来就不需要完整结果(比如 ZeRO-2 里每张卡只需要自己负责的那片梯度来更新自己负责的那片参数),那么第一步 Reduce-Scatter 之后就可以停下——省掉整整一半通信。ZeRO/FSDP 的通信效率正建立在这个拆解上。
21.2.3 Ring All-Reduce 的思路
把 N 张卡连成一个环,每张卡只与左右两个邻居通信:
| |
优点:每张卡的收发量都是 2D(N−1)/N,与 N 无关;带宽利用率高(每个方向都不空闲)。缺点:延迟为 2(N−1) 轮,N 很大时延迟会成为主要开销——这正是"跨机 All-Reduce 慢"的机制来源之一。工程上用 树形 / 分层(hierarchical)All-Reduce 来减轻:机内先做一轮,机间再做一轮,把跨机通信的轮数降下来。
21.3 通信硬件:为什么 TP 必须放在同机
| 互连 | 带宽量级(单向) | 延迟 | 连接范围 |
|---|---|---|---|
| PCIe 5.0 ×16 | 约 64 GB/s | 微秒级 | 机内(点对点) |
| NVLink 4.0(H100 代) | 约 450 GB/s(每卡 18 链路合计,双向约 900) | 亚微秒级 | 机内(NVSwitch 全连接) |
| NVSwitch | 机内任意两卡等带宽全连接 | 亚微秒级 | 单机(8~72 卡) |
| InfiniBand NDR | 约 50 GB/s(400 Gb/s) | 微秒级 | 跨机 |
| 以太网 RoCE 100Gb | 约 12.5 GB/s | 微秒级 | 跨机 |
数量级上的结论很清晰:NVLink 比 PCIe 快约 7 倍,比 InfiniBand 快约 9 倍,比百 G 以太网快约 36 倍。
因此一条硬性工程规则:
重要
通信频率越高的并行,必须放在越快的域内。
- TP 每层前向/反向都要 All-Reduce(见 21.5),频率最高 ⟹ 必须放在 NVLink 域内(同机),跨机做 TP 会严重掉吞吐。
- EP 每层都做 All-to-All,频率同样极高 ⟹ 也必须优先放在 NVLink 域内,或至少用高带宽 IB。
- DP 每步只同步一次梯度,频率低 ⟹ 可以跨机。
- PP 只在相邻 stage 间传激活,频率最低 ⟹ 最适合跨机。
这也解释了为什么实际大规模训练的标准形态是:机内 TP(8 卡满 NVLink)+ 机间 PP 与 DP。
21.4 数据并行:DP 与 DDP
21.4.1 流程
数据并行的做法最直观:每张卡放一份完整模型,各喂不同的数据。
| |
注意第 ③ 步为什么必须是"同一个梯度":如果各卡用各自不同的梯度更新,参数就会分叉,下一轮的前向就失去了可比性。保证参数一致性是 DP 的正确性基础,也是一切通信开销的来源。
21.4.2 通信量与参数量同阶
第 ② 步的通信量:梯度张量大小为 P(参数量)个元素,All-Reduce 通信量约 2P(元素数)。所以
DP 每步通信量 ≈ 2 × 参数量
这是 DP 的核心特征:通信量与参数量同阶,与 batch size 无关。 推论很重要——增大全局 batch size 是"免费"降低 DP 通信占比的手段:数据多了,计算量线性增加,但同步一次的成本不变。
工程上还有两个补充手段:
- 梯度累积(gradient accumulation):把
K个小 micro-batch 的梯度先本地累加,再每K步同步一次。等效于把全局 batch 放大K倍,通信频率降到1/K。代价是优化器的有效更新次数减少,学习率需要相应调整。 - DDP 的 bucket 与重叠:反向传播是逐层产生梯度的。DDP 不等全部梯度算完,而是把梯度按参数分成若干 bucket(桶),某个桶一填满就立刻发起 All-Reduce,与后续层的反向计算并行进行。
| |
bucket 大小的取舍:太小则每次通信的消息小、启动开销占比高、带宽打不满;太大则第一个桶要等很久才满,重叠窗口变小、尾部还会剩下一个无法隐藏的通信尾巴。实践中常取几十 MB 级别,并按"反向产生的顺序"排列,让靠后产生的梯度(反向最先算出的那些层)先进桶。
21.5 张量并行:Megatron 风格的层内切分
数据并行不减少单卡显存(每卡一份完整模型),所以模型大到单卡放不下时必须切层内。张量并行(tensor parallelism, TP)把权重矩阵本身切开。
21.5.1 MLP 的列切与行切
考虑一个两层 MLP(先忽略激活函数):Y = GeLU(X·A)·B,其中 X ∈ R^{n×d}、A ∈ R^{d×h}、B ∈ R^{h×d}。
天真做法(按列切 A):把 A 按列切成 N 份 A = [A₁, A₂, …, A_N],每张卡算 Z_r = GeLU(X·A_r),其中 Z_r ∈ R^{n×h/N}。这没问题,因为 GeLU 是逐元素的,GeLU([X A₁, X A₂]) = [GeLU(X A₁), GeLU(X A₂)]——分块计算后再拼接,与整体计算完全等价。
但接下来要用 B。把 B 按行切成 B = [B₁; B₂; …; B_N](与 Z 的列切分对应),则
Y = GeLU(X·A)·B = [Z₁, Z₂, …, Z_N] · [B₁; B₂; …; B_N] = Σ_{r=1}^{N} Z_r·B_r
关键观察:每张卡 r 算出 Z_r·B_r 是一个 部分和,需要把所有 N 个部分和相加才能得到完整的 Y。这个"相加"就是一次 All-Reduce。
| |
为什么必须"第一个按列切、第二个按行切":
- 若两个都按列切,那么每张卡得到的是
Y的一个列块,不需要通信——但下一层又需要完整输入,于是通信被推迟到某处,且会引出"需要拼接"的问题; - 若两个都按行切,那
X也必须按列切,而X是上一层的输出、每张卡都持有完整副本,会造成冗余计算; - 只有"列切→行切"这一组合,能让
GeLU这一非线性算子作用在每张卡的局部结果上而不需要通信(因为按列切得到的Z_r已经是完整结果的列块),并且把所有通信压缩到最后的一次归约上。
这是 Megatron-LM 全部设计的核心,值得用一个等式记住:
Y = Σ_r ( GeLU(X·A_r) · B_r ),A_r 是 A 的列块,B_r 是 B 的对应行块。
21.5.2 注意力按头切
多头注意力天然可切:H 个头之间没有计算耦合(各自独立的 Q/K/V 投影、独立的注意力、最后拼接)。因此把 H 个头分给 N 张卡,每卡 H/N 个头,就完成了一次干净的切分。
输出投影 W_O 则对应按行切(因为各卡产出的是输出维度的不同段),于是又是一次 All-Reduce。结构与 MLP 完全同构。
21.5.3 通信位置与次数
【2026-09-02 选择 Q12】 的考点就是这一段。逐项数清:
| |
对照真题选项:A(仅在 Loss 阶段)、C(仅在训练结束后的参数同步)、D(仅在数据加载)全部错误。正确答案是 B:每个 Transformer 层内部的前向和反向传播过程中。
21.5.4 通信量:与激活同阶
TP 的 All-Reduce 搬运的是什么?是张量 Y ∈ R^{n×d}(n 是 token 数、d 是隐藏维度),通信量约 2·n·d 个元素。
对比同一层的计算量(以 MLP 为例,2 × 2·n·d·h):
| |
这个比值很健康:h 越大,每搬运一个元素能换来的计算越多。所以 TP 的单次通信量并不大。它的问题不在量,而在频率——每层每步 4 次,32 层就是 128 次,模型的每一步迭代都如此。高频率 + 高延迟的通信正是跨机 TP 掉吞吐的机制。
重要
DP 与 TP 的通信特征完全相反,这是本章最该记牢的对比:
- DP:低频、大通信量(每步 1 次,通信量
≈2P与参数量同阶)⟹ 可以跨机。 - TP:高频、小通信量(每层前后向各若干次,通信量
≈2nd与激活同阶)⟹ 必须同机、走 NVLink。
21.5.5 序列并行
TP 下每张卡都持有完整输入的副本,于是 LayerNorm、Dropout 这些逐元素算子在每张卡上重复计算并重复存储激活。序列并行(sequence parallelism) 沿序列维度切分这些部分,消除冗余:只在 TP 区域内沿 n 维切分,需要完整激活的算子(如注意力)前用 All-Gather 拼回来,之后再用 Reduce-Scatter 切回去。
注意这里通信量也是约 2nd 级别,与 TP 本身的 All-Reduce 同阶,因此序列并行基本是"免费"的显存优化——代价只是多两次集合通信。
21.6 流水线并行:按层切分与 bubble
21.6.1 基本形态
流水线并行(pipeline parallelism, PP)把模型的 L 层按顺序切成 p 个 stage,每个 stage 放在一张卡(或一组卡)上。第 r 个 stage 只持有 L/p 层,显存压力随之下降。
代价是顺序依赖:stage 1 必须先算完,stage 2 才能开始。为了让所有卡同时忙碌,把一个 batch 切成 m 个 micro-batch,让它们像流水线一样依次流过各 stage:
| |
21.6.2 bubble 比例公式
设单个 micro-batch 通过一个 stage 的时间为 t。朴素调度下:
- 总时间 = 前向填充
(p−1)·t+ 稳态m·t+ 反向排空(p−1)·t……用更标准的口径:总步数为2(m + p − 1)·t,其中有效工作是2m·t,其余是 bubble:
bubble 比例 = (p − 1) / (m + p − 1)
推导思路:p 个 stage 在稳态时全部忙碌,但流水线有 p−1 个"填充槽位"和 p−1 个"排空槽位",合计 2(p−1) 个空闲 stage-时间;总 stage-时间为 2p·m(每 micro-batch 每 stage 前后向各一次共 m·p 对)——两者之比化简即得上式。
结论:bubble 比例随 p 增大而增大,随 m 增大而减小。
算例:p = 8、m = 32 时 bubble = 7/39 ≈ 17.9%;若把 m 提到 128,bubble = 7/135 ≈ 5.2%。
21.6.3 1F1B 与虚拟流水线
1F1B(one-forward-one-backward) 调度改变了每个 stage 的执行顺序:在填充阶段结束后,每个 stage 交替执行"一个前向、一个反向"。
它的两大好处:
- 显存峰值下降:朴素调度要先做完所有
m个 micro-batch 的前向,才能开始反向,中途必须保存m份激活;1F1B 中每个设备同时"在途"的 micro-batch 数被流水线深度限制在p左右,因此激活显存峰值从O(m)降到O(p)——这是一个与 micro-batch 数解耦的独立收益。 - 反向可以更早开始,与后续前向重叠。
虚拟流水线(virtual pipeline / interleaved 1F1B) 让每个设备持有多个不连续的层块(如 2 个 chunk),把它们交错执行。此时每个 stage 的填充深度从 p−1 降到约 p/v(v 为虚拟 stage 数),于是
bubble 比例 ≈ (p − 1) / (m·v + p − 1)
p = 8、v = 2、m = 32 时 bubble ≈ 7/71 ≈ 9.9%——相比朴素 1F1B 的 17.9% 减半。代价是每张卡要持有 v 组层,通信次数也变成 v 倍(点对点通信本身很便宜,所以通常划算)。
21.6.4 PP 的通信特征
PP 只在相邻 stage 之间传递激活与激活梯度,是**点对点(point-to-point)**通信,通信量约 n·d 个元素/次,频率为每 micro-batch 每边界 2 次。相比 TP,它的频率低得多、且没有集合通信的同步开销。
因此 PP 是跨机扩展的首选。 唯一的代价是 bubble——bubble 期间部分卡闲置,这是买了显存和扩展性,付出了算力利用率。
21.7 ZeRO 与 FSDP:把训练状态也切开
21.7.1 训练时的显存账本
混合精度 + Adam 训练一个参数量为 P 的模型,每张卡(DP 情形下)需要存:
| 项 | 精度 | 每参数字节 | P = 7.5×10⁹ 时 |
|---|---|---|---|
| 模型参数(fp16) | 2 B | 2 | 15 GB |
| 梯度(fp16) | 2 B | 2 | 15 GB |
| fp32 主权重副本 | 4 B | 4 | 30 GB |
Adam 一阶矩 m | 4 B | 4 | 30 GB |
Adam 二阶矩 v | 4 B | 4 | 30 GB |
| 合计 | 16 B | 120 GB |
注意 16 字节这个数字:它是"混合精度 + Adam"的固有开销,与模型结构无关。也就是说,训练 1 个参数需要 16 字节的状态——这就是为什么训练比推理的显存需求大得多(推理 FP16 只需 2 字节/参数,见第 19 章 19.4)。
所以 7.5B 模型的标准 DP 需要 120 GB/卡,比 A100 80GB 还大——模型本身放得下(只有 15 GB),但训练状态放不下。这正是 ZeRO 要解决的问题。
21.7.2 ZeRO 的三个阶段
ZeRO(zero redundancy optimizer) 的核心思想:DP 里每张卡都存了一份完全冗余的训练状态。既然大家算出的梯度相同、更新也相同,为什么每张卡都要存全量?把它们切分到各卡上,需要时再临时取回。
| 阶段 | 切分什么 | 每卡显存(P = 7.5B,N = 8) | 相对基线 |
|---|---|---|---|
| 基线 DP | 都不切 | 15(参数)+15(梯度)+90(优化器)= 120 GB | 1× |
| ZeRO-1 | 只切优化器状态 | 30 + 90/8 = 30 + 11.25 = 41.25 GB | 2.9× |
| ZeRO-2 | 优化器状态 + 梯度 | 15 + 1.875 + 11.25 = 28.1 GB | 4.3× |
| ZeRO-3 | 优化器状态 + 梯度 + 参数 | 15/8 + 1.875 + 11.25 = 13.1 GB | 9.2× |
为什么 ZeRO-1 只有 2.9 倍而不是 8 倍:因为优化器状态(90 GB)虽然被切分了,但参数(15 GB)与梯度(15 GB)还停留在每卡全量,合计 30 GB 是"不可压缩的地板"。当优化器状态从 90 降到 11.25 后,剩下的 30 GB 反而成了主要部分。这解释了一个常见困惑:ZeRO-1 的收益远小于 8 倍。 只有把参数也切了(ZeRO-3),才能真正逼近 N 倍。
通信代价:
| 阶段 | 每次迭代的额外通信 | 相对基线的通信量 |
|---|---|---|
| ZeRO-1 | Reduce-Scatter(梯度)+ All-Gather(更新后的参数) | 约 2× 基线 |
| ZeRO-2 | 同上 | 约 2× 基线 |
| ZeRO-3 | 前向/反向各需 All-Gather 参数,反向还需 Reduce-Scatter 梯度 | 约 3× 基线 |
这个通信量分析与 21.2.2 紧密相关:能只用 Reduce-Scatter 就绝不做 All-Reduce,因为后者是前者的两倍。基线 DP 的一次 All-Reduce 代价是 2D;ZeRO-1/2 用"Reduce-Scatter(D)+ All-Gather 更新后的参数(D)“两步替代,合计也是 2D 的两倍量级——也就是说,ZeRO 用约 2 倍的通信换来了数倍的显存节省,这是一笔明确标价的交易,不是免费的。所以能靠 ZeRO-1 解决就不上 ZeRO-3。
21.7.3 FSDP
FSDP(fully sharded data parallel) 可以理解为"ZeRO-3 的工程化实现”:参数、梯度、优化器状态全部分片,前向/反向时按需 All-Gather 某一层的参数,用完立刻释放。
| |
它与 ZeRO-3 的差别主要在实现层次:ZeRO 是 DeepSpeed 库层面的优化,FSDP 是 PyTorch 原生集成的实现,并支持嵌套 FSDP / HSDP(hybrid sharded data parallel)——把 N 张卡分成若干组,组内分片、组间复制,从而把 All-Gather 的通信限制在更小、更快的域内。这又一次体现了 21.3 的规则:让高频通信留在快域里。
21.8 专家并行与 MoE
21.8.1 稀疏激活
MoE(mixture of experts) 把 MLP 层替换成 E 个并行的"专家",每个 token 只被路由到 top-k 个专家(常见 k = 1 或 2)。
| |
收益:总参数量可以做到 E 倍,但每个 token 的实际计算量只增加 k 倍。这就是稀疏激活的价值——参数量(决定知识容量)与计算量(决定成本)解耦了。
21.8.2 All-to-All 通信
专家并行(expert parallelism, EP)把不同专家放在不同设备上。于是每个 token 必须被发送到它所选专家所在的设备上,算完再送回来——这是一次 All-to-All:
| |
注意这里出现了 n(token 数):EP 的通信量与 token 数成正比,与 TP 的 n·d 同阶但乘上了 k 与路由的不均匀性。而且 All-to-All 是每层都做——所以 EP 的通信频率与 TP 同级,必须放在 NVLink 域内或用高带宽 IB。
21.8.3 负载均衡与容量因子
MoE 最棘手的工程问题是负载不均:router 可能把所有 token 都送给少数几个专家,导致那几张卡算不完、其余卡闲置。两种治理手段:
- 负载均衡损失(auxiliary load-balancing loss):在训练目标中加一项,惩罚"专家使用率方差过大",用梯度把流量推均匀。这是训练层面的手段。
- 容量因子(capacity factor, CF):工程层面的手段——为每个专家设定一个容量上限
capacity = CF × (n·k / E),超出上限的 token 被直接丢弃(走残差旁路,不经过专家)。CF = 1.0表示容量恰好等于平均负载,此时任何不均衡都会导致丢 token;CF = 1.25是常见折中:给 25% 的余量,既能吸收一定波动,又不会浪费太多算力;CF越大越不容易丢 token,但显存与算力浪费也越大。
警告
被丢弃的 token 会绕过专家层直接走残差,因此不是"报错"而是"静默降质"。推理时丢 token 会让部分输入的实际计算路径与训练时不同,因此 MoE 推理必须监控丢 token 率,这是 MoE 部署中最容易被忽略的指标。
21.9 3D/4D 并行的组合选型
真实的大规模训练从来不是"选一种并行",而是多种并行叠加,常见的表述如 “TP=8, PP=8, DP=64”(共 4096 卡)。
21.9.1 决策流程
| |
三条经验规则:
- TP 度数不超过单机的 GPU 数(通常 8,GB200 NVL72 这类系统可更大)。这是 21.3 的直接推论。
- PP 度数 ≤ 层数 / 每卡最少层数,且要让
m ≥ 4p以把 bubble 压到可接受范围(21.6.2 的公式)。 - DP 度数吃掉剩下的所有卡,因为 DP 最容易扩展、通信频率最低。
21.9.2 全局 batch size 的约束
全局 batch = micro_batch × 梯度累积步数 × DP 度数
三条约束同时成立:
micro_batch受单卡显存限制(尤其受激活占用限制,与序列长度平方相关);- 梯度累积步数用于把全局 batch 补到目标值,同时降低 DP 通信频率(21.4.2);
DP 度数是硬件与并行策略给定的。
因此实践中常常是:先定全局 batch(由收敛性决定),再由显存定 micro_batch,最后用梯度累积补足差额。 这也解释了为什么改并行配置常常需要连带改学习率——全局 batch 变了,学习率的缩放规律(线性缩放或平方根缩放)也要跟着调整。
21.10 通信开销的度量与诊断
有了上面的框架,诊断"训练慢"就有了清晰的路径:
| 现象 | 可能原因 | 检查方法 |
|---|---|---|
| 加卡后吞吐不升反降 | 通信占比过高 | 对比"纯计算时间"与"每步总时间" |
每步耗时随 N 线性增长 | 集合通信未用环算法或落在慢网络上 | 看 rank 间是否走 NVLink(nvidia-smi topo -m) |
| 反向阶段出现明显空档 | bucket 太大或太小,未能重叠 | 用 profiler 看 All-Reduce 与反向 Kernel 的时间线是否重叠 |
| 部分卡等待时间长 | MoE 负载不均或 PP bubble | 看丢 token 率、看各 stage 的利用率 |
| 显存 OOM 但算力利用率不高 | 激活未重算、micro_batch 过大 | 打开 gradient checkpointing |
通信占比(communication ratio) 是最核心的单一指标:
通信占比 = 纯通信时间 / 每步总时间
若该值小于约 10%,说明重叠做得好,可以继续加卡;若超过 30%,则加卡的收益已经很低,应当先优化通信(换更快的域、调整 bucket、减小 TP 度数)。
计算通信重叠是把通信占比压下去的主要手段,DDP 的 bucket(21.4.2)是最经典的例子:把通信拆成小块,与后续计算并行发起。TP 的 All-Reduce 也可以与后续层的计算重叠(但重叠窗口比 DP 小,因为每层之间耦合更紧)。
本章小结
| 关键结论 | 一句话表述 | 常见错误 |
|---|---|---|
| 四大约束 | 显存容量/带宽、算力是收益,通信是成本 | 只算显存,忽略通信代价 |
| 集合通信量 | All-Reduce ≈ 2D,All-Gather / Reduce-Scatter ≈ D,均与 N 无关 | 以为通信量随卡数线性增长 |
| All-Reduce 拆解 | All-Reduce = Reduce-Scatter + All-Gather | 明明只需分片结果却做完整 All-Reduce |
| 拓扑规则 | 频率越高,域必须越快:TP/EP 同机,PP/DP 可跨机 | 跨机做 TP |
| DP/DDP | 通信量与参数量同阶、每步一次;bucket 与反向重叠 | 认为通信量随 batch 增大 |
| TP | MLP 第一个线性层按列切、第二个按行切;前向两次 All-Reduce,反向两次 | 认为 TP 只在 Loss 处通信 |
| TP vs DP | TP 高频小量(与激活同阶),DP 低频大量(与参数量同阶) | 混淆两者的通信特征 |
| PP | bubble = (p−1)/(m+p−1);1F1B 降显存;虚拟流水线把 bubble 再减半 | 忽略 bubble 对算力利用率的侵蚀 |
| ZeRO | 16 字节/参数的状态开销;ZeRO-1 只有约 3 倍收益(参数与梯度不可压缩) | 以为 ZeRO-1 就有 8 倍收益 |
| MoE/EP | 稀疏激活解耦参数量与算力;All-to-All 每层都做;容量因子决定丢 token 率 | 忽略丢 token 导致的静默降质 |
自测题
Q1(推导)N = 8 张卡做数据并行,模型参数量 P = 7×10⁹(FP16 梯度)。求每次梯度同步的 All-Reduce 通信量,并估算在 100 Gb/s 以太网(约 12.5 GB/s)与 NVLink(约 450 GB/s 单向)上分别需要多久。
答案与解析
梯度张量大小 = P = 7×10⁹ 个元素,FP16 即 D = 2 × 7×10⁹ = 14 GB。
按 21.2.1 的口径,All-Reduce 的通信量约为 2D(N = 8 时更精确地是 2D(N−1)/N = 1.75D ≈ 24.5 GB),这是全系统的消息总量。从每张卡的角度看,它发送约 D(N−1)/N ≈ 12.25 GB、接收同样多,但收发在环上是并行的、各占用链路的一个方向,所以决定耗时的是"单向 12.25 GB"或"总流量 24.5 GB 分两个方向":
| |
结论是量级层面的:跨机 DP 若走百 G 以太网,单步梯度同步就要 1~2 秒,完全不可用;走 NVLink 则只要几十毫秒。所以 DP 的通信量确实与参数量同阶,DP 也必须挑网络——跨机必须上 InfiniBand(400 Gb/s ≈ 50 GB/s)以上,并配合梯度累积把同步频率降下来。
常见错误:把 N 乘进通信量,得到"8 卡就要 100 多 GB"的结论。环算法的通信量与 N 无关(只差一个 (N−1)/N 的因子,N 大时趋近 1),这是它最重要的性质。
Q2(推导)写出 Megatron 风格 TP 中 MLP 的切分方案,并证明 Y = GeLU(X·A)·B 只需一次 All-Reduce。若 A ∈ R^{4096×16384}、X ∈ R^{n×4096}、n = 2048,在 N = 8 时估算每张卡的显存占用节省比例。
答案与解析
切分与证明:
| |
所以每张卡算出一个完整形状的部分和 W_r,做一次 All-Reduce(sum) 即得 Y。只通信一次,因为求和号可以提到最后。
显存节省:A 有 4096 × 16384 = 6.7×10⁷ 个参数,FP16 下全量 134 MB。每张卡只存 A_r ∈ R^{4096 × 2048},即 1/8:FP16 下 16.8 MB。
同时 B 也只存 1/8,前向中间量 Z_r ∈ R^{n × h/N} 同样只占 1/8——这正是 TP 相比 DP 能降低激活显存的原因(DP 每卡都要存全量激活)。
常见错误:把"按列切 A、按列切 B"当作方案。那样每卡得到的是 Y 的一个列块,虽然前向不需要通信,但下一层的输入必须完整——通信只是被推迟,且需要额外的拼接操作,反而更复杂。
Q3(计算)一个 32 层模型用 PP 切成 p = 8 个 stage,micro-batch 数 m = 32。(a) 朴素 1F1B 的 bubble 比例是多少?(b) 用 v = 4 的虚拟流水线后是多少?(c) 要把 bubble 压到 5% 以下,m 需要多大(v = 1)?
答案与解析
(a) bubble = (p−1)/(m+p−1) = 7/(32+7) = 7/39 ≈ 17.9%
(b) bubble ≈ (p−1)/(m·v + p−1) = 7/(32×4+7) = 7/135 ≈ 5.2%
(c) 令 7/(m+7) ≤ 0.05 ⟹ m + 7 ≥ 140 ⟹ m ≥ 133。
工程含义:想把 bubble 压到 5%,要么把 micro-batch 数提到 130 以上(意味着全局 batch 极大,可能影响收敛),要么用虚拟流水线把有效深度加大 4 倍。这就是虚拟流水线存在的理由——它让"减少 bubble"与"控制全局 batch"不再直接冲突。
常见错误:把 m 当成"全局 batch size"。m 是micro-batch 的个数,全局 batch = m × micro_batch_size(再乘 DP 度数)。微调 m 只影响流水线效率,不改变单个 micro-batch 的显存。
Q4(计算)P = 7.5×10⁹、N = 8 的混合精度 Adam 训练。分别估算基线 DP、ZeRO-1、ZeRO-2、ZeRO-3 的每卡显存,并解释为什么 ZeRO-1 只有约 3 倍收益而不是 8 倍。
答案与解析
单卡全量状态:16 B/参数 × 7.5×10⁹ = 120 GB,构成是参数 15 GB、梯度 15 GB、优化器状态 90 GB(fp32 主权重 30 + m 30 + v 30)。
| |
为什么 ZeRO-1 只有 2.9 倍:被切分的只有优化器状态那 90 GB;参数与梯度合计 30 GB 是不可压缩的地板。切分后 90/8 = 11.25,剩下的 30 GB 反而成了主要部分,于是 120 / 41.25 ≈ 2.9。
只有当参数也被切分(ZeRO-3,15/8 = 1.875)时,总量才降到 13.1 GB,逼近 N = 8 倍的理论值(理论下限是 120/8 = 15 GB,实测更低是因为 fp16 参数分片与 fp32 主权重分片的记账口径略有差异)。
实践含义:如果单卡只是"差一点"放不下,ZeRO-1 就够了且通信代价最低;如果要训练远大于单卡的模型,必须上 ZeRO-3/FSDP。不要跳过 ZeRO-1/2 直接上 ZeRO-3——后者每次前向都要 All-Gather 参数,通信量约为基线的 3 倍。
Q5(辨析)某团队把 TP 度数设为 16,跨了两台 8 卡机器(机间 InfiniBand)。他们发现扩展后单步耗时反而比 TP=8 更长。请解释原因,并给出两种改法。
答案与解析
原因:TP 的 All-Reduce 发生在每一层的前向与反向(21.5.3:每层每步 4 次)。TP=16 时其中一半的通信必须跨机走 InfiniBand(约 50 GB/s),而机内 NVLink 约 450 GB/s——跨机那部分慢约 9 倍,且延迟高一个量级。由于通信是每层都发生的同步点,慢的那一半会把整个流水线拖住:每层的耗时不再由计算决定,而由跨机 All-Reduce 决定。于是 TP = 16 比 TP = 8 更慢。
改法:
- 把 TP 度数限制在 8(不超过单机卡数),把多出来的机器用于 PP 或 DP。PP 只在 stage 边界点对点通信、频率低得多(21.6.4),DP 每步只同步一次梯度。这样总卡数不变,但高频通信全部留在 NVLink 域内。
- 改用分层 All-Reduce + 序列并行:机内先归约、机间再归约,把跨机消息量降到
1/8;但这条只能缓解、不能消除,因为跨机那一轮仍然每层都要做。更彻底的做法是换用更高带宽的互连(如多轨 IB 或 NVLink 跨机方案)。
一句话结论:TP 度数不应超过 NVLink 域内的卡数——这不是调优建议,而是由通信频率与带宽比决定的硬约束。
与真题的关联
| 真题 | 考查角度 | 对应本章小节 |
|---|---|---|
【2026-09-02 选择 Q12】 张量并行通信位置 | Megatron 列切/行切方案;前向与反向在每层内各有若干次 All-Reduce | 21.5.1、21.5.3 |
【2026-09-02 选择 Q11】 prefill/decode 瓶颈 | DP 的"通信量与 batch 无关"性质与 decode 的 batch 摊薄是同一类复用思想 | 21.4.2、第 19 章 19.3 |
【2026-09-09 选择 Q3】 KV Cache 显存公式 | 显存账本方法(逐项列量纲再相乘)与本章 21.7.1 完全同构 | 21.7.1 |
【2026-08-05 选择 Q13】 推理峰值显存构成 | 显存不止权重;训练侧对应的是"16 字节/参数"的训练状态账本 | 21.7.1 |
【2026-08-05 选择 Q20】 混合精度与训练稳定性 | BF16 的指数位宽与 FP32 相同,是混合精度训练状态可切分的前提 | 21.7.1、第 20 章 20.1.1 |
延伸阅读
- Shoeybi et al., Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism, 2019 —— 列切/行切方案与每层 All-Reduce 的原始出处。
- Rajbhandari et al., ZeRO: Memory Optimizations Toward Training Trillion Parameter Models, SC 2020 —— 三阶段切分与通信量分析。
- Narayanan et al., Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM, SC 2021 —— 1F1B 调度、虚拟流水线与 3D 并行的组合选型。
- Huang et al., GPipe: Efficient Training of Giant Neural Networks using Pipeline Parallelism, NeurIPS 2019 —— bubble 比例公式的来源。
- Fedus et al., Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity, JMLR 2022 —— 容量因子、负载均衡损失与丢 token 问题。
- Korthikanti et al., Reducing Activation Recomputation in Large Transformer Models, MLSys 2023 —— 序列并行与激活重算的完整分析。
- 第 19 章(推理系统与性能工程)提供"算力 / 带宽 / 算术强度"的量化工具;第 20 章(量化与压缩)提供降低单卡显存占用从而减少并行度需求的手段。