流水线并行¶
流水线并行(PP)将模型的Transformer隐藏层划分为连续的流水线阶段。每个阶段由一个张量并行(TP)组执行,当TP大小为1时由一个工作进程执行,并将中间激活发送到下一阶段。例如,--pipeline-parallel-size 2将隐藏层划分到两个流水线阶段之间。
输入tokens → PP阶段0(较早的隐藏层)→ 中间激活 → PP阶段1(较晚的隐藏层、最终norm、LM head和采样)→ 输出tokens。
本指南使用以下术语:
| 术语 | 含义 |
|---|---|
| PP阶段 | 包含连续范围模型层的逻辑分区。 |
| PP rank | 工作进程在其PP通信组内的阶段索引。具有相同阶段索引和不同TP rank的工作进程共同执行一个阶段。 |
| TP组 | 在一个PP阶段内共同应用TP的工作进程。 |
| 节点 | 物理服务器。一个节点可以包含多个PP阶段或TP组。 |
Note
并非所有模型实现都支持PP。部署前,请查看支持模型中的流水线并行列。
首次部署时,请从快速开始入手。生产环境部署前,请审阅配置层分区和兼容性限制。当部署需要额外功能或调优时,可使用高级场景和性能分析。
快速开始¶
以下示例展示了启动基本PP部署所需的最少选项。在生产环境使用该配置前,请审阅拓扑、兼容性和性能相关章节。
开始之前¶
启动服务前,请确认以下事项:
- 可见的NPU数量满足所选的TP/PP/DP拓扑要求。
- 所有节点使用相同的vLLM、vLLM Ascend、模型权重和Python环境。
- 所有节点可以访问相同的模型路径或等效的本地副本。
- 对于MP部署,每个节点都可以访问头节点的master地址和端口。
- HCCL正常;对于Ray部署,Ray资源视图也正常。
单节点部署¶
以下示例演示了在两张NPU上的最小PP语法。仅在需要层分区时使用此拓扑:
export ASCEND_RT_VISIBLE_DEVICES=0,1
vllm serve /path/to/model \
--tensor-parallel-size 1 \
--pipeline-parallel-size 2 \
--trust-remote-code
当每个阶段需要使用一个TP组时,增大--tensor-parallel-size。例如,TP4 PP2需要八张可见的NPU。
使用多进程的双节点部署¶
多进程(MP)后端可以在不依赖Ray集群的情况下跨两个节点启动PP部署。以下示例使用两个8-NPU节点,将TP保持在每个节点内部,并在每个节点上放置一个PP阶段。将<HEAD_NODE_IP>替换为工作节点可以访问的地址,将<MASTER_PORT>替换为未使用的TCP端口。两个节点上使用相同的值。
在头节点上,使用节点rank 0:
vllm serve /path/to/model \
--distributed-executor-backend mp \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2 \
--nnodes 2 \
--node-rank 0 \
--master-addr <HEAD_NODE_IP> \
--master-port <MASTER_PORT> \
--trust-remote-code
在工作节点上,使用节点rank 1并添加--headless:
vllm serve /path/to/model \
--distributed-executor-backend mp \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2 \
--nnodes 2 \
--node-rank 1 \
--master-addr <HEAD_NODE_IP> \
--master-port <MASTER_PORT> \
--headless \
--trust-remote-code
只有头节点启动API服务器。两个节点必须使用相同的模型、TP、PP、--nnodes、--master-addr和--master-port值。为每个节点分配从0到--nnodes - 1的唯一--node-rank,并在运行任一命令之前设置所需的HCCL和通信环境变量。
使用Ray的多节点部署¶
启动Ray集群后,在头节点上运行vllm serve。对于两个8-NPU节点,将TP保持在每个节点内部,并在节点之间使用PP:
vllm serve /path/to/model \
--distributed-executor-backend ray \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2 \
--trust-remote-code
仅在每个节点上设置好所需的通信环境变量之后再启动Ray。完整的集群配置文档见Ray分布式。
何时使用PP¶
PP在以下场景中很有用:
- 模型无法容纳在一个TP组中,必须按层进一步划分。
- 多节点部署应将高频TP集合通信保持在每个节点内部,同时通过PP在节点之间发送激活。
- 在P/D分离部署中,Prefill节点需要更多设备来满足模型容量或长上下文prefill的需求。
PP还会在阶段之间引入激活传输和流水线气泡。当模型适合单节点部署时,以仅使用TP的部署作为基准,然后在模型容量或网络拓扑需要时再添加PP。
| 部署目标 | 建议的起点 |
|---|---|
| 模型适合单节点 | 先仅使用TP并进行基准测试,然后再添加PP。 |
| 模型跨多个节点 | 在节点内使用TP,在节点之间使用PP。 |
| 需要多个服务副本 | 先构建一个TP/PP副本,然后仅在支持的模型、算子和网络拓扑上添加DP。 |
| 长上下文Prefill需要PP调优 | 先从PP开始,然后评估动态分块流水线并行。 |
配置层分区¶
层分区决定每个PP阶段执行目标模型隐藏层的哪个范围。如果目标模型有N个隐藏层,PP大小为P,则由PP rank i选择的阶段使用一个半开区间:
只有目标模型的Transformer隐藏层参与此分区。
自动分区¶
默认情况下,vLLM 会尽可能均匀地分布隐藏层。当层数不能被 PP 大小整除时,vLLM 会从倒数第二个流水线阶段开始,将剩余层分配给 PP 排名更低的阶段。这样可以避免给最后一个阶段增加更多隐藏层,因为最后一个阶段通常还负责执行最终归一化、LM 头、logits 和采样。当阶段数超过两个时,少量余数层会放在中间阶段,以减轻输入和输出阶段的压力。
对于具有 61 个隐藏层的目标模型:
PP2: [31, 30]
PP rank 0: [0, 31)
PP rank 1: [31, 61)
PP4: [15, 15, 16, 15]
PP rank 0: [0, 15)
PP rank 1: [15, 30)
PP rank 2: [30, 46)
PP rank 3: [46, 61)
请先使用自动分区。只有当测量结果显示某个阶段的显存或延迟存在不平衡时,才进行自定义分区。
自定义分区¶
将 VLLM_PP_LAYER_PARTITION 设置为每个 PP 阶段执行的目标隐藏层数,按 PP 排名顺序排列:
export VLLM_PP_LAYER_PARTITION="32,29"
vllm serve /path/to/61-layer-model \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2 \
--trust-remote-code
在此示例中:
该分区必须满足以下所有规则:
- 每个 PP 排名使用一个正整数,以逗号分隔。
- 条目数量必须等于
--pipeline-parallel-size。 - 总和必须等于目标模型的隐藏层数。
- 不要包含嵌入、最终归一化、LM 头或草稿模型层。
- 在同一服务实例中,所有 worker 必须使用相同的值。
- 在 Ray 集群上,请在启动 Ray 之前在每个节点上设置该值。
- 更改该值后,请重启服务。
无效的条目数量或层总和将导致启动失败。
调优阶段平衡¶
阶段平衡取决于工作负载。最后一个阶段通常需要额外的显存和计算资源来处理最终归一化、LM 头、logits、采样,以及可能的本地推测解码草稿模型。
使用以下调优循环:
- 从自动分区开始。
- 在具有代表性的工作负载下,记录每个 PP 阶段中 worker 的峰值显存和单步延迟。
- 如果最后一个阶段是瓶颈,则每次将目标隐藏层从最后一个阶段移动一个到 PP 排名更低的先前阶段,例如从
[31,30]改为[32,29]。 - 每次更改后重复进行准确性和性能测试。
移动过多层可能只会将瓶颈转移到另一个阶段,因此不要仅根据显存容量来选择分区。
高级场景¶
PP 与推测解码¶
VLLM_PP_LAYER_PARTITION 仅对目标模型进行分区。草稿模型的层不包含在其层总和中,其权重命名和层布局取决于具体的推测解码实现。
在当前 Model Runner V1 的本地 MTP 和 EAGLE proposer 路径中,草稿模型加载在最后一个 PP 阶段上,而不是跨 PP 阶段进行分区。因此,最后一个阶段可以包含:
- 其目标模型隐藏层。
- 目标模型的输出侧模块。
- 本地草稿模型及其支持模块。
如果最后一个 rank 受到显存或延迟的限制,可以通过自定义分区减少其目标隐藏层。draft_tensor_parallel_size 仅控制草稿模型的 TP 大小;它不定义草稿模型的 PP 分区。
推测解码的支持因模型、方法和 Model Runner 而异。在启用 PP 之前,请参阅推测解码和相关模型教程。
P/D 分离部署中的 PP¶
PP 通常在 Prefill 节点上启用,而 Decode 节点保持 PP1。使用 MooncakeConnectorV1 时,Prefill 和 Decode 配置都必须描述实际的 Prefill 拓扑。
| 设置 | Prefill 节点 | Decode 节点 |
|---|---|---|
--pipeline-parallel-size |
实际的 Prefill PP 大小,例如 2。 |
目前为 1。 |
prefill.pp_size |
实际的 Prefill PP 大小。 | 与 Prefill PP 大小相同。 |
prefill.pp_layer_partition |
自定义 Prefill 分区(如果使用)。 | 相同的自定义 Prefill 分区。 |
decode.pp_size |
1 |
1 |
VLLM_PP_LAYER_PARTITION |
当 Prefill 节点使用自定义分区时设置。 | 不要将 Prefill 值复制到 PP1 Decode 进程中。 |
对于使用 TP8 PP2 和自定义分区 [32,29] 的 61 层 Prefill 模型,请在两侧的 kv_connector_extra_config 中包含以下拓扑:
{
"prefill": {
"dp_size": 1,
"tp_size": 8,
"pp_size": 2,
"pp_layer_partition": "32,29"
},
"decode": {
"dp_size": 1,
"tp_size": 1,
"pp_size": 1
}
}
Prefill 进程还必须导出:
如果使用自动分区,请省略两侧的 pp_layer_partition。当前的 Mooncake connector 要求 Prefill TP 大小大于或等于 Decode TP 大小,并且是后者的整数倍。
有关完整的 P/D 启动命令,请参阅使用 Mooncake 进行 PD 分离。有关长上下文 Prefill 优化,请参阅动态分块流水线并行。
性能特征:PP 与 TP 对比¶
PP 和 TP 以不同的方式分布模型执行,因此两种策略都不是普遍更快的。TP 对 Transformer 层内的受支持操作进行分区。TP worker 参与每一层,并使用集合通信来合并部分结果,而未分区的组件可以保持复制。PP 将连续的层分配给不同的阶段,并在相邻阶段之间传输中间张量。在混合拓扑中,TP 通信保持在每个 PP 阶段内部,而 PP 通信连接各个阶段。
与大型跨节点 TP 组相比,PP 的主要性能优势在于通信局部性,而不是单个层内更快的计算。
| 方面 | 张量并行 | 流水线并行 | 性能影响 |
|---|---|---|---|
| 模型划分 | 每个 TP rank 都参与每一层的计算,并持有每个组件的分片或副本。 | 每个 PP 阶段只执行分配给它的层;TP 还可以额外对这些层进行分片。 | PP 可以在不创建非常大 TP 组的情况下扩展模型容量。 |
| 通信 | 集合通信操作可能出现在许多 Transformer 层内部。 | 中间张量在相邻 PP 阶段之间传输。 | 将 TP 保持在每个节点内部通常可以降低跨节点通信的频率。 |
| 单请求延迟 | 所有 TP worker 并发参与同一层的计算。 | 一个请求按顺序遍历各 PP 阶段。 | 当 TP 互连速度较快时,TP 通常更适合对延迟敏感、低并发的负载。 |
| 稳态吞吐量 | 较大的 TP 组可能因集合通信延迟和更小的每 rank 矩阵运算而损失效率。 | 由独立请求或 Prefill 块组成的并发调度器批次可以让不同阶段保持繁忙。 | 当流水线有足够的工作且各阶段平衡时,PP 可以提高吞吐量。 |
| 内存 | 权重在每一层内分片;某些张量可以保持复制。 | 权重和 KV 缓存按层划分,而边缘阶段还持有输入侧或输出侧的模块。 | 两者都能减少每个 rank 的内存占用,但相同的并行大小并不能保证相同的峰值内存。 |
| 扩展限制 | 可用的 TP 大小可能受到注意力头、KV 头、隐藏维度、专家路由或受支持内核的限制。 | 模型必须支持 PP,并且具有可划分的层。 | 当增大 TP 无效或不再高效时,PP 很有用。 |
| 主要瓶颈 | 一次慢速集合通信会延迟 TP 组中的每个 rank。 | 最慢的阶段及其边界传输会限制流水线。 | TP 依赖集合通信效率;PP 依赖阶段平衡和激活传输效率。 |
流水线气泡与工作负载影响¶
PP 会在工作进入和离开流水线时引入空闲时间,并且只要某个阶段比其他阶段耗时更长,也会产生空闲时间。这种空闲时间通常称为流水线气泡。相等的层数并不能保证相同的阶段延迟:第一个和最后一个阶段还可能执行嵌入、最终归一化、LM head、logits 处理、采样或投机解码 drafter。
| 工作负载特征 | 预期行为 |
|---|---|
| 单个请求或低并发 Decode | 几乎没有独立工作可以让多个阶段保持占用。与高效的节点内 TP 基线相比,阶段遍历和通信通常会增加延迟。如果对比的是跨节点 TP 组,应同时测量两种配置,因为跨节点集合通信延迟可能逆转结果。 |
| 高并发与连续批处理 | 并发调度器批次可以占用不同阶段,从而减少相对流水线气泡并提高吞吐量。 |
| 长上下文 Prefill | 每个块更多的计算可以分摊 PP 通信开销,并且 PP 可以提供长上下文所需的内存容量。 |
| 可变的 prompt 长度 | 批次和块的持续时间各不相同,因此固定长度的基准测试可能会掩盖阶段不平衡。 |
| 不平衡的层划分 | 最慢的阶段会让其他阶段等待,并限制稳态吞吐量。 |
因此,当 TP 可以保持在每个节点内部、各阶段可以通过实测延迟和内存进行平衡,并且工作负载提供足够的并发请求或 Prefill 块来让流水线保持占用时,PP 更有可能优于跨节点 TP。当模型可以放入单个节点、低并发延迟是首要目标,或者各阶段无法平衡时,TP 仍然是首选的基线。
对于长上下文 Prefill 工作负载,请考虑使用动态分块流水线并行,它会根据实测执行时间调整块大小,以减少阶段空闲时间。
兼容性与限制¶
- PP 在当前版本中无法与 Prefill 上下文并行(PCP)结合使用。参见上下文并行。
- Xlite 图模式与 PP 不兼容。
- 稀疏 KV Cache 卸载不支持 PP。
MooncakeConnectorV1目前要求 Decode 侧 PP 大小为1。- 对于通过 RoCE 进行的跨节点 MoE 部署,目前不能同时启用 PP 和 DP,因为
MoeDistributeDispatch通信路径不支持这种组合拓扑。 - 功能组合仍因模型而异。在生产部署前,请查阅相应的功能指南。
故障排查¶
| 症状 | 检查与操作 |
|---|---|
| 启动时报告资源不足 | 确认可见的 NPU 满足所选 DP/PP/TP 拓扑,并且 Ray 能看到每个预期的 NPU。 |
启动时拒绝 VLLM_PP_LAYER_PARTITION |
检查条目数量是否等于 PP 大小,且总和是否等于目标隐藏层数量。 |
| 某个 PP rank 内存不足 | 检查它是否为最后一个阶段或托管了本地 drafter。测量所有 rank,然后一次移动一个目标层。 |
| 第一个请求挂起 | 使用更小的序列长度和批处理上限重试。使用 --enforce-eager 判断是否涉及图捕获,并验证 rank 间通信。 |
| MP worker 无法加入头节点 | 确认两个节点使用相同的主节点地址、主节点端口、节点数量、模型和并行大小;每个节点 rank 唯一;并且主节点端口可访问。worker 命令必须包含 --headless。 |
| Ray 部署挂起或缺少 rank | 确认每个节点上的环境、模型路径、通信变量和 Ray 资源都一致。 |
| 跨节点 RoCE MoE 部署在启用 PP 和 DP 后失败或挂起 | 将 PP 大小或 DP 大小保持在 1;当前的 MoeDistributeDispatch 路径不支持这种组合拓扑。 |
| P/D 握手超时 | 比较 P/D 连接器拓扑、prefill.pp_size、可选的 prefill.pp_layer_partition 以及可用的 kv_port 范围。 |
相关文档¶
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 vl/vllm-ascend