第 24 天 · 把模型切段排成流水线,再把批次切碎
一句话
GPipe 把网络按层切成 K 段放到 K 个加速器上,再把小批次切成 M 个微批次依次流过各段,并用重计算节省显存。它训练出 5.57 亿参数的图像模型和 60 亿参数、128 层的多语言翻译模型。
论文讲了什么
结论先行:当模型大到一块加速器装不下时,GPipe 给出一个简单、通用的方案:按层切分模型,把批次切碎后流水线式地送进去。它保持与单卡训练完全相同的数学结果,同时让多块设备基本保持忙碌。
问题。朴素的模型并行把第 1–10 层放在设备 1,第 11–20 层放在设备 2,依此类推。但前向传播必须先算完设备 1 才能算设备 2。任意时刻只有一块设备在工作,其他设备都在等待。K 块设备的利用率只有约 1/K。
方法:3 个组件。
- 按层切分:把 L 层网络切成 K 段,每段放在一个加速器上。切分时尽量让每段的计算量接近,否则最慢的一段会拖住整条流水线。
- 微批次流水线:把大小为 N 的小批次切成 M 个微批次。设备 1 算完第 1 个微批次就交给设备 2,自己立刻开始第 2 个微批次。反向传播同样流水线化。M 个微批次的梯度累加后,在小批次结束时统一更新一次参数。
- 重计算(re-materialization):前向时每段只保存段边界的输入激活值,不保存段内各层的激活。反向时重新计算段内激活。峰值激活显存从
O(N × L)降到O(N + (L/K) × (N/M)),代价是多算约一次前向。
气泡开销。流水线刚开始和快结束时,总有设备在等待。这段空闲叫气泡(bubble),占比约为 (K − 1) / (M + K − 1)。例如 K = 4、M = 16 时,气泡约占 16%。论文发现 M ≥ 4K 时气泡开销可以忽略。
同步更新。梯度更新是同步的。无论切成几段、几个微批次,训练结果都与单卡跑整个小批次相同。这让研究者可以先在小规模上调参,再直接放大。
关键结果。
- 图像:训练了 5.57 亿参数的 AmoebaNet,ImageNet top-1 准确率达到 84.4%。迁移到 CIFAR-10 和 CIFAR-100,分别达到 99.0% 和 91.3%。
- 翻译:训练了 60 亿参数、128 层的 Transformer,用一个模型翻译 100 多种语言。它在多数语言对上超过分别训练的双语模型。
- 扩展性:设备之间只在段边界传递激活值,通信量小。没有高速互连的硬件也能获得接近线性的加速。
局限。网络必须能表示成层的顺序序列。批归一化在训练时只能用微批次的统计量。各段负载不均衡时,效率会明显下降。
关键概念
- 流水线并行(pipeline parallelism)
- 把模型按层切成多段,放在不同设备上,让不同的数据块同时处于不同段中计算。它像工厂流水线,各工位同时处理不同工件。
- 微批次(micro-batch)
- 把一个小批次再切成的更小数据块。微批次越多,流水线越满,气泡越小;但单个微批次太小会降低每块设备的计算效率。
- 流水线气泡(pipeline bubble)
- 流水线启动和排空阶段设备空等的时间,占比约 (K−1)/(M+K−1)。增加微批次数 M 可以降低这个比例。
- 重计算(re-materialization)
- 也叫激活检查点。前向时只保存少量激活值,反向时重新计算其余部分,用约 1 次额外前向的计算量换取大幅显存节省。
- 同步梯度更新(synchronous gradient update)
- 累加所有微批次的梯度后再统一更新参数。结果与单卡训练整个小批次一致,不会出现异步方案的梯度过时问题。
- 模型并行(model parallelism)
- 把一个模型的参数分到多台设备上存放和计算,用于模型大到单卡装不下的情况。与之相对的数据并行是每台设备存一份完整模型。
历史位置:为什么值得读
GPipe 出现时,"模型太大装不下"刚刚成为现实问题。此前的主流是数据并行:每块设备一份完整模型,各算一部分数据,再用 all-reduce 同步梯度。数据并行解决不了单卡显存上限。2018 年同期还有两条路线:Mesh-TensorFlow 把单个矩阵运算切到多台设备上;微软的 PipeDream 用异步流水线,需要存多个版本的权重。GPipe 选择了同步方案,实现简单,结果可复现。
它的影响直接体现在大语言模型的训练基础设施上:
- 2019 年的 Megatron-LM 提出张量并行,2019 年的 ZeRO 提出优化器状态切分。
- 训练 GPT-3 这一代模型时,业界把数据并行、张量并行、流水线并行组合成"3D 并行"。流水线这一维正是 GPipe 开创的。
- 重计算成为训练大模型的默认选项。
它和清单里其他论文的关系:第 22 天 Deep Speech 2 展示了系统工程对规模的意义。第 25 天的缩放定律说明模型越大越好。GPipe 回答的是中间那一步:怎样让更大的模型真正训得起来。第 14 天的 Transformer 由同构的层堆叠而成,特别适合按层切分。
学前准备
- 理解反向传播需要保存前向的激活值
- 知道数据并行和梯度累加是什么
- 知道 ResNet 和 Transformer 由重复层堆叠(先看第 9、14 天)
- 会用 PyTorch 统计张量的显存占用
在原仓库怎么学
- 运行 setup.py:它用单元测试验证 GPipe 的输出和梯度与普通顺序执行在数学上一致。
- 阅读 data/README.md:了解实验使用的数据。
- 阅读 implementation.py:找出模型切分、微批次调度、梯度累加和重计算 4 部分。
- 按顺序做 exercises/ 里的 5 个练习:
exercise_01_microbatch.py切分微批次,exercise_02_pipeline_forward.py实现流水线前向,exercise_03_gradients.py处理梯度累加,exercise_04_checkpoint.py实现重计算,exercise_05_full_gpipe.py组装完整 GPipe。 - 对照 exercises/solutions/ 检查实现。
- 运行 train_minimal.py:用
--partitions、--micro-batches、--layers改变配置,比较不同设置下的显存和速度。 - 运行 visualization.py:生成流水线调度甘特图和显存随微批次变化的曲线,可与目录中已有的 pipeline_schedule.png 和 memory_scaling.png 对照。
- 最后用 notebook.ipynb 复习全流程。
今天再看
流水线并行仍是训练大模型的标准维度之一,但 GPipe 的调度方式已被改进。2026 年训练前沿大语言模型,通常同时使用数据并行、张量并行、流水线并行、专家并行和序列并行。
GPipe 的"先全部前向、再全部反向"调度需要同时保存 M 个微批次的激活。后续改进包括:
- 1F1B 调度:每做一次前向就做一次反向,降低峰值显存。
- 交错式 1F1B:每块设备负责多个不连续的段,进一步缩小气泡。
- Zero Bubble(2024)和 DeepSeek-V3 的 DualPipe(2024):把反向拆细并与通信重叠,把气泡压到接近 0。
两个思想完全保留下来:同步更新保证可复现,重计算用算力换显存。理解 GPipe 是读懂这些新调度的起点。
容易卡住的地方
- 气泡公式记不住:画一张 K 行、M+K−1 列的格子图,每行是一块设备,每列是一个时间步。数一数空格,公式自然出来。
- 梯度累加后结果和单卡不一致:损失要按微批次数 M 取平均,或者在累加时除以 M。否则梯度会放大 M 倍。
- 在单机 CPU 上跑不出加速:仓库在一台机器上模拟流水线,重点是验证调度逻辑和显存变化。真正的并行加速需要多块设备。
- 批归一化模型结果变差:训练时批归一化只看到一个微批次。微批次太小时统计量噪声大,可以换成层归一化,或增大微批次。
延伸阅读
- 原论文:GPipe: Efficient Training of Giant Neural Networks using Pipeline Parallelism
- 原仓库第 24 天目录:24_gpipe/ —— 代码、笔记本、练习与答案(英文)
- PipeDream: Fast and Efficient Pipeline Parallel DNN Training —— 同期的异步流水线方案
- Training Deep Nets with Sublinear Memory Cost —— 重计算(梯度检查点)的经典论文
- Megatron-LM —— 张量并行,与流水线并行互补
- Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM —— 3D 并行与交错式 1F1B 调度