Prhub

#38373 [torch.compile]: Disable Sequence Parallelism (SP) for piecewise compilation

原始 PR 作者 SouthWest7 合并时间 2026-04-27 01:44 文件变更 9 提交数 25 评论 21 代码增减 +223 / -80

执行摘要

禁用 piecewise 编译时的 Sequence Parallelism,仅保留 full-graph 支持

关联的 RFC Issue #35771 指出:当使用 piecewise 编译(Dynamo 分区且 splitting_ops 非空)时,RMSNorm 残差张量会在子图间传递,而 SP 会沿 num_tokens 维度分割张量,导致残差大小在不同 TP rank 间不一致。已有的切片处理方式与 prompt_embeds 等多模态输入不兼容,且存在不安全的假设。因此提议仅在全图编译(Inductor 分区或空 splitting_ops)时支持 SP,以简化切片逻辑并提升正确性。

建议所有使用 vLLM 中 torch.compile 与 SP 的开发者和研究员阅读此 PR 的讨论,特别是关于配置降级策略和 pass 断言的设计,了解为何 piecewise 编译下的 SP 不被支持。对于希望开启 SP 的用户,文档应明确告知需要启用 inductor 分区或清空 splitting_ops。

讨论亮点

Review 中 reviewer(wangxingran222 和 ProExpertProg)提出了以下核心意见:

  • 保留 pass 断言:尽管配置层已强制降级,但仍建议在 SequenceParallelismPassAsyncTPPassis_applicable_for_range 中添加显式断言,以确保即使通过非标准路径实例化也能保持一致性。
  • 配置冲突处理位置:wangxingran222 建议将冲突处理直接放在 set_splitting_ops_for_v1 内部,而非通过 snapshot/reconcile,这样更简洁且符合现有模式(如 fuse_attn_quant)。作者采纳并重写了这部分逻辑。
  • 测试覆盖:ProExpertProg 指出需要更新 SP 相关的单元测试,包括 pass 测试和 e2e 测试,并且不能直接传入 MagicMock 参数。最终测试调整为使用默认 VllmConfig 或 object.__new__ 方式构造 pass 实例。
  • CUDAGraphMode 与 torch.compile 正交性:wangxingran222 指出不应在 SP 条件中依赖 CUDAGraphMode,因为 piecewise 编译可以独立于 cudagraph 模式启用。作者修正了该处逻辑。
  • E2E 验证:ProExpertProg 要求提供 lm_eval 结果以确认端到端正确性,作者附上了 Qwen3-14B 在 gsm8k 上的评测结果(准确率约 0.78),表明功能正常。

实现拆解

  1. 配置冲突自动降级:在 vllm/config/compilation.pyset_splitting_ops_for_v1 方法中,当 enable_sp 为 True 且 use_inductor_graph_partition 为 False 且 splitting_ops 非空时,强制将 splitting_ops 清空并降级 cudagraph_modeFULL,同时输出警告。
  2. 主要配置文件调整:在 vllm/config/vllm.py 中,移除原有的 snapshot/reconcile 机制(_snapshot_user_compilation_inputs / _reconcile_sequence_parallelism_for_cudagraph_mode),改为在 set_splitting_ops_for_v1 之后直接调用 _finalize_sequence_parallelism_config,避免二次计算。同时调整 SP 初始化顺序,使用本地变量 pass_config 简化重复引用。
  3. Pass 层强制执行:在 sequence_parallelism.pySequenceParallelismPass.is_applicable_for_rangecollective_fusion.pyAsyncTPPass.is_applicable_for_range 中,移除对 piecewise 模式的兼容逻辑,代之以明确的 assert,要求必须为 full-graph 模式。
  4. 运行时函数简化:在 vllm/v1/worker/utils.pyis_residual_scattered_for_sp 中,移除对 compile_sizes 的查询,直接断言 SP 要求 full-graph 编译,并简化返回逻辑。
  5. 测试配套:新增三个测试函数:test_sequence_parallelism_requires_full_graph_compilation(配置降级验证)、test_sequence_parallelism_pass_requires_full_graph_compilation(pass 断言触发验证)、test_async_tp_pass_requires_full_graph_compilation(异步 TP pass 断言验证)。
文件 模块 状态 重要度
vllm/config/vllm.py 配置层 modified 6.98
vllm/config/compilation.py 配置层 modified 6.7
vllm/compilation/passes/fusion/sequence_parallelism.py 编译层 modified 6.67
vllm/compilation/passes/fusion/collective_fusion.py 编译层 modified 6.08
vllm/v1/worker/utils.py Worker modified 6.18
tests/compile/test_config.py 测试 modified 6.59
tests/compile/passes/distributed/test_sequence_parallelism.py 测试 modified 5.68
tests/compile/passes/distributed/test_async_tp.py 测试 modified 5.64
tests/compile/correctness_e2e/test_sequence_parallel.py 测试 modified 3.42

关键符号

set_splitting_ops_for_v1 SequenceParallelismPass.is_applicable_for_range AsyncTPPass.is_applicable_for_range is_residual_scattered_for_sp test_sequence_parallelism_requires_full_graph_compilation test_sequence_parallelism_pass_requires_full_graph_compilation test_async_tp_pass_requires_full_graph_compilation

关键源码片段

vllm/config/vllm.py core-logic

核心配置文件,调整了 SP 初始化顺序、移除了 snapshot/reconcile 机制、简化了条件判断。是功能行为变更的主要入口。

# vllm/config/vllm.py 中 SP 初始化部分(调整后)# ... 省略前后文 ...
# async tp 建立在 seq parallelism 之上,需要它先启用
pass_config = self.compilation_config.pass_config
if pass_config.fuse_gemm_comms:
    pass_config.enable_sp = Trueif pass_config.enable_sp:
    if self.parallel_config.tensor_parallel_size == 1:
        logger.warning("Sequence Parallelism requires TP>1, disabling")
        pass_config.enable_sp = False
        pass_config.fuse_gemm_comms = False
    else:
        # 若未设置 min_token_num 阈值,则自动计算
        if pass_config.sp_min_token_num is None:
            from vllm.compilation.passes.fusion.sequence_parallelism import (
                get_sequence_parallelism_threshold,
            )
            tp_size = self.parallel_config.tensor_parallel_size
            hidden_size = self.model_config.get_hidden_size()
            element_size = self.model_config.dtype.itemsize
            pass_config.sp_min_token_num = get_sequence_parallelism_threshold(
                hidden_size, tp_size, element_size
            )
​
        if pass_config.sp_min_token_num is None:
            logger.warning(
                "Model hidden_size too small for the SP threshold heuristic, "
                "disabling. To force SP, set pass_config.sp_min_token_num manually."
            )
            pass_config.enable_sp = False
            pass_config.fuse_gemm_comms = False
# 随后在 set_splitting_ops_for_v1 之后调用 _finalize_sequence_parallelism_config
# 该函数会再次检查冲突并可能强制 full-graph 编译
# ... 省略后文 ...
vllm/config/compilation.py core-logic

新增 SP 与 piecewise 编译冲突的自动降级逻辑,是核心行为变更之一。

# vllm/config/compilation.py 中 set_splitting_ops_for_v1 方法片段# ... 原有逻辑 ...
# 当启用 SP 且未使用 Inductor 分区时,piecewise 编译与 SP 不兼容
if (
    not self.use_inductor_graph_partition
    and (self.pass_config.enable_sp or self.pass_config.fuse_gemm_comms)
    and self.splitting_ops
):
    logger.warning_once(
        "Sequence parallelism requires full-graph compilation when "
        "use_inductor_graph_partition is off. Setting splitting_ops "
        "to an empty list to preserve SP and async TP."
    )
    self.splitting_ops = [] # 强制全图编译
    if self.cudagraph_mode.has_piecewise_cudagraphs():
        logger.warning_once(
            "Sequence parallelism is incompatible with piecewise "
            "cudagraph when use_inductor_graph_partition is off. "
            "Setting cudagraph_mode to FULL."
        )
        self.cudagraph_mode = CUDAGraphMode.FULL # 降级 CUDA graph 模式
# ... 后续逻辑 ...

评论区精华

是否需要在 pass 中保留显式断言 正确性

wangxingran222 和 ProExpertProg 都指出,即使配置层已保证冲突不会发生,仍应在 SequenceParallelismPass 和 AsyncTPPass 的 is_applicable_for_range 中添加 assert,以防通过非标准路径使用 pass 时产生错误。

结论:作者同意并添加了 assert。 · 已解决

配置冲突处理位置选择 设计

wangxingran222 建议将 SP 与 piecewise 的冲突直接放入 set_splitting_ops_for_v1 内部处理,而不是通过 snapshot/reconcile 机制,后者过于复杂且易出错。

结论:作者重构为在 set_splitting_ops_for_v1 中直接处理冲突,并移除 snapshot/reconcile。 · 已解决

测试覆盖度的讨论 测试

ProExpertProg 指出单元测试应该使用更真实的配置构造方式,而不是直接传入 MagicMock。wangxingran222 指出 e2e 测试 test_sequence_parallel.py 需要更新以适配新行为。

结论:作者调整了测试实现,使用 default_vllm_config 或 object.__new__ 构造,并更新了 e2e 测试的配置。 · 已解决

CUDAGraphMode 与 torch.compile 的正交性 正确性

wangxingran222 指出 SP 的条件不应依赖 CUDAGraphMode,因为 piecewise 编译可以独立于 cudagraph 模式存在。

结论:作者去除对 CUDAGraphMode 的依赖,仅基于 use_inductor_graph_partition 和 splitting_ops 判断。 · 已解决

风险与影响

  1. 配置静默覆盖风险:如果用户显式设置了 splitting_ops 并启用 SP,系统会自动清空 splitting_ops 并降级 cudagraph 模式。虽然日志中包含 warning,但用户可能未注意,导致与预期编译行为不一致(例如编译时间增加或 CUDA graph 行为改变)。
  2. 断言失败风险:新增的 assert 在非全图编译且 SP 仍启用的场景下会直接触发异常。虽然配置层已保证不会发生,但若存在绕过配置层的代码路径(如直接构造 Pass 实例),可能引发程序崩溃。
  3. 性能退化风险:强制全图编译可能增大编译时间或峰值内存,对首次启动延迟敏感的应用有不利影响。
  4. 兼容性风险:此前依赖 piecewise+SP 的用户(如有特殊编译需求)将受到影响,可能找不到替代方案。

影响范围:使用 torch.compile 并启用 Sequence Parallelism(enable_sp=True)的用户,尤其是显式设置 splitting_ops 或未启用 inductor 分区的用户。
用户层面:这些用户将不再获得 piecewise 编译下的 SP 优化(该优化本身可能不安全),而是被静默切换为 full-graph 编译。对于模型较小或 token 数较少的场景,SP 本身也可能因达不到阈值而被禁用。
系统层面:配置初始化流程被简化,移除了 snapshot/reconcile 二次计算逻辑,有利于维护。
团队层面:消除了一个已知的正确性 issue,降低了后续多模态模型引入时的兼容性风险。

配置静默覆盖 断言可能触发 性能退化(编译时间) 缺少用户通知文档

关联 Issue

#35771 [RFC][torch.compile]: Disable Sequence Parallelism (SP) for piecewise compilation

完整报告

参与讨论