并行训练:DP / ZeRO / FSDP / TP / PP
一句话定位:单卡装不下训练状态时,并行训练把「权重、梯度、优化器状态」三样大件切开分给一群显卡——ZeRO/FSDP 切训练状态、张量并行切层内、流水线并行切层间。前置:预训练 → SFT → RLHF 全流程——「约 16 字节/参数」的显存口诀在那篇建立,本篇全部账目从它出发。
先看一本装不下的账
流程篇给过显存口诀:混合精度训练时每个参数要占约 16 字节——权重 2、梯度 2、优化器状态 12。拿 7B 模型一算就是 100 GiB 出头,单卡(80 GB 档)装不下;100B 模型更是要 1.5 TiB,任何单卡都免谈。
显卡不够,那就把训练摊到一群显卡上。
但「摊」的方式决定成败:切得不对,显卡之间互相等待的时间比干活还长。
切什么、怎么切、通信代价是什么,就是本篇要回答的问题。
答案是一族按「切什么」分级的技术:DP 复制一切不切;ZeRO/FSDP 竖切训练状态(优化器 → 梯度 → 权重逐级切);TP 把层横切成片;PP 把层分段接龙。切得对,一百张卡像一张大卡一样干活。先看全景:
图:并行训练全景——ZeRO 竖切训练状态、TP 横切层内、PP 层间接龙;通信代价决定部署位置(TP 机内、PP 跨机)
渐进拆解:从复制到切分
三种切法落到显卡上各是什么形状、通信发生在哪,先看一张结构图:
图:三根切分轴各切什么、通信发生在哪——DP 整份复制只同步梯度,TP 切层内须放机内,PP 按层切段可跨机
DP:最朴素的摊法,复制一切
数据并行是起点(PyTorch 里的实现叫 DDP,下文两个名字混用):每张卡放一份完整模型,各吃各的数据批次,每步结束互相同步一次梯度(求平均)。它简单、通信规整,但显存毫无节省——每卡都是全量三样大件,装不下的模型它也无能为力。DP 的价值在于给出通信的基准线:之后所有花招都拿来跟它比。从零预训练篇讲的「放大到集群的三件工程」,第一件就是它——本篇是那条放大路径的完整展开。
ZeRO 与 FSDP:三样大件逐级切
ZeRO(DeepSpeed 提出)的观察是:三样大件不必都放全量——优化器状态最臃肿(占 12 字节/参数)却最「机械」(只是统计量),先切它;梯度其次;权重最后。三级切法:
- ZeRO-1 切优化器状态:每卡只留自己负责那份参数的优化器状态。
- ZeRO-2 加切梯度:每卡只保留自己那份参数对应的梯度。
- ZeRO-3 加切权重:前向要用某层时临时从别卡借齐,用完即还。
妙处在通信账:普通 DP 同步梯度用的 all-reduce(全员归约平均),内部本就等价于「各卡归约出自己那片 + 再全员同步」两步;ZeRO-1/2 恰好只要其中一半产物——每卡只留自己分片的份,总通信量与 DP 完全相同,显存等于白省;ZeRO-3 因为要多跑「借权重」的临时同步,通信约加 50%。拿 7B 模型实算(8 卡、混合精度):
| 级别 | 切什么 | 通信代价 | 每卡显存 |
|---|---|---|---|
| DP(基线) | 不切 | 基准 | 106 GiB |
| ZeRO-1 | 优化器状态 | 与 DP 相同 | 36 GiB |
| ZeRO-2 | 加切梯度 | 与 DP 相同 | 25 GiB |
| ZeRO-3 | 加切权重 | 约加 50% | 13 GiB |
ZeRO-3 把「装不下」直接变成「装得下还有富余」。
FSDP:ZeRO-3 的工程化落地。 FSDP(全分片数据并行)是 PyTorch 原生的 ZeRO-3 实现:把权重、梯度、优化器状态全部分片,前向/反向进行到某层时临时 all-gather(全员汇聚)出该层完整权重,用完立刻丢弃只留自己的分片。对使用者它是个开关(包一层 API 即得),因此成为学术界与开源训练的默认起点;代价与 ZeRO-3 一致——那 50% 的额外通信,以及「借还」带来的调度复杂度。
TP:把一层切成片,通信最密集
先补一个名词:激活值指前向过程留下的中间结果(反向算梯度要用),它随 batch 与序列长线性涨,长上下文下能压过参数本身——本篇的 16 字节口诀不含它。
ZeRO 系省的是「训练状态」,可单层如果还是太大(注意力与 FFN 的大矩阵乘),就得动模型本身:张量并行(TP)把每层的大矩阵按行列切成 N 片,N 张卡各算一片,每层算完互相汇总一次。切法有讲究:权重矩阵按列切、各卡独立算完再拼接结果,可以少一次同步——Megatron-LM 的经典设计就是把注意力的投影与 FFN 的两段矩阵交替按列/行切,让一整层只在头尾各同步一次。
收益是每卡的权重与激活都变成 1/N;代价是每一层的前向与反向都要全组通信(经典实现每层前向两次、反向两次 all-reduce)——通信次数与层数成正比,且必须等最慢的卡。所以 TP 的铁律是放在机内(NVLink 是服务器机内显卡间的高速互联,带宽远高于跨机网络),跨机跑 TP 会被网络拖垮。
激活太占时的标准解法是激活重计算:前向不留中间结果、反向时重算,用约三成的额外计算换显存——它与并行正交:并行切开「三样大件」,重计算管「临时开销」,两者叠加使用。
PP:把层分段接龙,通信最稀疏
流水线并行(PP)换了个切法:按层分组,前 8 层给 1 号卡、接着 8 层给 2 号卡……数据像流水线一样流过。通信只在段与段的交界处发生(传一次激活),量最小、也扛得住慢网络——适合跨机。
代价是流水线空泡:流水线刚启动时下游没事干、收尾时上游没事干,这些空转就是气泡。气泡率 = (段数−1) ÷ (micro-batch 数 + 段数−1),把全局批次拆成越多份 micro-batch(填流水线的小份数),气泡越薄——8 段流水线下的三档实算:
- micro-batch 8:气泡率 46.7%
- micro-batch 32:气泡率 17.9%
- micro-batch 64:气泡率 9.9%
但 micro-batch 变小会让矩阵乘变矮、单步计算效率下降,与气泡率存在权衡;主流的 1F1B 调度(前向反向交错排布)压的是在飞激活的显存占用,气泡率与上式相同。
大白话:DP 是「每个司机开一辆整车」;ZeRO 是「停车紧张,把备胎、工具箱、油桶分开放各家车库」;TP 是「一辆车的引擎太大,四个人合力装」;PP 是「一条装配线,每人负责几道工序」。
选型决策树:给定模型与集群,三问定方案
实战里的决策路径是固定的,画成树:
图:并行选型决策树——先问训练状态装不装得下(DDP/ZeRO 阶梯),再问单层装不装得下(机内 TP),最后按拓扑定跨机(PP);实战常是三维组合拳
技术定义:DP 每卡持完整训练状态、按步同步梯度;ZeRO-1/2/3 依次分片优化器状态、梯度、权重,前两级通信量与 DP 持平、第三级约增 50%;FSDP 为 ZeRO-3 的 PyTorch 原生实现;TP 按矩阵行列切分层内计算,每层前向与反向需全组通信;PP 按层分段,仅段边界传输激活。大规模训练常以「机内 TP + 跨机 PP + 全局 ZeRO」三维组合部署。
动手:算分片账、气泡账与通信账
三笔账支撑本篇全部决策,都可实算验证:
P = 7.1e9 # 7B 参数
N = 8 # 8 卡
# 混合精度显存口诀:权重 2 + 梯度 2 + 优化器 12 = 16 字节/参数
ddp = 16 * P / 2**30
z1 = (2 + 2 + 12/N) * P / 2**30 # ZeRO-1:切优化器
z2 = (2 + 2/N + 12/N) * P / 2**30 # ZeRO-2:加切梯度
z3 = (2/N + 2/N + 12/N) * P / 2**30 # ZeRO-3:加切权重
print(f"DDP {ddp:.0f} GiB → Z1 {z1:.0f} → Z2 {z2:.0f} → Z3 {z3:.0f}")
# 实算输出:DDP 106 GiB → Z1 36 → Z2 25 → Z3 13
p_stages, m_micro = 8, 32
bubble = (p_stages - 1) / (m_micro + p_stages - 1)
print(f"PP 气泡率: {bubble:.1%}") # 实算输出:17.9%
# 第三笔:TP 每层的通信对象 = batch × 序列长 × 隐藏维 × 精度字节
act = 4 * 4096 * 3584 * 2 / 2**20
print(f"TP 每层通信对象 ≈ {act:.0f} MiB") # 实算输出:112 MiB
账本读法:
- 第一笔账回答「切到哪一级够用」——80 GB 卡装 7B 全量训练装不下(106 GiB),ZeRO-1 就够了(36 GiB);70B 模型 8 卡即使 ZeRO-3 训练状态也要约 130 GiB/卡,还需加卡或叠加手段。
- 第二笔账回答「PP 的空转有多疼」——micro-batch 数是免费的气泡阀,拆批前先看这行公式。
- 第三笔是通信量的估算口径:TP 每层的通信对象是激活张量(batch × 序列长 × 隐藏维 × 精度字节),层数越多通信越频繁;PP 只传段边界的同尺寸张量——这就是「TP 扛不住慢网络、PP 扛得住」的量化根源,也是自测第一题的答案骨架。
边界与取舍
什么时候 TP 不如 PP? 判据是「通信发生在哪、网络扛不扛得住」。TP 的通信在每层的前向与反向都要发生(经典实现各两次),次数与层数成正比,对带宽和延迟都敏感——跨机(以太网/InfiniBand 跨节点)跑 TP,通信等待会吞掉并行收益;PP 的通信只在段边界一次一段,量小且可流水掩盖,慢网络只影响交界瞬间。
所以:单机 8 卡能装下 → TP 优先(机内带宽富余);必须跨机 → PP 承担跨机维度,TP 退回机内。通信量的估算口径见动手一节的第三笔账——先算 TP 的每层激活张量与层数的乘积,再对照机内/跨机带宽,答案自然出来。
什么时候不用并行? 单卡或单机能装下(LoRA 微调、7B 以下全参)——并行只添乱;推理场景——本篇是训练侧的切分,推理侧的省法(KV Cache、分页)在推理优化篇。另外并行不改变「训练什么」:数据配比、损失设计这些流程篇的事,并行一概不碰——它只回答「怎么在有限的卡上把它训起来」。
坏味道预警:把并行度当性能旋钮猛拧。 卡越多不等于越快——TP 超过机内卡数、PP 段数超过 micro-batch 数、ZeRO-3 用在小模型上,都是「通信与空转吃掉收益」的典型。每次加并行度前,先用动手段的两笔账算一遍:显存是否真不够、气泡率是否可控。
自测
合上文章先自己答,再展开对照:
什么时候 TP 不如 PP?通信量怎么估?
判据是通信模式对网络的敏感度。TP 的通信发生在每一层的前向与反向(每层全组汇总),次数与层数成正比,对带宽与延迟双重敏感——跨机跑 TP 时慢网络会吞掉并行收益,所以跨机场景 TP 不如 PP:PP 只在段边界传一次激活,量小且可被流水掩盖,天然适合跨机。通信量估算口径:TP 每层的通信对象是激活张量 = batch × 序列长 × 隐藏维 × 精度字节(如 4×4096×3584 bf16 约 112 MiB),总通信 ≈ 每层激活 × 层数 × 前向与反向的通信次数;PP 只算各段边界的一次传递。决策顺序:先看模型单层/整层能否装进机内——能装下优先机内 TP;跨机需求用 PP 承担,TP 退守 NVLink 域内。
ZeRO 三级各切什么?为什么说前两级「通信免费」?
ZeRO-1 切优化器状态(12 字节/参数的大头)、ZeRO-2 加切梯度、ZeRO-3 加切权重——逐级把三样大件分片到各卡。前两级「通信免费」的原因:普通 DP 同步梯度用的 all-reduce 原语,内部本来就等价于「reduce-scatter(各卡归约出自己那片)+ all-gather(再全员同步)」两步——ZeRO-1/2 恰好只需要其中一半的产物(每卡只留自己分片的梯度/优化器状态),总通信量与 DP 完全持平,显存省了通信没多付。ZeRO-3 则要额外跑「前向/反向临时借齐权重」的 all-gather,通信约加 50%——免费午餐到这一级为止(7B 模型 8 卡实算:DP 106 GiB → ZeRO-1/2/3 每卡 36/25/13 GiB)。
PP 的流水线气泡怎么算、怎么压?
气泡来自流水线的启动与收尾:第一批数据还没流到最后一段、最后一批已经离开前几段,中间的空转就是气泡。公式:气泡率 = (段数−1) ÷ (micro-batch 数 + 段数−1)。压法是把全局批次拆成更多 micro-batch 来填流水线——8 段流水线下,micro-batch 从 8 提到 32、64,气泡率从 46.7% 降到 17.9%、9.9%(实算);但 micro-batch 变小会降低每步的计算效率(矩阵乘变矮),与气泡率存在权衡,工程上取两者平衡点。主流的 1F1B 调度(前向反向交错)还能进一步压在飞激活的显存占用(气泡率不变),思路同源:让每张卡手里始终有活。
参考与延伸
- Rajbhandari 等《ZeRO: Memory Optimizations Toward Training Trillion Parameter Models》(2020):三级分片与通信量分析的原论文 — arxiv.org/abs/1910.02054
- PyTorch 官方教程《Getting Started with FSDP》:FSDP 与 ZeRO-3 的对应关系及使用 — pytorch.org/tutorials/intermediate/FSDP_tutorial.html
- Shoeybi 等《Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism》(2019):TP 的工业标准实现 — arxiv.org/abs/1909.08053
- Huang 等《GPipe: Efficient Training of Giant Neural Networks using Pipeline Parallelism》(2019):流水线并行与 micro-batch 填充的奠基论文 — arxiv.org/abs/1811.06965
- DeepSpeed 官方文档:ZeRO 配置与三级开关 — www.deepspeed.ai
下一站:GPU Kernel 入门:Triton / FlashAttention——并行训练把活分给一群卡,每张卡上的活怎么跑得快,轮到 GPU 内核出场:FlashAttention 省的不是计算而是搬运。