跳转至

流水线并行

流水线并行(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选择的阶段使用一个半开区间:

PP rank i: [start_layer_i, end_layer_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 rank 0: [0, 32)
PP rank 1: [32, 61)

该分区必须满足以下所有规则:

  • 每个 PP 排名使用一个正整数,以逗号分隔。
  • 条目数量必须等于 --pipeline-parallel-size。
  • 总和必须等于目标模型的隐藏层数。
  • 不要包含嵌入、最终归一化、LM 头或草稿模型层。
  • 在同一服务实例中,所有 worker 必须使用相同的值。
  • 在 Ray 集群上,请在启动 Ray 之前在每个节点上设置该值。
  • 更改该值后,请重启服务。

无效的条目数量或层总和将导致启动失败。

调优阶段平衡

阶段平衡取决于工作负载。最后一个阶段通常需要额外的显存和计算资源来处理最终归一化、LM 头、logits、采样,以及可能的本地推测解码草稿模型。

使用以下调优循环:

  1. 从自动分区开始。
  2. 在具有代表性的工作负载下,记录每个 PP 阶段中 worker 的峰值显存和单步延迟。
  3. 如果最后一个阶段是瓶颈,则每次将目标隐藏层从最后一个阶段移动一个到 PP 排名更低的先前阶段,例如从 [31,30] 改为 [32,29]。
  4. 每次更改后重复进行准确性和性能测试。

移动过多层可能只会将瓶颈转移到另一个阶段,因此不要仅根据显存容量来选择分区。

高级场景

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 进程还必须导出:

export VLLM_PP_LAYER_PARTITION="32,29"

如果使用自动分区,请省略两侧的 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