Pipeline Parallel:bubble 怎么来、多大?
1F1B、interleaved 解决什么?peak memory 一样吗?
先弄清楚:每个概念是什么
- Pipeline parallel(PP)
- 把 \(L\) 层按顺序切成 \(p\) 段(stage),每张卡一段,相邻 stage 之间 p2p 传 activation(backward 传 gradient)。一个 batch 切成 \(m\) 个 micro-batch 依次送进去。例:L = 32、p = 4 → 每卡 8 层。
- Pipeline bubble
- 开工时后面的 stage 等 activation,收工时前面的 stage 等 gradient,这段空转就是 bubble。为了 optimizer 语义严格同步,每个 batch 末尾都要 flush 一次,所以每个 batch 都有。
- 1F1B
- 预热几个 forward 后,做一个 forward 就做一个 backward,backward 完就释放那份 activation。
看图:GPipe 和 1F1B 的时间格
30 秒回答
Pipeline parallelism splits the layers into p stages on p GPUs and the batch into m micro-batches. At the start later stages wait for activations, and at the end earlier stages wait for gradients; that idle time is the bubble, (p−1)/m of the ideal compute time for both GPipe and 1F1B, so we want m ≫ p. GPipe runs all forwards before any backward and stashes activations for all m micro-batches; 1F1B alternates forward and backward after a warm-up, so at most p are in flight. Interleaving gives each GPU v non-contiguous chunks, cutting the bubble to (p−1)/(vm) at v times the point-to-point communication.
推导 / 关键公式
bubble 多大
开头空等 \(p-1\) 个 forward,结尾空等 \(p-1\) 个 backward:
\[ t_{pb} = (p-1)(t_f+t_b),\qquad t_{id} = m\,(t_f+t_b) \] \[ \text{bubble} = \frac{t_{pb}}{t_{id}} = \frac{p-1}{m} \]interleaved
每张卡拿 \(v\) 段不相邻的层。每段的 forward、backward 时间都变成 \(1/v\),bubble 跟着 \(\div v\),但 stage 之间的 p2p 通信 \(\times v\),还要求 \(m\) 是 \(p\) 的整数倍:
\[ \text{bubble}_{\text{int}} = \frac{1}{v}\cdot\frac{p-1}{m} \]peak activation(第一个 stage 最大)
GPipe 存 \(m\) 个 micro-batch。1F1B 存 \(p\) 个,每个 \(L/p\) 层,合计 \(L\) 层的量,和不切 PP 一样,不随 \(p\) 变小。interleaved 再乘 \(1 + \frac{p-1}{pv}\)。
手算例子
\(p = 4\)、\(m = 6\),F、B 各算 1 格(.. 是 bubble):
1F1B
GPU0 F1 F2 F3 F4 .. .. .. B1 F5 B2 F6 B3 .. B4 .. B5 .. B6
GPU1 .. F1 F2 F3 .. .. B1 F4 B2 F5 B3 F6 B4 .. B5 .. B6 ..
GPU2 .. .. F1 F2 .. B1 F3 B2 F4 B3 F5 B4 F6 B5 .. B6 .. ..
GPU3 .. .. .. F1 B1 F2 B2 F3 B3 F4 B4 F5 B5 F6 B6 .. .. ..
GPipe:GPU0 先做完 F1–F6 再 B1–B6,同样 18 格
18 格里理想只要 12 格,bubble \(= 6/12 = 3/6 = (p-1)/m\)。换成真实配置 \(p = 8\)、\(m = 32\):
| schedule | bubble | GPU0 存几份 micro-batch 的 activation |
|---|---|---|
| GPipe | 7/32 = 21.9% | 32 |
| 1F1B | 21.9% | 8 |
| interleaved v = 4 | 7/128 = 5.5% | 8 × 1.22 = 9.75 |
必答点
- bubble 来自流水线的填充和排空:\((p-1)/m\)(占理想计算时间,占 wall time 是 \((p-1)/(m+p-1)\)),GPipe 和 1F1B 一样
- 所以要 \(m \gg p\)(GPipe 的经验是 \(m \ge 4p\)),但 micro-batch 不能太小,见 parallelism 配置
- 1F1B 不减 bubble,减 memory:in-flight \(\le p\)(GPipe 是 \(m\))
- interleaved:bubble \(\div v\),代价是 p2p 通信 \(\times v\)
- peak memory 不一样:model state 每卡 \(1/p\);activation 第一个 stage 最多(\(L\) 层 × 1 份),最后一个最少
追问
Zero Bubble 怎么做到的?
把 backward 拆成 B(对输入的 gradient,上一个 stage 在等)和 W(对 weight 的 gradient,没人等),W 往后挪去填 bubble。再绕开 optimizer step 的全局同步,在同步训练语义下做到零 bubble。
DualPipe 是什么?
DeepSeek-V3 的 schedule。micro-batch 从流水线两端同时喂,一对 forward、backward chunk 拆成 attention、all-to-all dispatch、MLP、all-to-all combine 交错执行,让 MoE 的 all-to-all 和 PP 通信被计算盖住。代价是每卡存两份参数,activation peak 多约 \(1/p\)。
串行的几张卡负载不均怎么办?
先减 bubble。第一个 stage 有 embedding、最后一个有 LM head 和 loss,给它们少放几层(Megatron:--decoder-first-pipeline-num-layers、--decoder-last-pipeline-num-layers)。
来源Narayanan et al. 2021 §2.2(pp.2–4,bubble、1F1B、interleaved)、§3.4(p.6)· GPipe §2.3(p.4)· PipeDream §3.3(p.7,1F1B)· Korthikanti et al. 2022 §4.2.3(p.8,第一个 stage 存 \(L\) 层、interleaved 系数)· Zero Bubble §2(p.3)、abstract· DeepSeek-V3 §3.2.1、Table 2(pp.12–13)· Megatron-LM arguments.py