按层切到不同卡上,为什么有卡在等?
本课一问:张量并行只能留在一台机里。卡再多,最自然的切法是按层切:64 层分成几段,每段放一张(或一组)卡,跨机只传段与段之间的激活。可这样一来,为什么总有卡在空等?
这一课先不碰:长序列(岔路 1)与 MoE 专家(岔路 2);DualPipe 的完整调度只给公式;段与段之间的通信时间(模拟里记为 0)。
从已有出发
切什么每张卡一份完整模型,各算全局 batch 的 1/N;反向之后把 N 份梯度加起来,每张卡用同一份梯度更新。
多出的通信all-reduce 梯度
有多大锚点 BF16 梯度 55.6 GB;8 卡 ring all-reduce 每卡每步发 97.2 GB。
切什么优化器状态、梯度、参数按 N 份切开,每张卡只存、只更新自己那份;ZeRO-3 在用到一层之前把这一层的参数拼回来。
多出的通信reduce-scatter 梯度 + all-gather 参数
有多大8 卡 ZeRO-3:每卡模型状态 55.6 GB(原来 444.5 GB);通信每卡每步 145.9 GB,是 DP 的 1.5 倍。
切什么一层里的矩阵乘拆给 t 张卡:第一个矩阵按列切、第二个按行切,非线性各算各的,最后一次 all-reduce。
多出的通信每层 all-reduce(前向 2 次、反向 2 次)
有多大t = 8、每 4,096 个 token:每卡发 18.8 GB,每层都要等它做完;所以只放在一台机的 8 张卡里。
切什么把 64 层按顺序切成 p 段放在不同的卡上,每段做完把激活交给下一段,反向时再把梯度传回来。
多出的通信段与段之间 send / recv 激活
有多大锚点每段 8 层(p = 8);每个 micro-batch(4,096 个 token)在段间传 0.0 GB 激活;代价是气泡:p = 8、m = 32 时 21.9%。
切什么一条很长的序列切给几张卡,每张卡只存自己那段 token 的激活;注意力需要全部 K、V,就让 K、V 块沿环传一圈。
多出的通信注意力里沿环传 K、V
有多大s = 131,072、8 卡:每张卡每一步传出一块 K、V 0.1 GB,每个全注意力层传 7 块。
切什么MoE 的专家分到不同卡上,token 用 all-to-all 发到持有对应专家的卡,算完再 all-to-all 收回来。
多出的通信FFN 前后各一次 all-to-all
有多大DeepSeek-V3:256 个路由专家 ÷ 64 张卡 = 每卡每层 4 个;每个 token 最多去 4 个节点。
前三课切的是数据、模型状态、层内矩阵;这一课切「层」本身。它的吸引力在通信上:按层切时,段与段之间只传一份激活。锚点一个 micro-batch(4,096 个 token)在一个段边界上传 4,096 × 5,120 × 2 字节 = 41.9 MB,前向一次、反向一次;对比上一课张量并行同样 4,096 个 token 每卡要发 18.8 GB。所以跨机的那一维通常交给流水线。
这一课讨论的是 micro-batch 在层之间怎么流动,序列的内容不进入调度,所以贯穿例句不出场:下面的每一格都是「某一段处理某一个 micro-batch」。
先自己设计:切成 8 段,整批依次流过
锚点 64 层切成 p = 8 段,每段 8 层。最朴素的跑法:整个 batch 先在第 0 段做前向,交给第 1 段……到第 7 段算出 loss,再从第 7 段一路反向回来。
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
第 0 段做完第 0 个 micro-batch,就交给第 1 段,自己接着做第 1 个——几个 micro-batch 同时在不同的段里流动。空等只剩开头的「灌满」和结尾的「排空」。
改进一:micro-batch,气泡降到 (p−1)/m
GPipe(Huang 等,2018)把一批切成 m 个 micro-batch。设一段处理一个 micro-batch 的前向用 F、反向用 B,整条流水线的时间是 (m + p − 1)(F + B),其中每张卡真正在干活的只有 m(F + B)。多出来的 (p − 1)(F + B) 就是气泡:
这个公式是由调度直接推出来的 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条原文:气泡时间比 = t_pb / t_id = (p−1)/m,分母是理想计算时间。GPipe 论文 §2.2 写的是 O((K−1)/(M+K−1)),分母是总时间。 出处Narayanan et al. 2021 §2.2(需联网) ↗需联网 。可 m 不能无限加:全局 batch 固定时,m 越大,每个 micro-batch 越小,矩阵乘越吃不满卡;GPipe 还有一个更直接的代价——所有前向做完才开始反向,每段要同时存 m 份激活。
改进二:1F1B,激活从 m 份压到 p 份
PipeDream(Harlap 等,2018)的调度是「一前一后」:第 d 段先做 p − d − 1 个前向热身,之后做一个前向、做一个反向,交替进行,反向做完就释放那一份激活。气泡和 GPipe 一样多,但 0 号段最多同时存 p 份激活,而不是 m 份 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条原文:1F1B(PipeDream-Flush)把在途 micro-batch 限制在流水线深度 p 以内。组件里「0 号卡最多同时存几份」是模拟逐步数出来的。 出处Narayanan et al. 2021 §2.2 ↗需联网 。
改进三、四:interleaved 与 Zero Bubble
下面这个组件把五种调度放在一起。每一种的执行顺序都由它的算法生成——GPipe、1F1B、Megatron 的 interleaved 1F1B、Zero Bubble 的 ZB-H1——再按「F 等前一段、B 等后一段」的依赖关系逐个排时间:
试三件事:① 先在曲线上方做预测,再看:m 从 32 翻到 64,相对理想时间的气泡大约减半,但永远到不了 0;② 在 GPipe 与 1F1B 之间来回切,总时长与气泡一模一样,读「0 号卡最多同时存几份」——32 份对 8 份;③ 切到 interleaved(v = 4),气泡从 21.9% 降到 5.5%;再切到 Zero Bubble,看紫色的 W 块是怎么填进原来的斜纹空等里的。
- interleaved 1F1B(Narayanan 等,2021):每张卡放 v 段不连续的层(卡 0 放第 0 段和第 8 段……),一个 micro-batch 要在卡之间转 v 圈,每一格变成原来的 1/v,灌满和排空也缩成 1/v,气泡 (p−1)/(v·m)。代价是段间的点对点通信多了 v 倍,并要求 m 是 p 的整数倍。
- Zero Bubble(Qi 等,2023):反向其实是两件事——算「对输入的梯度」B(前一段在等它)和算「对权重的梯度」W(谁也不等它)。把 W 挪出关键路径、拿去填空等:F、B、W 各用 1 份时间时,ZB-H1 每段的空等是 (p−1)(F+B−W),只有 1F1B 的 (p−1)(F+B+W) 的 1/3,显存与 1F1B 相同 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条气泡公式由调度推出;吞吐的提升是论文实测:同等显存下比 1F1B 最多高 23%,放宽显存后最多 31%。组件的 ZB-H1 按论文规则贪心生成,在 F = B = W 时与公式逐位相等。 出处Qi et al. 2023(Zero Bubble,需联网) ↗需联网 。
现代:DualPipe,把通信也藏起来
DeepSeek-V3 用 16 路流水线,并设计了 DualPipe:micro-batch 从流水线的两头同时喂进来,一个前向块和一个反向块成对执行,把专家并行的 all-to-all 和流水线的通信藏到对方的计算后面(岔路 2 会回到这一点)。报告表 2 给出三种调度的对比 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条公式是报告给出的;「all-to-all 与 PP 通信可以完全隐藏」是报告对其实现的自述。 出处DeepSeek-V3 报告 §3.2.1 表 2(本地 PDF) ↗ ,把 F = 1、B = 2(整段反向)、W = 1 代进去,p = 8:
| 调度 | 气泡(报告表 2) | 代入 F = 1、B = 2、W = 1 | 参数 | 激活 |
|---|---|---|---|---|
| 1F1B | (PP − 1)(F + B) | 21 | 1 份 | PP 份 |
| ZB1P | (PP − 1)(F + B − 2W) | 7 | 1 份 | PP 份 |
| DualPipe | (PP/2 − 1)(F&B + B − 3W) | 3 × (F&B − 1):F&B 是一对前向、反向块重叠执行的时间,介于 2 与 3 之间,所以是 3 到 6 | 2 份 | PP + 1 份 |
DualPipe 的代价写在最后两列:要存两份参数(报告说因为专家并行切得很大,这不太增加显存),激活多一份。它还要求段数和 micro-batch 数都是偶数,但不要求 micro-batch 数是段数的整数倍。
常见误解之一:「8 段流水线 = 8 张卡同时在算,所以快 8 倍。」
不切 micro-batch 时,8 张卡里任何时刻只有 1 张在算。流水线并行首先解决的是「放不下」;要快,得靠 micro-batch 把流水线填满,而灌满、排空的 p − 1 格永远在。
常见误解之二:「micro-batch 越多越好。」
m 越大气泡越小,但:GPipe 的激活随 m 涨;全局 batch 固定时 m 越大,每个 micro-batch 越小、矩阵乘越吃不满卡;全局 batch 也受收敛性约束(C5 岔路)。
常见误解之三:「气泡率就是 (p−1)/m。」
那是「空等 ÷ 理想时间」。空等占总时间的比例是 (p−1)/(m+p−1):p = 8、m = 32 时一个是 21.9%,一个是 17.9%。读论文和博客时先看它用的是哪一个。
🔍 锚点切 8 段,最后一段为什么总是最慢?
上面的模拟假设每段一样快。锚点真切起来并不均匀:最后一段除了 8 层,还有 lm_head——每个 token 要和 248,320 个词的输出向量各做一次点积,算量 2 × 5,120 × 248,320 ≈ 2.54 GFLOP/token;而一层平均 3.81 亿个参数,约 0.76 GFLOP/token。lm_head 一个就顶约 3.3 层,最后一段比别的段慢四成,整条流水线都要等它。实际配置会少给首尾两段分几层;DeepSeek-V3 的 DualPipe 则把最浅的层(含 embedding)和最深的层(含输出头)放在同一张卡上,让 MTP 与主模型共享这两块参数和梯度(报告 §3.2.3)。
证据三问
| 问 | 本课的回答 |
|---|---|
| ① 它解决什么问题? | 模型大到一台机放不下、张量并行又不能跨机时,按层切开,跨机只传段间激活 |
| ② 数学上为什么可能有效? | 由调度推出的气泡公式:GPipe / 1F1B 为 (p−1)/m(相对理想时间),interleaved 再除以 v,ZB-H1 每段空等 (p−1)(F+B−W) 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条组件逐个模拟,与这些闭式公式逐位相等(通信记为 0)。 出处Narayanan 2021;GPipe;Qi 2023 ↗需联网 |
| ③ 实验上为什么最后选了它? | Megatron 2021 用 PP 与 TP、DP 组合,在 3,072 张 GPU 上训 1T 参数的模型,达到峰值的 52%;DeepSeek-V3 与 Llama 3 都用 16 路流水线 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条作者自报的实测与配置。 出处Narayanan 2021 摘要;DeepSeek-V3 §3.2;Llama 3 表 4 ↗需联网 |
演进地图:你在这里
- 解决了训练一步的全部东西都在一张卡上,不需要任何通信。卡在锚点的模型状态 16 字节 × 27,781,427,952 = 444.5 GB,是 80 GB 的 5.6 倍;就算放得下也太慢:DeepSeek-V3 预训练用了 2,664K H800 GPU 小时,一张卡约 304 年。
- 解决了每卡一份完整模型、算 1/N 的数据,每步把梯度加起来。ring 让每卡只收发 2(N−1)/N 倍梯度:锚点 8 卡 97.2 GB、64 卡 109.4 GB(汇总到 0 号卡的朴素做法:388.9 GB → 3,500 GB)。卡在只解决「慢」:每张卡仍要放下完整的 444.5 GB。
- 解决了反向逐层产出梯度,攒满一桶(默认 25 MiB)就先发,通信藏到后面几层的反向里。卡在DP 的通信量每步固定:锚点 8 卡每卡 97.2 GB,按 IB 50 GB/s 要 1.94 s;每卡 4,096 个 token 的反向只有约 1.05 s(推演)——token 太少就藏不住。
- 解决了不再每卡存一份:8 卡上 444.5 → 152.8 → 104.2 → 55.6 GB(依次切优化器状态、梯度、参数)。卡在切参数后每步多一次 all-gather,通信是 DP 的 1.5 倍;激活不切:s = 4,096 的选择性重计算要 45.6 GB,放不进剩下的 24.4 GB。
- 解决了第一个矩阵按列切、第二个按行切,一个 MLP 只要一次 all-reduce;t = 8 配序列并行,激活 45.6 → 5.7 GB。卡在每层前向 2 次、反向 2 次同步:每 4,096 个 token 每卡要发 18.8 GB,每层都要等——只能放在机内。ZeRO 原文实测:跨两台 DGX-2,每卡约 5 TFLOPS,不到峰值 5%。
- 解决了按层切,跨机只传段与段之间的激活;切 micro-batch 填满流水线;1F1B 把在途激活从 m 份压到 p 份;interleaved 把气泡除以 v。卡在首尾必然空等:p = 8、m = 32 时气泡 (p−1)/m = 21.9%(占总时间 17.9%),interleaved v = 4 也还有 5.5%。
- 解决了反向拆成「对输入」B 与「对权重」W,W 拿去填空泡(F = B = W 时 ZB-H1 的气泡是 1F1B 的 1/3);DualPipe 从两头喂 micro-batch,并把 all-to-all 藏到另一批计算后面。卡在DualPipe 要存两份参数;调度更复杂;通信只是被藏住了,量一点没少。
- 解决了128K 的序列按序列切给多张卡;zig-zag 头尾配对,把因果负载 10 : 26 : 42 : 58 配平成每卡一样多。卡在每个全注意力层都要在卡之间传 K、V:锚点 s = 131,072、8 卡时每层 0.5 GB;Ulysses 按头切,KV 只有 4 个头。
- 解决了DeepSeek-V3 的 654B 路由专家参数分到 64 张卡,每卡每层 4 个;每个 token 最多去 4 个节点。卡在跨节点 IB 50 GB/s 只有 NVLink 160 GB/s 的约 1/3,跨节点 EP 的计算与通信约 1 : 1;热门专家所在的卡成为掉队者(→ C11)。
- 解决了Llama 3 405B:[TP, CP, PP, DP] = 8 × 1 × 16 × 128,16,384 张 H100,BF16 MFU 41%;DeepSeek-V3:PP 16 × EP 64 × ZeRO-1 DP,不用 TP。卡在没有万能配置:每种组合都要先算清每卡显存、每一维的通信走哪条链路、气泡多大(实验课)。
一句话
流水线并行按层切,但下一段要等上一段的输出、反向又要等后面的梯度,首尾必然空等;切成 m 个 micro-batch 让空等占比降到 (p−1)/m,1F1B 把在途激活压到 p 份,interleaved、Zero Bubble、DualPipe 继续填空。
先停在这里:记住「灌满与排空的 p − 1 格永远在」「1F1B 省的是激活,不是气泡」「两种气泡口径」三句,就可以去实验课。
再深一层:展开 lm_head 的 Dig,再去 PP 调度可视化器里看 DualPipe 的双向调度。
下一个缺口
- 岔路 1:128K 的序列,激活放在哪?——前四课切的都不是「一条序列」本身。
- 岔路 2:MoE 的几百个专家放在哪?token 怎么送过去?——DualPipe 要藏的那个 all-to-all 从哪来。
- 主线:实验课:给锚点在 8 张卡和 64 张卡上各配一套并行方案——数据、状态、矩阵、层,四种切法怎么组合。
你可能会问
- 「流水线的段间通信为什么记成 0?」 为了把「调度本身造成的空等」单独看清。真实系统里段间传激活要时间(锚点每个 micro-batch 每个边界 41.9 MB),它会加到关键路径上,也可以和计算重叠——DualPipe 就是专门做这件事的。
- 「流水线并行和数据并行能一起用吗?」 能,而且总是一起用:一条流水线是一组卡,再复制几条流水线做数据并行。几维怎么排,见实验课。
- 「为什么不直接把 m 设得很大?」 见误解之二:全局 batch 是由训练的收敛性决定的,DP × m × 每个 micro-batch 的大小 = 全局 batch,m 大了别的就得小。