Skip to content

vLLM Ascend ACL Graph 详解

在大语言模型推理场景中,最大化 NPU 计算资源利用率并减少 Host 端调度开销是性能优化的关键。本文将深入探讨 vLLM Ascend 平台上的 ACL Graph 功能,从设计背景、核心机制到实现细节与当前限制,提供一份详尽的技术指南。

1. 背景:为什么需要 ACL Graph

LLM 推理中,每个 Token 的生成都涉及数千个算子。在传统的 Eager Mode(即时执行模式) 下,Host(CPU)需要逐个向 Device(NPU)下发算子指令。

若 Host 下发速度慢于 Device 执行速度,就会出现 Host-Bound 现象。严重时,Device 可能一半以上时间处于空闲等待状态,造成巨大算力浪费。

ACL Graph(图模式) 通过将计算图进行捕获并一次性下发,显著减少 Host 与 Device 之间的通信开销:

  • Eager Mode(串行交互)

    • Host:Launch Op1 -> Launch Op2 -> Launch Op3 -> ...
    • Device:Run Op1 -> Run Op2 -> Run Op3 -> ...
    • 痛点:通信间隙导致 Device 频繁空闲。
  • Graph Mode(批处理交互)

    • Host:Launch Graph(包含所有 Ops)
    • Device:Run Op1 -> Run Op2 -> Run Op3 -> ...
    • 优势:Device 连续执行,吞吐量最大化。

2. 核心机制

ACL Graph 的工作流程主要分为两个阶段:

  1. 捕获(Capture):引擎启动时通过一次模拟前向传播捕获所有算子并保存为图。
  2. 重放(Replay):实际请求到达时,直接在 Device 上重放该图。

实际应用面临两个主要挑战:输入形状的动态性复杂算子的兼容性

2.1 填充与分桶(Padding and Bucketing)

图模式要求重放时的输入 Shape 必须与捕获时一致。然而 LLM 的输入 Shape 由调度器调度的请求决定,具有高度动态性。

  • 暴力解法:按最大可能 Shape 捕获一张图,将所有输入 Padding 到最大长度。这会带来大量无效计算。
  • 优化解法(Bucketing)
    1. 设定一个阈值。
    2. 低于阈值:预先捕获多个不同 Shape 的图(Bucket)。输入 Padding 到最近的 Bucket 大小,平衡计算效率与图复用率。
    3. 高于阈值:认为此时 Tensor 较大、计算密集,Host 调度开销占比降低,回退到 Eager Mode 以避免 Padding 开销。

2.2 分段图与全图(Piecewise and Full Graph)

随着模型架构演进(如 MLA),Attention 层日益复杂。当 Batch 中同时包含 Prefill 与 Decode Token 时,统一图模式难以处理。

vLLM Ascend 提供两种策略:

2.2.1 分段图(Piecewise Graph)

  • 原理:将模型切分,Attention 层使用 Eager Mode,其余层(MLP、LayerNorm)使用 Graph Mode。
  • 适用场景:无法运行全图的复杂 Attention 场景。
  • 缺点:相比全图,Host 下发开销依然存在;小 Batch 或弱 CPU 仍可能 Host-Bound。
  • 资源消耗:模型被切分为 num_hidden_layers + 1 个子模块,每个子模块作为独立图运行,消耗大量 Stream 资源。

2.2.2 全图(Full Graph)

  • 原理:包含 Attention 层在内的所有算子均在图中执行。
  • 优势:性能最优。
  • 实现难点:需在执行前更新 Attention 算子参数(如 Block Tables)。由于内存复用机制,必须使用特定 NPU 接口(graph_task_update)并配合事件(Event)同步,确保数据一致性。

调度策略优先级

  1. 首选 Full Graph 以获得最佳性能。
  2. 若全图不可用,降级为 Piecewise Graph
  3. 若性能仍不理想,采取混合策略:Decode 阶段用全图,Prefill 阶段用 Eager Mode。

3. 实现细节

vLLM 在 Ascend 上的图模式实现主要依赖 ACLGraphWrapper

  1. 装饰器拦截support_torch_compile 装饰器替换模型类的 __init__forward 接口。
  2. 执行流forward 被调用时,控制权移交给 ACLGraphWrapper,由其决定进行 Capture 还是 Replay。
  3. 参数更新:全图模式下,Ascend 后端实现 update_attn_paramsupdate_mla_attn_params,通过 torch.npu.graph_task_update_begin/end 在图执行任务中嵌入参数更新,确保内存复用时的正确性。

4. 资源约束与 DFX

4.1 Stream 资源限制

ACL Graph 的主要瓶颈在于 Stream(流) 资源:

  • 硬件 Stream 总数约 2048,预留部分后可用约 1800 个。
  • 每个图至少占用 1 个独立 Stream。
  • 每个通信域(Comm Domain)增加 1 个 Stream 消耗。
  • Piecewise Graph 的挑战:模型被切分为数十个子图,Stream 消耗远高于全图模式。

当前通过 update_aclgraph_sizes 函数动态计算最大支持的 Bucket 数量,防止 Stream 溢出。

4.2 当前限制

截至 v0.11.0+,存在以下限制:

  1. 暂不支持显式配置 FULLFULL_AND_PIECEWISE 模式(系统自动选择)。
  2. 启用 MTP(Multi-Token Prediction)且 num_speculative_tokens > 1 时,需显式设置 cudagraph_capture_sizes
  3. 暂不支持 use_inductor 后端。

5. 快速上手

在 vLLM Ascend 的 V1 Engine 中,ACL Graph 默认开启。确保配置中未设置 enforce_eager=True

bash
python -m vllm.entrypoints.openai.api_server \
  --model /path/to/your/model \
  --device ascend
  # 不要添加 --enforce-eager

更多详细配置请参考 vLLM 性能文档

参考

Maintained by Robin