Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

9.6 通信、容错与工程实践

把 9.2–9.5 的手段都用上之后,训练能跑起来了。但「能跑」与「跑得快、跑得久」之间还有一大段工程距离:通信能不能藏进计算里、坏了能不能快速恢复、两次实验的结果能不能说得清差异从哪来。

这一节面向的是「已经会用并行、但还没把集群用顺」的读者。四个主题:

  1. 通信:集合通信有哪些原语、各自的量级是多少、怎么估时间?
  2. 重叠与压缩:为什么「通信与计算重叠」是吞吐的第一杠杆,梯度压缩能帮上什么忙?
  3. 容错:万卡规模下故障是常态,checkpoint 策略与恢复时间怎么设计?
  4. 配平:5D 并行怎么把各轴并行度分下去?确定性训练牺牲了什么?

9.6.1 集合通信原语与通信量的量级

定义 9.6.1 · 五个必须认识的集合通信原语

设参与通信的卡数为 kk、消息大小为 SS 字节、每卡发送量为 VrankV_{\text{rank}}:

原语 语义 每卡发送量(环状实现,kk 较大时) 在训练里用在哪
Broadcast 一张卡的数据发给所有卡 ≈S\approx S 参数初始化、把超参同步给所有 rank
Reduce 所有卡的数据求和,结果落在一张卡 ≈S\approx S 中心化聚合(参数服务器风格)
All-Reduce 所有卡求和,每张卡都拿到结果 ≈2S\approx 2S DDP 的梯度同步
Reduce-Scatter 求和后按卡分片,每卡只拿自己那 S/kS/k ≈S\approx S ZeRO-2/3 与 FSDP 的梯度归约
All-Gather 各卡的分片拼成完整张量,每卡都拿到完整结果 ≈S\approx S FSDP 计算前聚合参数、序列并行的重排
All-to-All 每卡向所有卡各发一段(等价于一次转置) ≈S(k−1)/k\approx S(k-1)/k 专家并行与序列并行(Ulysses 换头)
Send / Recv(P2P) 点对点 SS(只在相邻两卡之间) 流水线并行的段边界

两条恒等式随时可用:All-Reduce ≈\approx Reduce-Scatter ++ All-Gather(这就是 ZeRO-2 能用更便宜的原语替换 All-Reduce 的原因);All-Gather 与 Reduce-Scatter 互为「转置」操作(发送量与接收量互换)。

为什么「环状」能省掉一半的通信

朴素的 All-Reduce 想法是「每张卡都向其他人收集一遍」,那是 S(k−1)S(k-1) 的量级。环状算法把它改成接力:

  1. 把张量切成 kk 块,每张卡从右手邻居收一块、加到自己的对应块上、再传给左手邻居——转 k−1k-1 圈后,每一块的总和正好落在某一张卡上(这是 reduce-scatter);
  2. 第二轮沿环把「已经算好的块」传开,每张卡收齐 kk 块就得到完整结果(这是 all-gather)。

两轮各 S(k−1)/kS(k-1)/k,合计 ≈2S\approx2S。关键洞察是「流量守恒」:每个字节至少要被每张卡看见一次,所以 SS 是下界;环状算法只用了两倍的下界,而且并发走满所有链路,不依赖任何中心节点。

工程含义:通信时间由「带宽」与「延迟」共同决定。大消息时 t≈V/βt\approx V/\beta 由带宽决定;小消息时固定延迟(每次通信的握手、kernel 启动)占主导。这解释了为什么「把多个小消息打包成大消息」(梯度分桶)能显著提速。

例 9.6.1 · 三种原语的通信时间对比

k=8k=8 张卡,消息大小 S=14S=14 GB(7B 模型的 bf16 梯度)。链路为节点间 InfiniBand 400 Gb/s(β≈50\beta\approx50 GB/s)。分别估算 All-Reduce 与 Reduce-Scatter 的每卡时间,并说明 ZeRO-2 的收益;再说明若走 NVLink(β≈300\beta\approx300 GB/s)会怎样。

解

All-Reduce(DDP 口径)。 V=2×k−1kS=2×78×14=24.5 GB⇒t=24.550≈0.49 s.V=2\times\frac{k-1}{k}S=2\times\frac78\times14=24.5\ \text{GB}\Rightarrow t=\frac{24.5}{50}\approx0.49\ \text{s}.

Reduce-Scatter(ZeRO-2 口径)。 V=k−1kS=78×14=12.25 GB⇒t=12.2550≈0.25 s.V=\frac{k-1}{k}S=\frac78\times14=12.25\ \text{GB}\Rightarrow t=\frac{12.25}{50}\approx0.25\ \text{s}. 省一半——因为归约后的完整结果不再需要广播给所有卡(每卡只需要自己分片的那段)。

换 NVLink。 All-Reduce 的 t≈24.5/300≈0.08t\approx24.5/300\approx0.08 s,省 6 倍。但真实节点内很少需要跨卡 All-Reduce 整个模型:ZeRO 与 FSDP 的分片通信天然发生在节点内,只有数据并行的跨节点梯度同步才走 IB。

量级小结表(同一 S=14S=14 GB):

场景 原语 每卡流量 IB 时间 NVLink 时间
DDP 梯度同步 All-Reduce 24.5 GB 0.49 s 0.08 s
ZeRO-2 梯度归约 Reduce-Scatter 12.25 GB 0.25 s 0.04 s
FSDP 参数聚合(每层) All-Gather 单层量级(KB–MB) 延迟主导 延迟主导

结论:大消息看带宽、小消息看延迟。跨机的 GB 级 All-Reduce 是秒级开销,必须靠「更大的计算量摊薄」或「与计算重叠」来隐藏,而不是指望链路变快。■\blacksquare

∎

9.6.2 通信与计算重叠

让通信藏进计算里的四种做法
做法 机制 适用于 关键参数
梯度分桶 + 异步归约 反向每算完一层就把该层梯度放入一个桶,桶满立刻发起 All-Reduce(不等整网反向结束),与后续层的计算重叠 DDP / ZeRO 桶大小(bucket size);太小 → 消息碎、延迟占比高;太大 → 重叠窗口不足
参数预取 FSDP / PP 在算第 ll 层时,提前发起第 l+1l+1 层的 All-Gather / 发送 ZeRO-3 / FSDP / 流水线 预取深度(多留几份参数 → 显存换重叠率)
计算分块(chunking) 把一个大矩阵乘切成小块,每块算完就可参与通信(如 FlashAttention 的分块 + 环状传 KV) 长序列注意力、序列并行 块大小与通信/计算比
通信算子融合 把 All-Reduce 与相邻的逐元素算子(如加法、缩放)合成一个内核,省一次读写 ZeRO、TP 框架是否内置(Megatron / DeepSpeed 均有)

判定方法:理想重叠下,tstep≈max⁡(tcompute,tcomm)t_{\text{step}}\approx\max(t_{\text{compute}},t_{\text{comm}});无重叠时 tstep≈tcompute+tcommt_{\text{step}}\approx t_{\text{compute}}+t_{\text{comm}}。用 profiler 把二者时间线画出来,看通信内核是否与计算内核在时间上重叠——这是判断「重叠有没有生效」的唯一可靠方法。

重叠的本质是「让两种不同的资源同时开工」

GPU 的计算单元(Tensor Core / SM)与网卡(NIC)是两组独立的硬件。如果训练是「算一会儿 → 等通信 → 再算」,那么网卡忙的时候计算单元空着,两者交替各闲一半。

重叠的本质就是给这两种资源同时派活:把计算切成能独立进行的块,让「第 ii 块的通信」与「第 i+1i+1 块的计算」并行。

它有一个硬约束:重叠需要多留一点显存(预取的参数、分桶的梯度缓冲、双缓冲的激活)。所以「显存换重叠」与「重叠换吞吐」是同一件事的两面。当显存极度紧张时,重叠率必然下降——这也解释了为什么小显存卡上跑多卡训练,扩展效率总是比大显存卡低。

例 9.6.2 · 重叠与不重叠差多少

某配置每步 tcompute=20t_{\text{compute}}=20 s,tcomm=8t_{\text{comm}}=8 s。求无重叠、理想完全重叠、以及实际重叠率 60% 三种情况下的单步时间与扩展效率差异(假设 8 卡)。

解

(1)无重叠。 t=20+8=28t=20+8=28 s。

(2)理想完全重叠。 t=max⁡(20,8)=20t=\max(20,8)=20 s —— 通信完全被计算盖住。

(3)实际重叠率 60%。 被隐藏的通信为 0.6×8=4.80.6\times8=4.8 s,暴露的为 3.23.2 s: t=20+3.2=23.2 s.t=20+3.2=23.2\ \text{s}.

对加速比的影响(设单卡基线 t1t_1 与这些数字同比例):不重叠时 8 卡的有效算力利用率相当于 tcomputet=2028=71.4%,\frac{t_{\text{compute}}}{t}=\frac{20}{28}=71.4\%, 而重叠率 60% 时升到 2023.2=86.2%\frac{20}{23.2}=86.2\%,理想重叠时接近 100%100\%。

结论:重叠率是仅次于「气泡」的吞吐杀手,而且它是纯工程问题(分桶、预取、融合),不需要改算法。所以调优顺序里它排得很前。■\blacksquare

∎
梯度压缩与 ZeRO++ 的思路(拓展)

当跨节点带宽成为硬瓶颈时,可以从「少传」入手:

  • 低精度通信:梯度用 bf16(甚至 FP8)传输——DDP 默认已是 bf16;再往下压需要用误差反馈(把量化误差累加到下一步)来保持收敛。
  • 梯度稀疏化:只传超过阈值的梯度分量 + 索引。理论上压缩率高,但索引开销与负载不均衡常常抵消收益,在稠密大模型训练中不如量化稳定。
  • ZeRO++ 的三种组合(DeepSpeed 提出的系统优化,见延伸阅读):① 分层分区——把每卡的梯度分片再切细,使 All-Gather 尽量发生在节点内(把跨机流量降下来);② 量化梯度——跨机通信降到低比特;③ 二级分区——用节点内的另一份副本做聚合。三者都是「用节点内带宽换取跨机带宽」这一思路的具体化。

注意:压缩会改变梯度,从而影响收敛;引入前必须做对照实验(同样的等效批与学习率,比较损失曲线),不能只看吞吐数字。本段属拓展内容,具体收益强依赖拓扑与实现,需按你的环境实测(标注为需核实)。

9.6.3 checkpoint 策略与恢复时间

checkpoint 的四种策略与选择判据
策略 做法 保存时间 恢复粒度 适用
全量(每卡存全模型) 每卡各自 dump 完整模型状态 慢(每卡都写 GB 级) 最简单 小模型、少卡
分片(sharded) 每卡只写自己那 1/k1/k 的模型状态,附带元数据描述分片布局 快(总量 = 模型状态 / 卡数) 需要相同或可重排的分片布局 大模型默认
异步(async) 写盘与训练并行,写的是某一时刻的一致性快照 对训练几乎无阻塞 稍复杂(需要快照机制) 长时间训练
重算(recompute-on-load) 只存最小的种子 / 输入,恢复时重算 最快(存得最少) 最慢(恢复时要重算) 有确定性数据管线的场景

选择判据:用「期望损失」比较——单次故障的平均损失 ≈ 12×\tfrac12\times(checkpoint 间隔)×\times 训练吞吐,而 checkpoint 的固定开销 ≈ 训练时间 ×(保存时间 / 间隔)。两者加总最小处即为最优间隔(与经典的最优 checkpoint 间隔分析同型)。

例 9.6.3 · 7B 的 checkpoint 账与最优间隔

N=7×109N=7\times10^{9},混合精度 Adam(模型状态 112112 GB),用 128128 张卡训练。存储为并行文件系统,聚合写带宽约 22 GB/s(128 卡共享)。若单次故障平均损失 5 分钟的进度,恢复(含重启、加载、重建数据管线)耗时约 33 分钟。

(1)求分片 checkpoint 的数据量与保存时间; (2)若每 2 小时存一次,求「每小时因故障 + checkpoint 造成的平均额外时间」。

解

(1)数据量与时间。 分片写入的总量 = 模型状态总量 = 112112 GB(每卡 112/128=0.875112/128=0.875 GB)。 tsave=112 GB2 GB/s=56 s≈0.93 min.t_{\text{save}}=\frac{112\ \text{GB}}{2\ \text{GB/s}}=56\ \text{s}\approx0.93\ \text{min}. (若用全量策略:128×112=14,336128\times112=14{,}336 GB,t≈t\approx 2 小时 —— 完全不可行,这就是「分片是默认」的原因。)

(2)每小时的额外时间。 设故障率为每小时 ff 次: 额外时间/小时=f×(5+3)⏟故障损失+60120×0.93⏟checkpoint 开销 分钟.\text{额外时间/小时}=\underbrace{f\times(5+3)}_{\text{故障损失}}+\underbrace{\frac{60}{120}\times0.93}_{\text{checkpoint 开销}}\ \text{分钟}. 取 f=0.5f=0.5(每两小时一次故障,见 9.6.4 的量级参考): =0.5×8+0.47=4.5 分钟/小时≈7.5%.=0.5\times8+0.47=4.5\ \text{分钟/小时}\approx7.5\%. 即近 8% 的训练时间花在故障与保存上——这在大规模训练里是必须计入预算的成本,而不是意外。

(3)最优间隔的直觉。 间隔 TT(小时)时,期望故障损失 ≈0.5 f T×8\approx 0.5\,f\,T\times8 分钟(平均等到间隔中点),保存开销 ≈(60/T)×0.93\approx(60/T)\times0.93 分钟。对 TT 求导取零:4f=55.8T2⇒T≈55.84f4f=\frac{55.8}{T^{2}}\Rightarrow T\approx\sqrt{\frac{55.8}{4f}}。f=0.5f=0.5 时 T≈5.3T\approx5.3 小时 —— 间隔越短不一定越好,因为保存本身也要时间(当然真实系统还会加上「必须能在可接受时间内恢复」的硬约束)。■\blacksquare

∎

9.6.4 大规模故障率与容错设计

为什么「故障」在大规模训练里是工程常量

把单个组件的故障率想成 λ\lambda(次/小时)。系统里有 GG 个组件(GPU、网卡、光模块、电源、交换机端口),整体故障率近似 GλG\lambda,平均无故障时间(MTBF)≈ 1Gλ\dfrac{1}{G\lambda}。

数量级感受:假设单卡的小时故障率 λ≈3×10−6\lambda\approx 3\times10^{-6},则

卡数 GG 期望 MTBF 换算
8 ≈4.2×104\approx 4.2\times10^{4} 小时 基本无感
512 ≈650\approx 650 小时 近一个月一次
8192 ≈41\approx 41 小时 一到两天一次
16384 ≈20\approx 20 小时 几乎每天

读法:故障率随规模线性增长,而训练时长不变(大模型要跑几周到几个月),于是「每天都坏」成为常态。公开的工程记载(如 Llama 3 的技术报告,2024,arXiv:2407.21783)也报告了万卡级训练中远高于单机的计划外中断率 —— 具体数字随集群与统计口径差异很大,引用时需核对原始报告的统计窗口(标注为需核实)。

因此容错不是「以防万一」,而是与吞吐并列的设计目标:检错(谁坏了、有没有静默数据损坏)→ 恢复(多快能重启)→ 一致性(恢复后训练是否等价于没坏过)。

容错设计清单
层次 要做的事 常见做法 代价
检错 快速发现「哪张卡坏了」而不是整机挂掉 心跳 / NCCL 超时、健康检查脚本(跑一个小的 all-reduce + 矩阵乘自测) 检测延迟通常几分钟
恢复 重启后把状态恢复到一致点 分片 checkpoint + 元数据(分片布局、数据管线位置、优化器步数) 加载时间随模型大小上升
弹性 坏卡就绪后重新组队继续 在支持弹性训练的框架里重配进程组(各框架支持度不同,需核实) 需要重排分片与数据分片
静默损坏 检测「没报错但算错了」 抽样校验(周期性比对手工计算的损失值 / 梯度范数是否落在期望范围) 额外计算极少,但需要对照基准
确定性 让「恢复后」与「未中断」一致 固定数据顺序与种子(9.6.5) 牺牲部分吞吐与灵活性
容错与恢复的五个高频误解
  1. 「有 checkpoint 就不怕」。checkpoint 只解决「丢多少进度」,不解决一致性:恢复后若数据顺序被打乱、或 optimizer 步数对不上,训练是「悄悄换了实验条件」。元数据必须和权重一起存。
  2. 「异步 checkpoint 一定更快」。它把写盘与计算重叠,但需要快照一致性机制(否则存下来的是不同时刻的混合状态);在写的过程中若发生故障,可能得到不可用的文件。通常做法是「周期性同步 + 更频繁异步」。
  3. 「坏卡换掉重启就行」。还要检查数据分片与随机状态是否重放正确;若用固定的 global batch 索引恢复,需要框架支持「按步数而不是按数据流位置」恢复。
  4. 「故障率与卡数无关,是概率运气问题」。故障率随组件数线性增长,是统计必然;把大规模训练的失败归因于「运气不好」会导致完全错误的预算规划。
  5. 「确定性训练只是加个种子」。要同时固定:数据顺序、随机初始化、dropout/采样、算子实现(有些算子没有确定实现)、归约顺序。缺任何一项,两次运行都会有微小差异,且并行度不同时差异更明显。

9.6.5 确定性训练与 5D 并行配平

定义 9.6.2 · 5D 并行的五个轴

在 3D(DP × TP × PP)之上再加两轴:

轴 切什么 通信特征 常用取值
DP(数据并行) 数据 每步一次大 All-Reduce(≈2S\approx2S) 最外层,尽可能大
TP(张量并行) 层内权重与激活 每层若干次 All-Reduce,延迟敏感 ≤ 单机 GPU 数(常 4 或 8)
PP(流水线并行) 层 段间 P2P,量小 2–16,配合 M≥M\ge 若干倍 PP
EP(专家并行,MoE 专用) 专家(FFN 的多个分支) All-to-All,量中等、模式复杂 与专家总数、拓扑强相关
CP / SP(上下文 / 序列并行) 序列维(激活与 KV) 环状或 all-to-all(注意力需交换) 长序列才需要

配平原则:① 通信最密集的轴放在最快的链路(TP 在 NVLink 内);② 通信最少的轴放最外层(DP 跨机);③ 各轴乘积必须等于总卡数;④ 每一轴都要守住自己的整除约束(TP 要整除头数与 FFN 隐维;PP 要整除层数;EP 要整除专家数)。

配平不是「找最优解」,而是「先满足硬约束再优化软目标」

硬约束(必须满足,否则跑不起来):

  1. 显存:每卡模型状态 + 激活 + 通信缓冲 ≤ 卡容量;
  2. 整除性:TP / PP / EP 的并行度必须能整除对应的结构量;
  3. 拓扑:TP 不出节点。

软目标(在满足硬约束的可行解里挑):

  1. 扩展效率最大化:等价于「让最贵的通信尽量小、尽量被重叠」;
  2. 气泡最小:MM 足够大;
  3. 批量与学习率的兼容:全局批不要大到需要改优化器配方。

所以实践里的流程是:列出可行解 → 按软目标排序 → 用一小段基准测试(benchmark)实测两三个候选 → 定稿。没有人靠纯算就能定下最终配置——因为通信时间取决于实际拓扑与内核质量。

5D 配平的示例表(以 4096 卡、bf16、长序列为例)

下表是示例量级,用于建立「各轴怎么分」的直觉;真实取值必须按模型结构、显存与拓扑重算:

模型规模(示例) 总卡 4096 的一种分法 说明
7B TP 1 × PP 2 × DP 2048 7B 单卡放得下(ZeRO-2 后 2626 GB),几乎不需要 TP/PP;此规模通常不用 4096 卡
70B TP 4 × PP 8 × DP 128 TP 留在节点内(4 卡一组);PP 8 段配 M≥64M\ge64;DP 承担主要并行度
400B+(稠密) TP 8 × PP 16 × DP 32(× 可用 CP 若干) TP 吃满单机 8 卡;PP 16 段对气泡要求高;DP 变小后 ZeRO 分片更关键
MoE 类(总参数百 B、激活数十 B) TP 8 × PP 8 × EP 8 × DP 8 EP 引入 All-to-All,需与 TP 共享拓扑预算;具体配平强依赖专家数与路由设计,需按报告核对

读表要点:随着模型变大,TP 与 PP 先增大(吃紧的是单卡显存与层数),DP 缩小;到了 MoE,多出一个「用 All-to-All 换稀疏激活」的维度。每一行的乘积都等于 4096(MoE 行中 8×8×8×8=40968\times8\times8\times8=4096,EP 与 DP 共享剩余的卡)。注意:这些分解是教学示例,表达的是「各轴怎么分」的推理方式,不是对任何具体训练报告配置的复述——真实配置受模型结构(专家数、层数、头数)、显存与拓扑共同约束,引用具体报告的配平必须回原报告核对(标注为需核实)。

确定性训练:先定口径,再定开关

第一步:决定你要哪一种「确定性」。

口径 含义 可行性
逐位可复现(bitwise) 同配置两次运行结果完全相同 单机单卡可能;多卡 + 高性能算子几乎不可得(浮点归约顺序、非确定性算子)
统计可复现 指标差异在预期噪声内(如损失曲线形态一致) 工程上实际追求的目标
同并行度内可复现 相同卡数与拓扑下可重复 通常可行(固定种子 + 确定性算子)

第二步:把随机性来源逐个钉死。

  1. 数据顺序:固定 sampler 与 worker_init_fn;记录「已消费样本数」作为 checkpoint 的一部分(否则恢复后数据流会重置)。
  2. 权重初始化:固定种子;注意并行度不同时初始化的划分方式也可能不同(每卡初始化自己那部分),所以「同一种子、不同 TP 度」不产生同一模型。
  3. Dropout / 采样:掩码要与并行切分一致(定义 9.3.2 的注记)。
  4. 算子确定性:开启确定性算法开关(如 torch.use_deterministic_algorithms(True)),并接受由此带来的性能损失与被禁用的算子(哪些算子受影响随版本变化,需核实)。
  5. 归约顺序:跨卡归约的实现顺序由拓扑决定;不同卡数下浮点求和顺序不同,这就是「逐位可复现」多卡下不可得的根本原因(见 9.1.6 陷阱 9 关于浮点结合律的讨论)。

第三步:把「不确定但可控」的部分写进实验记录:卡数、并行配置、桶大小、精度、算子开关——这些都属于 工具箱 要求的「一次训练的最小记录集」。

工程实践中的七个高频误解
  1. 「扩展效率低就是硬件不行」。先按顺序查:批太小(算力利用率低)→ 通信未重叠 → 气泡太大 → 段间负载不均 → 最后才怀疑硬件。
  2. 「通信量算出来很小,所以通信不是瓶颈」。小消息受延迟支配,量小不等于时间短。分桶、融合、增大单次消息都是针对延迟的手段。
  3. 「重叠是框架自动做好的」。默认开关往往只覆盖一部分;桶大小、预取深度、是否融合都需要按模型调。
  4. 「checkpoint 越频繁越安全」。保存本身要时间(例 9.6.3:7B 约 1 分钟/次),频率过高反而净损失。
  5. 「万卡训练主要成本是算力」。故障恢复、通信开销、气泡、调参实验都要计入;工程界普遍认为非计算开销占比相当可观(具体比例随配置差异大,不作定量断言)。
  6. 「恢复训练只要把权重读回来」。数据流位置、优化器步数、随机状态、(若用)学习率调度器的位置都必须恢复,否则等价于换了个实验。
  7. 「确定性只是可复现性要求,不影响其他」。开确定性算子通常要牺牲吞吐(禁用最快的内核),所以它是「可复现性 vs 速度」的显式取舍,而不是免费的开关。
即时自测 · 9.6

Q1 写出 All-Reduce 与 Reduce-Scatter 的每卡流量(用 SS、kk 表示),并说明为什么 ZeRO-2 能用后者替代前者。

Q2 某步 tcompute=30t_{\text{compute}}=30 s、tcomm=12t_{\text{comm}}=12 s,实际暴露的通信时间 4.8 s。求实际单步时间与重叠率。

Q3 万卡集群的 MTBF 为什么远小于单卡?给出「组件数 × 单组件故障率」的推导思路。

Q4 为什么多卡训练难以做到「逐位可复现」?至少给出两个来源。

参考要点

Q1 All-Reduce:2S(k−1)/k≈2S2S(k-1)/k\approx2S;Reduce-Scatter:S(k−1)/k≈SS(k-1)/k\approx S。ZeRO-2 中梯度也被分片,每卡只需要自己那 1/k1/k 份的和,不需要让所有卡都拿到完整的平均梯度,所以可以用「只归约不广播」的 Reduce-Scatter 替代需要「归约 + 广播」的 All-Reduce,流量因此约减半。

Q2 隐藏的通信 =12−4.8=7.2=12-4.8=7.2 s,重叠率 =7.2/12=60%=7.2/12=60\%。单步时间 =30+4.8=34.8=30+4.8=34.8 s(若不重叠则为 4242 s)。

Q3 整体故障率近似为各组件故障率之和:λsys≈Gλ\lambda_{\text{sys}}\approx G\lambda,故 MTBF≈1/(Gλ)\text{MTBF}\approx1/(G\lambda),随 GG 线性缩短。单卡 8 张时以万小时计,8192 张时降到几十小时量级——而训练时长不变(数周),于是故障成为常态而非意外。

Q4 两个来源:① 浮点归约顺序不同(环状 versus 树状、不同卡数、不同切分)导致求和结果在最低位不同,误差随后被放大;② 非确定性算子(原子加、某些卷积/归约实现)本身不保证顺序固定。其他可接受答案:不同并行度下 dropout 掩码划分不同、不同内核实现的累加精度不同(如 bf16 累加 vs fp32 累加)、数据加载的多 worker 顺序。

延伸阅读
  • Narayanan et al., Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM(2021,arXiv:2104.04473)——通信量分析与重叠策略的经典参考。
  • Zhao et al., PyTorch Distributed: Experiences on Accelerating Data Parallel Training(2020,arXiv:2006.15704)——DDP 的梯度分桶与重叠实现。
  • Wang et al., ZeRO++: Extremely Efficient Collective Communication for Giant Model Training(2023,arXiv:2306.10209)——分层分区、量化梯度与二级分区的系统优化。
  • PyTorch 官方文档:torch.distributed.checkpoint(分片存取)、torch.use_deterministic_algorithms(确定性开关)(截至 2025 年,无对应论文,以官方文档为准)。
  • Llama 3 技术报告(2024,arXiv:2407.21783)——万卡级训练的中断率、并行配置与工程实践的公开记载(统计口径需核对)。
  • DeepSeek-V3 技术报告(2024,arXiv:2412.19437)——MoE 训练的并行配平与通信-计算重叠(DualPipe)工程记载。

本节小结:集合通信的量级可以用三行公式记住——All-Reduce ≈2S\approx2S、Reduce-Scatter / All-Gather ≈S\approx S、P2P 只有 SS;大消息看带宽、小消息看延迟。吞吐的第一杠杆是重叠(分桶、预取、分块、融合),但它要以显存为代价。规模上去以后,故障是与吞吐并列的设计目标:MTBF 随组件数线性缩短,checkpoint 的最优间隔由「期望故障损失」与「保存开销」共同决定,而恢复的一致性(数据流、步数、随机状态)常被忽略。最后,5D 配平是「先满足硬约束、再优化软目标」的流程,确定性训练则是「可复现性 vs 吞吐」的显式取舍。下一节把这些全部落到一个具体问题:手上有 1–8 张卡,到底该怎么配。