通信
分布式训练将执行时间的相当一部分用于梯度同步、激活重分布以及在网络互连结构上路由令牌。本附录不将逐步证明塞进正文,而是提供贯穿全书使用的定量通信开销模型:点对点公式(\(\alpha\)-\(\beta\) 与 LogGP)、集合通信执行上界(AllReduce、AllGather、ReduceScatter、AllToAll)、流水线气泡算式,以及梯度压缩阈值。
如何使用本附录
本附录被设计为在将分布式训练症状(“AllReduce 很慢”“流水线气泡正在拖垮吞吐量”“是否应该压缩梯度?”)转化为定量诊断时使用的参考材料。
此处采用的约定遵循全书记号:\(\alpha\) 表示每条消息的启动延迟,\(\beta\) 表示链路带宽(字节每秒),\(n\) 表示点对点消息大小,\(n^*\) 表示 \(\alpha\)-\(\beta\) 交叉点,\(N\) 表示参与 GPU 的数量,\(M\) 表示集合通信载荷大小(字节)。
The \(\alpha\)-\(\beta\) Communication Model
Systems Perspective 1.1: 为什么这很重要
网络上的每一次点对点传输都遵循相同的基本模式:发送方先支付一笔固定的启动开销以发起消息,然后以链路带宽决定的速率传输载荷。这个两参数模型捕捉了网络通信的本质物理特性。
\(\alpha\)-\(\beta\) 模型(公式 1)预测传输一条大小为 \(n\) 字节的点对点消息所需的时间:
\[ T(n) = \alpha + \frac{n}{\beta} \tag{1}\]
其中:
- \(\alpha\) 是启动延迟(秒)——发起消息的固定开销,包括软件开销、网卡(NIC)处理和网络路由建立
- \(\beta\) 是链路带宽(字节/秒)——启动之后的持续数据速率
- \(n\) 是消息大小(字节)
该模型将每次传输分解为恰好两项开销:一笔与大小无关的每条消息开销(\(\alpha\)),以及一项随载荷线性缩放的每条字节开销(\(n/\beta\))。这一分解驱动 节 1.3 中所有的算法选择决策。
对物理互连结构(表 1)进行参数化,可为机器学习集群中常见硬件提供基线 \(\alpha\) 与 \(\beta\) 取值:
| 互连结构 | \(\alpha\)(延迟) | \(\beta\)(带宽) | 典型用途 |
|---|---|---|---|
| NVLink 4.0(H100) | 500 ns | 450 GB/s | 节点内 GPU 到 GPU |
| PCIe Gen5 | 1000 ns | 64 GB/s | CPU-GPU、NIC-GPU |
| InfiniBand NDR(400 Gbps) | 5 μs | 50 GB/s | 节点间(高端集群) |
| InfiniBand HDR(200 Gbps) | 7 μs | 25 GB/s | 节点间(上一代) |
| RoCE v2(100 GbE) | 10 μs | 12.5 GB/s | 节点间(以太网集群) |
| TCP/IP(以太网) | 50 μs | 视情况而定 | 控制面,非 RDMA 回退方案 |
延迟主导与带宽主导形态
\(\alpha\)-\(\beta\) 模型揭示了两种截然不同的运行形态。对于小消息,启动延迟 \(\alpha\) 占主导——链路大部分时间都花在发起传输上,而非维持传输。对于大消息,带宽项 \(n/\beta\) 占主导,启动开销可忽略。
交叉消息大小 \(n^*\),由 公式 2 定义,是两项贡献相等的临界点:
\[ n^* = \alpha \times \beta \tag{2}\]
当消息大小低于 \(n^*\) 时,通信处于延迟主导 形态:发送更多小消息会在重复启动上浪费大量时间。当消息大小高于 \(n^*\) 时,通信处于带宽主导 形态:链路被充分利用,唯一提速途径是提高带宽。
Napkin Math 1.1: 工作示例:InfiniBand NDR 上的交叉点
问题:在什么消息大小下,带宽项等于延迟项?
推导:
\(n^* = \alpha \times \beta =\) 5 μs \(\times\) 50 GB/s \(=\) 250 KB
分析:小于 250 KB 的消息在 IB NDR 上属于延迟主导。大型模型单个层的梯度张量通常约为 10–100 MB——明显高于该阈值。然而,控制消息、心跳和屏障同步都远低于该阈值。
系统学洞见:这正是 NCCL 与 Gloo 在启动 AllReduce 之前,先将小梯度张量批合成更大的”桶”的原因。逐个发送每个张量,每轮迭代都要支付 5 μs 的启动开销数百次,而非仅几次。
LogGP 模型扩展
\(\alpha\)-\(\beta\) 模型假设消息是一次原子传输。实际上,网络会流水线化消息:发送方可以在前一条消息完全接收之前注入新包。LogGP 模型 (Alexandrov 等 1995年) 在 LogP 基础上增加了一个长消息间隙参数:
- \(g\)(gap):发送方连续注入两条消息之间的最小间隔。该参数刻画 NIC 的注入速率上限。
- \(o_{\text{send}}\)、\(o_{\text{recv}}\)(overhead):处理器用于发起或完成消息的 CPU 时间,在此期间无法执行有用的计算。
对于长度为 \(n\) 字节的长消息,LogGP 将传输时间建模为约: \[T_{\text{long}}(n) \approx o_{\text{send}} + L_{\text{LogGP}} + (n - 1)G + o_{\text{recv}}\]
其中 \(L_{\text{LogGP}}\) 是网络延迟,\(o_{\text{send}}\) 与 \(o_{\text{recv}}\) 分别是发送方和接收方的开销,\(G\) 是长消息的每字节间隙,\(g\) 控制连续消息注入之间的最小间隔。非正式的 alpha-beta 式近似可用于机器学习性能剖析,但标准 LogGP 模型会将这些间隙参数与简单的带宽项区分开来。
在大多数机器学习训练场景中,\(\alpha\)-\(\beta\) 模型已经足够,因为梯度张量足够大,流水线效应相对于原始带宽是次要的。当分析大量小控制消息的开销,或建模通信与计算的重叠时,LogGP 模型才变得重要——这些情形出现在细粒度流水线并行与异步梯度更新中。
\(\alpha\)-\(\beta\) 模型描述点对点传输。集合操作——所有 GPU 都参与——由多次点对点传输组合而成,其成本公式直接由上述模型推导而来。
集合操作复杂度
Systems Perspective 1.2: 为什么这很重要
集合操作在所有 \(N\) 个 GPU 之间同时移动数据。每种集合通信都有一个特征带宽项(有多少数据流动)和延迟项(需要多少轮顺序消息步骤)。以下公式默认采用带宽最优环形算法;节 1.3 讨论何时其他算法更优。
AllReduce
AllReduce 是数据并行训练的基石:每个 GPU 以大小为 \(M\) 字节的局部梯度张量开始,以全局归约(求和)结果结束。环形算法将 AllReduce 分解为 ReduceScatter 阶段,随后是 AllGather 阶段。环形 AllReduce 的时间由 公式 3 给出:
\[ T_{\text{ring}} = 2 \cdot \frac{N - 1}{N} \cdot \frac{M}{\beta} + 2(N - 1) \cdot \alpha \tag{3}\]
带宽项中的因子 \(2(N-1)/N\) 随 \(N\) 增大而趋近于 2——每个字节实际上在环中往返两次(一次用于 reduce-scatter,一次用于 all-gather)。延迟项随 \(N\) 线性增长,这使得环形算法在大 GPU 数量下延迟开销很高。
作为对照,树形 AllReduce 的成本如 公式 4 所示:
\[ T_{\text{tree}} = 2 \log_2 N \cdot \frac{M}{\beta} + 2 \log_2 N \cdot \alpha \tag{4}\]
树形算法以带宽效率换取延迟效率:延迟项随 \(\log_2 N\) 增长,而非 \(N\);但带宽项在每个树形层级发送完整消息 \(M\),而非 \(M/N\) 个分片。
Napkin Math 1.2: 工作示例:环形与树状 AllReduce
问题:环形与树状 AllReduce 各需要多长时间?
环形 AllReduce:
\(T_{\text{ring}} \approx\) 42.4 ms
树状 AllReduce:
\(T_{\text{tree}} \approx\) 320.1 ms
分析:对于这种 1 GB 消息,环形 AllReduce 耗时 42.4 ms,树状为 320.1 ms——环形明显更快,因为它将带宽负载分散到所有链路上。树状算法的对数延迟优势相对于其在大消息场景下的带宽代价可以忽略不计。
系统启示:对于数据并行训练中典型的大梯度张量,环形(或基于环的)算法占主导地位。树状算法仅适用于小消息,或当延迟而非带宽构成瓶颈时才有用。
AllGather
AllGather 是 ReduceScatter 的互补操作:每台 GPU 从一个大小为 \(M/N\) 的分片开始,最终得到完整的 \(M\)-字节张量。它是完全分片数据并行(FSDP)中的核心通信原语,用于在每个前向传播之前重建参数,也是张量并行中重组被切分的激活量的核心原语。
环形 AllGather 的执行时间(公式 5)所需的传输量仅为 AllReduce 的一半:
\[ T_{\text{allgather}} = \frac{N - 1}{N} \cdot \frac{M}{\beta} + (N - 1) \cdot \alpha \tag{5}\]
AllGather 的成本恰好是 AllReduce 的一半(一次环传递而非两次),因为它不包含归约步骤。
ReduceScatter
ReduceScatter 是 AllGather 的对偶操作:每台 GPU 从一个完整的 \(M\)-字节张量开始,最终得到一个大小为 \(M/N\) 的分片,其中包含该分片的全局归约值。它是 FSDP 与 ZeRO 中的梯度同步原语,在每台 GPU 只需自身参数分片的梯度时,以成本更低的操作替代完整 AllReduce。
环形 ReduceScatter 的执行时间(公式 6)提供了梯度分片原语:
\[ T_{\text{reducescatter}} = \frac{N - 1}{N} \cdot \frac{M}{\beta} + (N - 1) \cdot \alpha \tag{6}\]
这种对称性并非偶然:环形 AllReduce 可分解为一次 ReduceScatter 加一次 AllGather,其成本恰好相加为 公式 3。
AllToAll
AllToAll 是最通用的集合通信:每台 GPU 向其他每台 GPU 发送一个大小为 \(M/N\) 的不同数据块,并从每台 GPU 接收一个不同的块。它是混合专家(mixture of experts (MoE))架构的路由原语,令牌必须被调度到正确的专家,并将结果汇聚回来。
成对交换式 AllToAll 的执行时间(公式 7)在同伴之间交换个性化数据块:
\[ T_{\text{alltoall}} = \frac{N - 1}{N} \cdot \frac{M}{\beta} + (N - 1) \cdot \alpha \tag{7}\]
尽管公式在形式上与 AllGather 和 ReduceScatter 相同,通信模式从根本上是不同的:AllToAll 属于个性化交换(每台 GPU 向每个同伴发送不同的数据),这使得它与计算的重叠更加困难,也更容易受到网络拥塞的影响。
Broadcast
Broadcast 将单个大小为 \(M\)-字节的张量从一台根 GPU 发送给其余所有 \(N - 1\) 台 GPU。它用于分发初始模型权重、更新后的学习率,以及训练过程中的配置变更。
树状 Broadcast 的执行时间(公式 8)随参与 GPU 数量呈对数增长:
\[ T_{\text{broadcast}} = \log_2 N \left(\alpha + \frac{M}{\beta}\right) \tag{8}\]
Broadcast 本质上是非对称的(一个发送者、多个接收者),因此树状拓扑是自然的。在未分段的树状 Broadcast 中,完整 \(M\)-字节载荷在每一棵树层级都被转发,因此延迟项和带宽项都出现在 \(\log_2 N\)-级关键路径上。分段或 scatter-allgather 类型的 Broadcast 变体可以降低带宽项,但它们需要采用不同的算法特定模型。
集合通信复杂度汇总
在给出各个公式之后,集合通信操作代价汇总 提供了一个紧凑的参考表,用于比较每种集合通信操作的代价结构。
| 操作 | 带宽项 | 延迟项 | 主要用途 |
|---|---|---|---|
| AllReduce(环形) | \(2 \cdot \frac{N-1}{N} \cdot \frac{M}{\beta}\) | \(2(N-1) \cdot \alpha\) | 数据并行梯度同步 |
| AllReduce(树状) | \(2\log_2 N \cdot \frac{M}{\beta}\) | \(2\log_2 N \cdot \alpha\) | 小消息同步 |
| AllGather(环形) | \(\frac{N-1}{N} \cdot \frac{M}{\beta}\) | \((N-1) \cdot \alpha\) | FSDP 参数重建 |
| ReduceScatter(环形) | \(\frac{N-1}{N} \cdot \frac{M}{\beta}\) | \((N-1) \cdot \alpha\) | FSDP/ZeRO 梯度分片 |
| AllToAll(成对交换) | \(\frac{N-1}{N} \cdot \frac{M}{\beta}\) | \((N-1) \cdot \alpha\) | MoE 专家路由 |
| Broadcast(树状) | \(\log_2 N \cdot \frac{M}{\beta}\) | \(\log_2 N \cdot \alpha\) | 权重分发、配置同步 |
从这张表中可以归纳出两种模式。第一,环形与成对交换模型都包含 \((N-1)/N\) 因子,当 \(N\) 较大时该因子趋近于 1。因此,每台 rank 的通信代价趋近于 \(M\) 的常数倍:环形 AllReduce 约为 \(2M\),环形 AllGather、环形 ReduceScatter 或成对交换 AllToAll 也约为 \(M\)。聚合流量仍随 rank 数量增长。第二,延迟项在环形算法中随 \(N\) 线性增长,而在树状算法中呈对数增长,由此产生了下文分析的算法选择权衡。
算法选择
Systems Perspective 1.3: 为何这很重要
环形 vs. 树状 vs. 递归减半加倍
环形算法最小化带宽使用,但要付出随 \(N\) 线性增长的延迟代价。树状算法最小化延迟,却因在每一层都发送完整消息而浪费带宽。递归减半加倍折中了两者的取舍:归约阶段采用减半(如同树状),汇聚阶段采用加倍,以接近最优的带宽代价换取 \(\mathcal{O}(\log N)\) 个延迟步骤。
环形与树状之间的决策边界同时取决于消息大小和参与方数量。对于由 公式 3 和 公式 4 建模的 2 的幂次方情形,令两者相等即可得到 公式 9 中的交叉点:
\[ M_{\times}(N) = n^* \times \frac{(N-1)-\log_2 N}{\log_2 N-(N-1)/N}, \qquad n^*=\alpha\beta \tag{9}\]
- \(M > M_{\times}(N)\)(大梯度):环形的建模代价更低,因为其较小的带宽系数抵消了额外的启动步骤。
- \(M < M_{\times}(N)\)(屏障、标量):树状的建模代价更低,因为其延迟启动项的对数优势超过了额外的带宽代价。
- \(M \approx M_{\times}(N)\)(中等张量):两种建模代价相近,因此应在目标拓扑上将其与递归减半加倍一并基准测试。
算法选择指南 为选择合适算法提供了指导。
| 形态 | 环形 | 树状 | 递归减半加倍 |
|---|---|---|---|
| \(M > M_{\times}(N)\) | 在所示模型下代价更低 | 带宽项更高 | 带宽接近最优且步骤数为对数的候选方案 |
| \(M < M_{\times}(N)\) | 线性启动项更高 | 在所示模型下代价更低 | 启动步骤数为对数的候选方案 |
| \(M \approx M_{\times}(N)\) | 在目标拓扑上基准测试 | 在目标拓扑上基准测试 | 在目标拓扑上基准测试 |
| 2 的幂次方 \(N\) | 对任意 \(N\) 均适用 | 与所示 \(\log_2 N\) 模型一致 | 需要 \(N = 2^k\) |
分层 AllReduce
现代集群具有两级拓扑:节点内的 GPU 通过 NVLink(450 GB/s)互联,而节点之间通过 InfiniBand(50 GB/s)互联。分层 AllReduce 利用这种非对称性分为三个阶段:
- 节点内归约(NVLink):每个节点将其 8 个本地 GPU 通过 NVLink 的 450 GB/s 带宽归约为单一结果。由于 NVLink 的单方向速率是 InfiniBand NDR 端口的 9×,因此这一阶段很快。
- 节点间 AllReduce(InfiniBand):各节点的结果在节点之间执行全归约。每个 8 个本地 GPU 中仅有一个代表参与,因此节点间环的参与方数量仅为扁平 GPU 级环的八分之一。
- 节点内广播(NVLink):每个节点通过 NVLink 将全局结果广播给其 8 个本地 GPU。
分层方法将节点间环的规模从全部 GPU 缩减为每个 8 个本地 GPU 的一位代表,使延迟步骤项减少约 8\(\times\),并将带宽密集型阶段限制在快速的节点内链路上。NCCL 会根据集合通信类型、消息大小、拓扑、架构和版本,在拓扑感知算法(如 Ring、Tree、CollNet 变体、NVLS/NVLSTree、PAT)之间进行选择;分层通信在多节点系统中很常见,但并非通用默认方案。
理解集合通信的代价结构,有助于分析数据并行的开销。流水线并行引入了另一种类型的开销:流水线阶段之间的顺序依赖所导致的空闲时间。
流水线算术
Systems Perspective 1.4: 为何这很重要
冒泡比例
在具有 \(p\) 个阶段和 \(m\) 个微批次的流水线中,公式 10 定义了冒泡比例,即 GPU 总时间中空闲所占的比例:
\[ b_{\text{pipe}} = \frac{p - 1}{p - 1 + m} \tag{10}\]
该公式同时适用于 GPipe(所有前向传播先完成,然后才开始任何反向传播)和 1F1B(前向与反向交错执行)两种调度。1F1B 调度的渐近冒泡比例相同,但由于更早释放微批次,其峰值显存占用更低。
冒泡比例取决于阶段数与微批次数的比值。在阶段数固定的情况下增加微批次,可以将流水线填充与排空分摊到更多有效工作之上。
经验法则:将冒泡开销控制在 20% 及以下需要 \(m \geq 4(p - 1)\);严格低于 20% 需要 \(m > 4(p - 1)\)。实用规则 \(m \geq 4p\) 是一个便于保守采用的目标。
流水线深度与微批次数量(表 2)决定有效冒泡比例。
| 流水线阶段 (\(p\)) | \(m\) = 8 | \(m\) = 16 | \(m\) = 32 | \(m\) = 64 |
|---|---|---|---|---|
| \(p\) = 4 | 27.3% | 15.8% | 8.6% | 4.5% |
| \(p\) = 8 | 46.7% | 30.4% | 17.9% | 9.9% |
如表所示,扩展到更深的流水线需要按比例增加微批次数,以维持较高的加速器利用率。当激活值内存容量限制了微批次数时,系统必须采用其他调度策略来降低气泡开销。
交错调度
交错调度(用于 Megatron-LM)为每个物理 GPU 分配 \(V\) 个虚拟阶段,而非一个。每个 GPU 处理模型中 \(V\) 个不连续的分块,这意味着流水线具有 \(p \times V\) 个虚拟阶段,但气泡开销仍使用原始的 \(p\),如 公式 11 所示:
\[ b_{\text{interleaved}} = \frac{p - 1}{p - 1 + m \times V} \tag{11}\]
分母中的微批次项乘以 \(V\),这是相对于 公式 10 而言的,因此气泡开销的降幅趋近于 \(V\),条件是 \(m\) 远大于 \(p - 1\)。对于 \(p\) = 8、\(m\) = 16 和 \(V\) = 4,气泡占比从 30.4 percent 降至 9.9 percent,降幅为 3.1×,代价是阶段间的通信更频繁、单次通信量更小。
交错调度凸显了分布式机器学习中反复出现的一个主题:通信粒度是可调参数。更小、更频繁的传输能改善重叠程度并减少空闲时间,但会增加累计延迟开销。梯度压缩也受同样的权衡关系支配。
压缩的成本效益
Systems Perspective 1.5: 为何重要
压缩方程
梯度压缩将原始的 \(M\) 字节梯度替换为大小为 \(M/r_{\text{comp}}\) 的压缩表示,其中 \(r_{\text{comp}}\) 为压缩比。公式 12 给出了采用压缩时的总时间:
\[ T_{\text{compressed}} = T_{\text{encode}} + T_{\text{transfer}}\!\left(\frac{M}{r_{\text{comp}}}\right) + T_{\text{decode}} \tag{12}\]
当 \(T_{\text{compressed}} < T_{\text{transfer}}(M)\) 时,压缩有益。整理这一不等式可得到 公式 13 中的盈亏平衡条件:
\[ T_{\text{encode}} + T_{\text{decode}} < T_{\text{transfer}}(M) - T_{\text{transfer}}\!\left(\frac{M}{r_{\text{comp}}}\right) \tag{13}\]
在带宽主导的情形下(\(M \gg n^*\)),通信时间随消息大小线性变化,不等式右端可简化为约 \(T_{\text{transfer}}(M) \times (1 - 1/r_{\text{comp}})\)。对于较高的压缩比(\(r_{\text{comp}} \gg 1\)),该值趋近于 \(T_{\text{transfer}}(M)\)——这意味着,只要编解码开销小于未压缩时的通信时间,压缩就值得采用。
Napkin Math 1.3: **工作示例:Top-k 压缩是否划算?**
问题:压缩是否减少了 AllReduce 的总时间?
数学:
- 未压缩 AllReduce:42.4 ms
- 压缩通信:3.2 ms
- 压缩后总时间:5.2 ms
- 加速比:8.2×
结果:压缩在通信时间上带来 8.2× 的加速比。2 ms 的编解码开销只是 42.4 ms 未压缩基线的一小部分。
系统洞见:在这一规模(256 个 GPU、1 GB 梯度)下,梯度压缩显然有利可图。但必须验证其对收敛的影响:top-k 稀疏化会丢弃信息,模型可能需要更多迭代才能达到相同的精度,从而可能抵消每次迭代的加速收益。
盈亏平衡编解码开销上限 (表 3) 随压缩比和未压缩 AllReduce 时间而变化。更高的压缩比可以容忍更大的编解码开销,上限为未压缩集合通信中随带宽变化的部分。
| 压缩比 (\(r_{\text{comp}}\)) | AllReduce = 10 ms(最大编解码开销) | AllReduce = 40 ms(最大编解码开销) | AllReduce = 100 ms(最大编解码开销) |
|---|---|---|---|
| 4\(\times\) | 5.6 | 28.1 | 73.1 |
| 16\(\times\) | 7.0 | 35.1 | 91.4 |
| 64\(\times\) | 7.3 | 36.9 | 95.9 |
| 256\(\times\) | 7.42 | 37.3 | 97.1 |
最终,这些盈亏平衡上限表明,梯度压缩在传输时间占主导的低带宽互连结构上带来最高的净收益。在高速互连结构上,可容忍的编解码开销预算受到严格限制,需要采用轻量级量化或稀疏化算法。
摘要
Key Takeaways: **通信成本是可预测的**
- \(\alpha\)-\(\beta\) 模型:该模型 (\(T(n) = \alpha + n/\beta\)) 将每次网络传输分解为固定的启动成本与随载荷成比例的带宽成本(原则 11)。交叉点消息大小 \(n^* = \alpha \times \beta\) 决定哪种成本占主导。
- 集合通信成本结构:环形 AllReduce、环形 AllGather、环形 ReduceScatter 和两两交换的 AllToAll 包含一个 \((N-1)/N\) 的带宽因子,而它们的延迟项随 GPU 数量线性增长。基于树的算法则以带宽换取对数级延迟扩展。
- 算法选择:消息大小相对于随参与者数量变化的交叉点 \(M_{\times}(N)\) 决定采用显示的环形还是树形模型更便宜。生产环境的选择还会在目标拓扑上对递归减半加倍和分层方案进行基准测试。
- 流水线气泡占比:\(b_{\text{pipe}} = (p-1)/(p-1+m)\) 是流水线并行的基本开销。实用规则 \(m \geq 4p\) 将气泡控制在 20% 以下,而采用 \(V\) 个虚拟阶段的交错调度,在微批次项占主导时使气泡减少量趋近于 \(V\)。
- 梯度压缩:当编解码开销(编码 + 解码)小于所节省的通信时间时,梯度压缩才有利可图。在高压缩比下,未压缩 AllReduce 时间中随带宽变化的部分趋近于开销预算,但收敛影响必须始终得到验证。
- 可预测参数:本附录中的点对点与集合通信模型源自两个硬件参数 (\(\alpha\) 和 \(\beta\)) 与两个工作负载参数(消息载荷 \(n\) 或 \(M\),以及集合通信的参与者数量 \(N\))。对一个集群测量这些量,即可得到分布式训练开销的完整一阶预测,而流水线与压缩模型会引入额外参数。