跳转至

ACL 图

概述

ACL 图是 vLLM 静态图执行在昇腾上的实现。上游 vLLM 和 PyTorch 文档已描述了通用图模型,包括 CUDAGraphMode、运行时调度、批次描述符、分桶与填充,以及全图和分段图的定义。本文档聚焦于 vllm-ascend 中昇腾特有的内容:平台集成点、ACL 图捕获引入的额外约束,以及在重放期间保持注意力参数正确的机制。

在昇腾上,设计目标与上游静态图执行一致:降低中小运行时形状的 host 启动开销。但实现边界有所不同。vLLM 提供通用调度路径,而 vllm-ascend 提供平台封装、捕获尺寸裁剪,以及 ACL graph 重放所需的 attention 特定更新逻辑。

前提条件与参考

本文档有意不重新解释上游主题,例如图模式选择、调度器行为、批次描述符构建、捕获分桶、填充策略,或全图与分段执行的通用含义。

ACL 图如何融入 vLLM

vLLM 拥有通用静态图流程。在昇腾上,NPUPlatform.get_static_graph_wrapper_cls() 返回 vllm_ascend.compilation.acl_graph.ACLGraphWrapper,这是 vLLM 启用静态图模式时使用的平台特定封装器。

ACLGraphWrapper 负责:

  • 从前向上下文中读取运行时模式和 batch_descriptor,
  • 决定是立即执行、捕获新的 ACL 图,还是重放缓存的 ACL 图,
  • 按批次描述符缓存图条目,
  • 保留昇腾后端所需的图池和重放记账信息。

该封装器不定义上游调度策略。它假定运行时模式和批次描述符已由 vLLM 正确选择,然后对该具体的运行时形状应用昇腾捕获或重放。

捕获大小与分桶

vLLM 图重放需要稳定的运行时形状,因此 vLLM 不会尝试捕获所有可能的批次形状。相反,它准备一组有限的捕获大小,并将运行时批次调度到最近的支持大小。如果运行时批次大于配置的最大捕获大小,则跳过图模式,执行回退到即时模式。

更多信息请参阅上游 CUDA Graphs 设计文档。

在昇腾上,这种通用的上游分桶策略仍然是起点,但最终的捕获大小可能会因平台特定约束而进一步减少:

  • 序列并行过滤可能会移除不支持的大小,
  • 运行时资源限制可能仍会阻止捕获某些配置的大小,
  • 某些运行时模式可能在捕获开始前被规范化。

昇腾特定设计约束

捕获广度仍受运行时资源限制

当所选的 graph 尺寸消耗的运行时资源超过当前后端所能提供的资源时,ACL graph 捕获可能会失败。Piecewise 模式是最敏感的情况,因为它会捕获大量子图,且总捕获开销随模型深度和配置的尺寸覆盖范围而增长。

当前实现可以为 graph 容量受限的硬件配置裁剪捕获尺寸集合。它还会在 vllm_ascend/compilation/acl_graph.py 中拦截已确认的捕获时 stream 资源特征,并以更清晰的缓解指导重新抛出。

在实践中,这意味着当捕获失败时,用户应将 cudagraph_capture_sizes 和 max_cudagraph_capture_size 视为主调优杠杆。较新的 HDK/CANN 组合可以显著提高 ACL 图容量,而通信密集型配置可能仍需要较小的配置大小集。

平台模式规范化比通用上游行为更严格

昇腾目前在 vllm_ascend.platform.NPUPlatform.check_and_update_config() 中收窄了一些通用上游模式。

  • 请求 full graph 模式的 encoder-decoder 模型在启用 vLLM 编译时回退到 PIECEWISE,否则回退到 NONE。
  • ACL graph 路径下 use_inductor 被禁用。
  • 根据配置,Xlite graph 模式可以禁用 ACL graph full 模式,或回退到 FULL_DECODE_ONLY。

这些检查记录了当前Ascend后端能够安全执行的上游图行为的子集。

关键的Ascend特有机制

用于全图重放的主机端注意力参数更新

Ascend上的全图重放有一个上游通用文档未详细说明的额外问题:即使整体图是静态的,某些注意力算子也需要运行时元数据更新。Ascend实现通过将图捕获与主机端任务参数更新分离来处理此问题。

流程如下:

  1. 在捕获期间,注意力后端记录每个图的任务句柄、事件、工作空间以及必须刷新的张量或元数据的弱引用。
  2. 在重放之前,update_full_graph_params() 调用后端特定的 update_graph_params() 实现。
  3. 该后端在底层注意力算子启动前后,使用 torch.npu.graph_task_update_begin(...) 和 torch.npu.graph_task_update_end(...) 在更新流上执行参数刷新。
  4. 使用 torch.npu.ExternalEvent 对象来强制主机端更新流与重放流之间的顺序。

该机制在以下注意力后端中实现:

  • vllm_ascend/attention/attention_v1.py
  • vllm_ascend/attention/mla_v1.py
  • vllm_ascend/attention/context_parallel/attention_cp.py
  • vllm_ascend/attention/context_parallel/mla_cp.py

重要的设计点是,Ascend全图支持依赖于后端提供的 update_graph_params() 钩子。没有这个钩子,仅靠捕获不足以重放正确的注意力状态。

重放顺序与同步

ACLGraphWrapper 在公共路径的重放前同步当前流,以确保主机端参数更新与将要使用它们的图执行保持一致。这在异步调度或多线程执行中尤其重要。

如果顺序未被保持,迭代 i 的参数更新可能被迭代 i-1 的重放观察到,或者迭代 i 的重放可能在其自身的参数更新完成之前开始。在实践中,这意味着注意力算子可能以不匹配的运行时元数据运行,从而导致错误结果、精度问题甚至挂起。代码为主流全图eagle场景保留了一条更窄的路径,但总体设计假设是相同的:重放不能超越待处理的参数更新工作。

Ascend上的全图与分段模式

上游文档已在语义上定义了全图和分段图。在Ascend上,实际差异由后端支持和资源成本驱动。

分段模式

分段模式是保守路径。它依赖于通用的vLLM拆分执行策略,然后将ACL图捕获应用于编译路径选择的非注意力段。在Ascend上,此模式目前是更广泛支持的选项,但它对流压力也最敏感,因为捕获的图数量随模型深度扩展。

全图模式

当注意力后端能够通过 update_graph_params() 支持运行时参数修补时,全图模式是更注重性能的路径。在Ascend上,全图支持与那些注意力特定的更新钩子、工作空间缓存和重放顺序保证相关联。

诊断与操作说明

  • 确认 graph 模式是否启用的最简单方法是启用 cudagraph 指标并保持 log stats 启用。在 CLI 用法中,使用 --cudagraph-metrics 且不要传入 --disable-log-stats。在 Python 用法中,设置 cudagraph_metrics=True 和 disable_log_stats=False。然后检查输出的指标和日志。
  • Profiling 也可以确认是否正在发生重放,开发者在本地调试时可以在重放前添加临时打印,但这些是次要方法,此处不再展开。
  • 捕获尺寸选择遵循上游配置,并带有平台过滤和硬件特定裁剪。ACLGraphWrapper 为已识别的旧 HDK 和 stream 资源捕获错误添加了指导。
  • 在 debug 模式下,ACLGraphWrapper 会断言重放使用与捕获时记录的相同 tensor 地址。
  • 对于 graph 执行内部的调试,仓库还在 vllm_ascend.utils 中提供了 graph 感知的打印辅助工具,但这些属于开发者诊断工具,而非执行设计的一部分。

相关文件

  • vllm_ascend/platform.py,模式规范化、平台钩子和静态图包装器选择。
  • vllm_ascend/compilation/acl_graph.py,ACL图包装器、捕获与重放缓存、图参数容器以及全图更新分发。
  • vllm_ascend/compilation/acl_graph.py,运行时ACL图捕获、重放和捕获失败指导。
  • vllm_ascend/attention/attention_v1.py,全图注意力参数捕获与更新逻辑。
  • vllm_ascend/attention/mla_v1.py,MLA(多头潜在注意力)特定的全图参数捕获与更新逻辑。
  • vllm_ascend/attention/context_parallel/attention_cp.py,上下文并行注意力更新路径。
  • vllm_ascend/attention/context_parallel/mla_cp.py,上下文并行MLA更新路径。