6.3 流水线并行推理:按层切段、Bubble 与跨节点扩展
PP 的层切分与段间通信、推理场景的 Bubble 与 Micro-batch 组织、PP 与 TP 的组合、vLLM 中 PP 的适用场景(跨节点与不均匀切分)
6.2 结尾留下一个结论:跨节点的事交给 PP。这一节讲清楚 PP 是什么、为什么它适合跨节点、以及它的两个固有代价——Bubble(气泡)和单请求延迟上升。推理场景里 PP 不是主角(TP 才是),但它是”模型大到单节点装不下”时的必经之路,也是理解 vLLM 启动参数 --pipeline-parallel-size 的钥匙。
📑 目录
- 1. 直觉:把模型按深度切成几段
- 2. 前向过程:接力棒式的层间传输
- 3. Bubble:流水线的固有浪费
- 4. 推理场景的 PP:和训练哪里不一样
- 5. 不均匀切分:PP 的隐藏能力
- 6. TP×PP 组合:节点内张量并行、节点间流水线
- 7. vLLM 中的 PP:配置与适用场景
- 📝 总结
- 🎯 自我检验清单
- 📚 参考资料
1. 直觉:把模型按深度切成几段
TP 是”每一层内部切”,PP 是”层与层之间切”——把 N 层 Transformer 按深度分成 P 段,每段放在一张(或一组)GPU 上:
PP=4 的 32 层模型:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ GPU 0 │ │ GPU 1 │ │ GPU 2 │ │ GPU 3 │
│ 层 0-7 │→│ 层 8-15 │→│ 层 16-23 │→│ 层 24-31 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
Embedding LM Head + Softmax
每个 GPU 只存自己那段的权重(约 1/P 的模型参数量),段与段之间传递的是激活(hidden state),不是梯度。前向像接力棒一样从第 0 段传到第 P-1 段。
💡 提示:PP 和 TP 的切分维度完全不同——TP 切”宽度”(矩阵的列/行),PP 切”深度”(层)。直观记忆:TP 是横着切蛋糕,PP 是竖着切蛋糕。两者可以叠加(6.1 的 TP×PP),先横切再竖切。
2. 前向过程:接力棒式的层间传输
单个请求的完整前向:段 0 算完 → 把中间激活发给段 1 → 段 1 算 → …… → 段 P-1 输出 logits。
2.1 通信成本
段间通信发生在每一段边界,每次传的数据量是激活 (和 TP 的 AllReduce 数据量同量级),但频率远低于 TP:
- TP:每层 2 次 AllReduce(80 层模型 = 160 次)
- PP:每段边界 1 次 P2P(PP=4 的 80 层模型 = 3 次)
这解释了 6.1 的结论:PP 的通信稀疏,配得上慢一个数量级的节点间网络。400Gb/s IB 下,单次激活传输 字节(Decode 场景 :32KB)耗时微秒级,几乎可以忽略。
2.2 显存分布
- 权重显存:÷P(每段只存自己的层)
- 激活显存:只存自己段的激活(但注意 PP 的激活是”整段”的,段内层数多时激活不小)
- Embedding 和 LM Head:通常放在第 0 段和第 P-1 段,两段显存会比其他段多一块
📌 关键点:PP 的显存收益是”按段”的——段内的层共享一份激活空间,但权重严格 ÷P。和 TP 一样,权重显存线性降;和 TP 不同的是,PP 不要求节点内高速互联,因为它天然为跨节点设计。
3. Bubble:流水线的固有浪费
3.1 单个请求的悲剧:串行接力
如果一次只有一个请求,PP 的延迟是所有段延迟之和——单请求场景下 PP 比单卡还慢(多了段间通信),完全没有收益。PP 的收益来自多个请求(或 micro-batch)交错填充流水线:
时间 →
段 0: [MB1][MB2][MB3][MB4]░░░░░░░░░░░░░░░░░░░
段 1: ░░░░[MB1][MB2][MB3][MB4]░░░░░░░░░░░░░░░
段 2: ░░░░░░░░[MB1][MB2][MB3][MB4]░░░░░░░░░░░
段 3: ░░░░░░░░░░░░░░[MB1][MB2][MB3][MB4]░░░░░
├─填充期─┤ ├─排空期─┤
- 填充期(Warm-up):前 P-1 个时间片,后面的段在空等(bubble)
- 稳态:所有段都在忙
- 排空期(Drain):最后 P-1 个时间片,前面的段空等
3.2 Bubble 的定量代价
设 micro-batch 数为 ,段数为 ,流水线吞吐效率:
- :效率 (16% 的 bubble)
- :效率
- :效率
💡 提示:结论——Bubble 靠”多请求”来填。训练里靠增大 micro-batch 数,推理里靠 Continuous Batching 的并发请求天然充当 micro-batch。这就是为什么低并发(空闲)场景下 PP 的 bubble 不可忽视,高并发场景下 PP 的效率反而不错。
3.3 单请求延迟:PP 的第二个代价
一个请求从头到尾要走完 P 段:单请求延迟 ≈ P × 单段延迟(填充期 + 自己的计算)。所以:
- 延迟视角:PP 让单请求变慢(×P 量级),与 TP 完全相反
- 吞吐视角:高并发下 PP 的吞吐效率可以接近 100%
📌 关键点:PP 是”用延迟换容量”的策略——它解决的是”装不下”(容量),代价是单请求延迟上升。如果模型单节点能装下,永远优先 TP;PP 只在”单节点装不下”或”无 NVLink 节点”(6.1 的边缘情况)时才出场。
4. 推理场景的 PP:和训练哪里不一样
训练里的 PP 有复杂的调度(1F1B、interleaved 等,模块三讲过),推理场景简单得多,因为:
| 维度 | 训练 PP | 推理 PP |
|---|---|---|
| 反向传播 | 有(需要对称的梯度流水) | 无——只有前向,调度简化一半 |
| Micro-batch 来源 | 显式切分训练 batch | Continuous Batching 的并发请求天然填充 |
| 调度目标 | 吞吐 + 收敛 | 吞吐 + 延迟均衡 |
| 显存 | 要存反向用的激活 | 只需前向激活(可以边算边丢) |
💡 提示:推理 PP 没有反向传播,因此不需要 1F1B 那样的双向流水调度,实现和调优都比训练简单。这也是 vLLM 等推理引擎敢把 PP 做进 v1 引擎的原因之一。
5. 不均匀切分:PP 的隐藏能力
TP 要求权重矩阵能整除切分(hidden size 能被 TP 整除,通常没问题),但总层数不一定能被 GPU 数整除。PP 天然支持不均匀切分——比如 33 层模型放 4 张卡,可以切成 [9, 8, 8, 8] 或 [9, 9, 8, 7]。
vLLM 官方文档明确提到的边缘场景:
如果模型在单节点能放下,但 GPU 数量不能整除模型(或 GPU 间没有 NVLink 互联,如 L40S),可以设置
tensor_parallel_size=1、pipeline_parallel_size=GPU 数,用 PP 替代 TP。
两个典型用例:
- 整除不了:TP 需要矩阵维度整除,PP 只要”层数能分”——几乎所有模型都能分
- 无 NVLink:L40S 这类 PCIe 互联的卡,TP 的每层 AllReduce 太贵,PP 的稀疏段间通信反而更优
📌 关键点:**“没有 NVLink 就用 PP”**是一条很实用的工程经验——它把 TP 的通信税(6.2 第 5 节)换成 PP 的 bubble 税,在低并发/高吞吐场景里往往更划算。判断标准:PCIe 互联(L40S、RTX 系列)→ PP;NVLink(A100/H100/B200 节点)→ TP。
6. TP×PP 组合:节点内张量并行、节点间流水线
超大规模模型的标配组合(6.1 的黄金配置):TP 锁节点内、PP 跨节点。
以 2 节点 × 8 卡跑 700B 模型为例:
节点 A(8 卡,NVLink) 节点 B(8 卡,NVLink)
┌──────────────────────┐ ┌──────────────────────┐
│ TP=8 组:层 0-39 │ ←→ │ TP=8 组:层 40-79 │
│ 每层内部 2 次 AllReduce│ IB │ 每层内部 2 次 AllReduce│
└──────────────────────┘ └──────────────────────┘
PP 段间通信(每段边界 1 次,走 IB)
- 节点内:TP=8 的 AllReduce 走 NVLink(900GB/s 级)
- 节点间:PP 段间激活走 IB(400Gb/s ≈ 50GB/s),但每 token 只有 1 次传输
vLLM 中对应:--tensor-parallel-size 8 --pipeline-parallel-size 2(16 进程,world size = 16)。
💡 提示:组合时的 rank 排列遵循 6.1 的原则——TP 最内层(同节点内连续编号)、PP 外层(跨节点)。vLLM 启动时会按此自动分配进程到节点,用户需要保证
--nnodes与节点数一致。
7. vLLM 中的 PP:配置与适用场景
7.1 配置
# 2 节点 × 8 卡,TP=8 + PP=2
vllm serve <model> \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2 \
--nnodes 2 \
--distributed-executor-backend ray
Python 侧:LLM(model=..., tensor_parallel_size=8, pipeline_parallel_size=2)。
7.2 适用场景清单
| 场景 | PP 是否合适 | 说明 |
|---|---|---|
| 模型单节点装不下 | ✅ 合适 | TP + PP 组合,PP 承载跨节点部分 |
| GPU 数不能整除模型 | ✅ 合适 | TP=1, PP=GPU 数(不均匀切分) |
| 节点无 NVLink | ✅ 合适 | PP 替代 TP,通信税更低 |
| 单节点能装下、追求最低延迟 | ❌ 不合适 | PP 增加单请求延迟,纯 TP 更好 |
| 低并发、延迟敏感 | ❌ 不合适 | bubble 在低并发下占比高 |
7.3 与投机解码的兼容性
第 5.5 节提过:vLLM ≤0.15 不支持 PP + 投机解码组合,新版逐步放开,但PP 下的投机收益需要单独验证——PP 的段间传输给验证前向增加了额外延迟,接受率收益会被摊薄。
📌 关键点:vLLM 中 PP 的定位是”容量方案”而非”性能方案”——用它是因为装不下或互联受限,而不是因为它快。评估 PP 部署时盯两个数:显存是否装下(容量目标) 和 高并发吞吐是否达标(bubble 是否被并发填满)。
📝 总结
- PP 的本质:按层深度切段,段间传激活(P2P),通信稀疏——为跨节点而生
- 两个固有代价:Bubble(吞吐效率随 micro-batch 数提升)和单请求延迟上升(×P)
- 推理 PP 更简单:没有反向传播,Continuous Batching 的并发请求天然填流水线
- 隐藏能力:不均匀切分(层数不整除)、无 NVLink 节点(PP 替代 TP)
- 黄金组合:TP=节点内 GPU 数、PP=节点数,TP 内层 PP 外层
- vLLM:
--pipeline-parallel-size+--nnodes,定位是容量方案
🎯 自我检验清单
- 用”横切/竖切”解释 TP 与 PP 的区别?
- 为什么 PP 的通信适合跨节点而 TP 不适合?频率差多少倍?
- Bubble 是怎么产生的?吞吐效率公式是什么?什么参数能填满它?
- 为什么推理 PP 比训练 PP 简单?micro-batch 从哪来?
- “GPU 数不能整除模型层数”和”无 NVLink”两个场景为什么用 PP?
- TP×PP 组合时 rank 如何排列?为什么 TP 必须在内层?
📚 参考资料
- Narayanan et al., PipeDream: Generalized Pipeline Parallelism for DNN Training(https://arxiv.org/abs/1806.03377)
- Narayanan et al., Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM(https://arxiv.org/abs/2104.04473)
- vLLM 官方文档:Parallelism and Scaling(https://docs.vllm.ai/en/latest/serving/parallelism_scaling/)
- vLLM 源码:vllm/config/parallel.py(https://github.com/vllm-project/vllm/blob/v0.26.0/vllm/config/parallel.py)