昇腾 NPU 图模式推理优化实战:cann-recipes-infer 中 npugraph_ex 与 GE 图模式的适配指南
2026/9/18 15:04:36 网站建设 项目流程

昇腾 NPU 图模式推理优化实战:cann-recipes-infer 中 npugraph_ex 与 GE 图模式的适配指南

【免费下载链接】cann-recipes-infer本项目针对LLM与多模态模型推理业务中的典型模型、加速算法,提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-infer

本文基于 cann-recipes-infer 开源仓库的图模式适配技能文档(.agents/skills/model-infer-graph-mode/SKILL.md)及其三份参考指南,系统讲解如何在昇腾 NPU 上通过torch.compile把 LLM 推理模型(重点是 Decode 阶段)适配到npugraph_ex(aclgraph 捕获回放)与 GE(Ascend IR)两种图模式,覆盖方案设计、图中断(Graph Break)与重编译修复、FA 融合算子参数配置、编译缓存以及验证测试全流程。读完本文,你将掌握一套可直接落地的图模式适配方法论:知道何时该用哪种模式、模型代码要满足哪些约束、actual_seq_lengths系列参数在不同图模式下应如何组织,并能结合仓库执行框架(executor/utils/graph_utils.py、executor/core/config/inference_config.py)理解底层编译接入与配置校验逻辑。

一、图模式适配的核心原则

在动手改造任何模型之前,先建立以下共识。这些原则来自技能文档的「重要原则」章节,是后续所有操作的前提:

  • 前置条件:模型必须已在 NPU 上运行且已导入torch_npu(导入后才会注册torch.npu设备相关 API)。
  • 图模式仅适用于 Decode 阶段:Prefill 阶段输入长度动态变化,不适合图模式,保持 eager 执行。这是全篇最重要的原则。
  • 保持模型完整性:不为适配图模式而简化模型逻辑,图模式改造应是对模型结构的适配而非阉割。
  • NPU 不支持的后端aot_eagerinductorcudagraphs等后端在昇腾 NPU 上不可用,不要沿用 CUDA 生态的编译路径。
  • 固定 tensor 图外预创建:attention_mask、KV cache 等推理全程不变的 tensor 应在图外预创建,需要时用torch._dynamo.mark_static()标记。
  • LLM Decode 重编译注意kv_len/actual_seq_lengths_kv每步都会变化,npugraph_ex可能因此触发重编译,遇到hit recompile_limit时参考重编译解决方案排查(见第八章)。
  • npugraph_ex decode 用 host list 长度字段:从ForwardMetaDataactual_seq_lengths_list_kv/qactual_seq_lengths_cu_list_kv/qList[int]形态)传给静态图路径;普通 eager / GE 路径仍用对应的 Tensor 字段。这一点在仓库执行引擎中有直接实现,见第十章。
  • 图模式验证项:确认 warmup 阶段首次编译功能正常;正式推理 decode 阶段直接复用 warmup 编译的图,不出现重编译(检查日志中是否有recompile标识)。
  • 编译缓存使用时机:先用常规图模式确认图可稳定捕获且无非预期重编译,再按官方指南使用cache_compile降低冷启动 / 重复编译耗时。
  • 精度问题调试:遇到精度问题可调用仓库中model-infer-precision-debugskill 进行排查。

二、图模式适配工作流程

技能文档给出了一套四步走的标准化流程,特别强调方案设计必须先经用户确认再开发

  1. 方案设计
    • 分析模型结构:识别模型中可能阻碍图模式的代码模式(如torch.cat扩展 KV cache、.item()调用、基于 Tensor 值的 Python 分支等);
    • 识别问题点:找出 Graph Break、重编译、动态 shape 等问题;
    • 设计改造方案:明确需要修改哪些文件、修改的具体内容、对现有功能的影响评估;
    • 输出设计方案文档:以 Markdown 格式呈现。
  2. 方案确认:等待用户确认方案后再进行开发;有修改意见则返回第一步。
  3. 实施开发:按照确认的设计方案逐步实施代码修改。
  4. 验证测试:由 Agent 实际执行以下测试并记录真实结果:
    • 编译验证:运行torch.compile,检查是否成功,记录编译日志;
    • 功能验证:运行模型,对比图模式前后输出;
    • 性能验证:记录 Prefill / Decode 阶段耗时;
    • 编译缓存验证(可选):图结构稳定后可验证cache_compile是否降低二次启动编译耗时;
    • 测试报告:整理测试环境、测试用例、对比数据。

三、图模式选型:npugraph_ex 与 GE 图模式

在开始适配前先确定使用哪种模式。如果用户未指定,默认采用 npugraph_ex

场景推荐模式详细文档
LLM 大语言模型npugraph_ex(优先阅读 LLM 指南).agents/skills/model-infer-graph-mode/references/llm-model-guide.md
通用模型npugraph_ex.agents/skills/model-infer-graph-mode/references/npugraph_ex-guide.md
需要 GE 图模式GE(Ascend IR).agents/skills/model-infer-graph-mode/references/ge-graph-guide.md

两种模式的核心差异如下表:

特性npugraph_ex 后端 (aclgraph)GE 图模式 (Ascend IR)
启用方式backend="npugraph_ex"torchair.get_npu_backend()
实现原理捕获模式 (Capture & Replay)FX 图转换为 Ascend IR,GE 引擎编译执行
成熟度试验特性,暂不支持商用更成熟稳定
PyTorch 版本需要 2.6.0+无特殊要求
支持场景在线推理通用场景
类似技术torch.cuda.CUDAGraph传统图编译
配置方式options={}参数CompilerConfig对象

npugraph_ex 快速示例

import torch import torch_npu model = YourModel().to("npu") opt_model = torch.compile(model, backend="npugraph_ex", fullgraph=True, dynamic=False) # 注:LLM Decode 场景 actual_seq_lengths 每步变化时需 dynamic=True output = opt_model(input_tensor)

关键约束:PyTorch 2.6.0+、仅支持在线推理、不支持随机数算子和动态控制流、forward 中不可使用.item()

GE 图模式快速示例

import torch import torch_npu import torchair from torchair import patch_for_hcom patch_for_hcom() # 集合通信入图(有 TP/EP 并行时需调用) model = YourModel().to("npu") config = torchair.CompilerConfig() npu_backend = torchair.get_npu_backend(compiler_config=config) opt_model = torch.compile(model, backend=npu_backend) output = opt_model(input_tensor)

仓库中的模式接入实现

从源码结构看,仓库执行框架把两种模式的编译入口统一封装在 executor/utils/graph_utils.py 的compile_model_forward()函数中,图编译前有一段通用准备:

import torchair as tng import torchair.ge_concrete_graph.ge_converter.experimental.patch_for_hcom_allreduce tng.patch_for_hcom() torch._dynamo.config.inline_inbuilt_nn_modules = False

其中tng.patch_for_hcom()处理集合通信入图(PyTorch 2.6 及之后版本中通常可省略),inline_inbuilt_nn_modules = False避免内建模块被过度内联。随后按exe_mode分派:exe_mode == "npugraph_ex"时走torch.compile(model_forward, dynamic=enable_dynamic_graph, fullgraph=True, backend="npugraph_ex", options=compile_options);否则构建CompilerConfig并设置frozen_parametertiling_schedule_optimizetopology_sorting_strategy等实验性配置,再通过tng.get_npu_backend(compiler_config=compiler_config)获取 GE 后端。

执行模式的配置项定义在 executor/core/config/inference_config.py 的ModelConfig中:

配置项默认值说明
exe_mode"eager"执行模式,仅支持eagerge_graphnpugraph_ex三者之一,非法值会抛ValueError
enable_cache_compileFalse是否启用编译缓存
enable_static_kernelFalse是否启用静态 kernel 加速,仅支持exe_mode='npugraph_ex',其他模式会报错
enable_dynamic_graphTrue是否使用动态图编译;ge_graph模式下只支持静态图,该开关会被忽略并告警

此外,ModelConfig._validate()还有两个值得注意的副作用:当exe_mode == "npugraph_ex"或平台为 Ascend 950 时,会设置环境变量TASK_QUEUE_ENABLE=1(npugraph_ex 只支持 0 或 1);否则设为2(eager 下优化 host 性能的默认值)。真实配置示例可参考 models/deepseek_v4/config/ci_a3/deepseek_v4_flash_rank_128_128ep_w8a8.yaml,其中exe_mode: "npugraph_ex"enable_static_kernel: Trueenable_dynamic_graph: False

四、npugraph_ex 后端使用详解

适用场景

  • 在线推理场景:追求简单快速适配;
  • 熟悉 CUDAGraph 模式:使用习惯类似;
  • LLM Decode 阶段:固定 shape 的单 token 输入。

使用约束

约束项说明
PyTorch 版本需要 2.6.0 及以上版本
支持场景在线推理场景,不支持反向流程 capture
随机数算子不支持 capture(randn、dropout 等)
动态控制流不支持,需保证图静态
Stream 同步不支持 stream sync 操作
成熟度试验特性,暂不支持商用产品

options 配置速查

opt_model = torch.compile( model, backend="npugraph_ex", fullgraph=True, options={ # ========== 调试 ========== "force_eager": False, # 强制 eager 模式调试 # ========== FX图优化 ========== "inplace_pass": True, # 原地操作优化 "input_inplace_pass": True, # 输入原地优化 "pattern_fusion_pass": True, # 算子融合 # ========== 内存优化 ========== "reuse_graph_pool_in_same_fx": True, # 图池复用 "clone_input": True, # 克隆输入 "clone_output": False, # 克隆输出 "use_graph_pool": None, # 图池配置 # ========== 性能优化 ========== "static_kernel_compile": False, # 静态Kernel编译 "remove_noop_ops": True, # 移除空操作 "frozen_parameter": False, # 冻结参数 # ========== 捕获控制 ========== "capture_limit": 64, # 重捕获次数限制 } )

在仓库的compile_model_forward()中,npugraph_ex 的compile_options至少包含frozen_parameter=Truestatic_kernel_compile=enable_static_kernelsuper_kernel_optimize=enable_superkernel等项,读者可以对照上表理解每个开关的定位。

核心 API

API用途
compile_fx()自定义 backend
register_replacement()自定义算子融合
cache_compile()编译缓存
limit_core_num()限核功能

常见问题

  1. 如何判断是否应该使用 npugraph_ex?适合:LLM decode 阶段、固定 shape 推理、简单快速适配;不适合:需要动态 shape、生产环境稳定性优先、训练场景。
  2. 报错"不支持 capture"怎么办?检查代码中是否包含随机数算子(randn、dropout)、动态控制流(基于 tensor 值的 if/while)、.item()调用。
  3. 性能劣化怎么办?开启重编译日志torch._logging.set_logs(recompiles=True),检查是否发生重编译,再参考 LLM 模型改造指南排查。

五、GE 图模式使用详解

GE 图模式通过 TorchAir 的CompilerConfig开启,将 FX 图转换为 Ascend IR 图,并通过 GE 图引擎实现图编译和执行。它更适合生产环境(稳定性优先)通用场景(功能丰富)复杂模型(需要更多配置选项)

CompilerConfig 配置入口

config = torchair.CompilerConfig() # debug 类功能 config.debug.xxx = ... # export 类功能(离线导图) config.export.xxx = ... # dump_config 类功能 config.dump_config.xxx = ... # fusion_config 类功能 config.fusion_config.xxx = ... # experimental_config 类功能 config.experimental_config.xxx = ... # inference_config 类功能 config.inference_config.xxx = ... # ge_config 类功能 config.ge_config.xxx = ...

其中experimental_config承载frozen_parameter(冻结参数)、tiling_schedule_optimize(tiling 调度优化)、topology_sorting_strategy(拓扑排序策略)等图内优化——这与仓库 executor/utils/graph_utils.py 中CompilerConfig()的用法一一对应。

核心 API

API用途
CompilerConfig配置图模式功能
get_npu_backend()获取 NPU 后端
get_compiler()获取编译器
dynamo_export()导出模型
register_fx_node_ge_converter()注册转换器
register_replacement()自定义算子融合

两种模式选择建议

从仓库文档 docs/cann/zh/npu_graph_optimization.md 看,两种模式没有绝对优劣,当前建议是优先选择npugraph_ex,以降低适配成本、保留更接近 eager 的开发体验。一个值得注意的细节是:npugraph_ex 当前常保持dynamic=True,并不是因为图本身必须动态,而是与推理场景中部分 FIA 算子接口有关——部分actual_seq_lengths入参仍以list[int]形式传入,强行静态化容易触发重编译;后续算子接口补齐 Tensor 输入后,这类配置可以继续收敛。例如 deepseek_v4 不存在这类 list 输入,其配置便选择了静态图enable_dynamic_graph: False

六、编译缓存使用建议

cache_compile适合在图模式已跑通、输入 shape / guard / 通信域稳定后启用,用于降低冷启动或多次拉起时的编译耗时;它不用于修复 Graph Break 或非预期重编译。启用时需按官方指南改造封装函数:

  • npugraph_ex 使用torch.npu.npugraph_ex.inference.cache_compile
  • GE / Ascend IR 使用torchair.inference.cache_compile
  • 使用后原torch.compile编译流程不再需要。

被缓存的函数应满足:是 module method、未被其他装饰器修饰、能形成 full graph,且同一缓存函数只能触发一次 Dynamo trace;Prefill / Decode 或 guard 不同的场景应拆分封装。若模型代码、输入规格、分布式 rank/world_size、CANN/torch_npu 版本发生变化,需重新生成或清理缓存。

仓库中的对应实现同样在 executor/utils/graph_utils.py:npugraph_ex 路径调用torch.npu.npugraph_ex.inference.cache_compile(model_forward, cache_dir=cache_dir, dynamic=enable_dynamic_graph, options=compile_options);GE 路径调用tng.inference.cache_compile(model_forward, cache_dir=cache_dir, config=compiler_config, dynamic=False, fullgraph=True, ge_cache=True)cache_dir默认位于model_config.output_path/compile_cache下,还支持通过cache_namespace为独立的静态图 shape 指定子目录。无论哪种模式,缓存命中都取决于模型代码、输入规格(shape/dtype)、编译配置和cache_dir是否保持一致,任意一项变化都会导致缓存失效并重新编译。

七、LLM 模型适配要点

对于 LLM 推理模型,必须严格区分 prefill 和 decode 阶段。图编译后会生成静态计算图,任何动态行为都可能导致图中断(graph break)或重编译,因此改造的关键是识别并隔离动态因素

Prefill 与 Decode 阶段限制

阶段是否支持图模式原因
Prefill禁止使用输入长度动态变化、首 token 生成逻辑复杂、shape 不固定
Decode推荐使用输入长度固定(通常为 1)、shape 稳定、适合图捕获

实现建议:将 prefill 和 decode 的 forward 逻辑分离成不同方法;仅对 decode 方法应用torch.compile图模式;prefill 阶段使用 eager 模式执行。

class YourModel: def prefill(self, input_ids, ...): """Prefill 阶段:使用 eager 模式""" # 输入长度动态变化,不适合图模式 return self._forward(input_ids, ...) def decode(self, input_ids, ...): """Decode 阶段:可使用图模式""" # 输入长度固定(通常为 1),适合图捕获 return self._forward(input_ids, ...) # 仅对 decode 方法应用图模式, model.prefill保持 eager model.decode = torch.compile(model.decode, backend="npugraph_ex", ...)

核心改造原则

核心原则:将动态变化的东西提取为模型输入,模型内部尽量保证静态。

动态因素问题表现解决思路
内存地址变化Guard 失败、重编译预分配固定大小,原地更新
Shape 变化图中断、多次编译固定 shape 或通过参数控制
Python 控制流Graph Break使用 Tensor 操作或模式参数
.item()调用强制 Graph Break保持 Tensor 或外部传入

重编译问题定位与解决

如果图模式性能劣化,必须定位是否发生了重编译:

# 开启重编译日志 torch._logging.set_logs(recompiles=True) # 运行模型 output = compiled_model(input) # 如果发生重编译,会打印类似: # [recompiles] Recompiling function <func_name> for reason: <reason>

重编译解决方案:

dynamic=False: 检测到重编译 │ └─→ 分析重编译原因 ├── 固定 shape 但仍重编译 → dynamic=False + skip_guard_eval_unsafe=True └── 输入 shape 变化 → dynamic=True

区分 Prefill/Decode 实践指南

为模型添加独立的prefill()decode()方法,通过is_prefill参数区分执行路径:

# === 模型层 === class MyModelForCausalLM(nn.Module): def forward(self, input_ids, position_ids, past_key_values, is_prefill=False, **kwargs): # is_prefill 控制不同执行路径 if is_prefill: # Prefill 专属:SP all-gather、取最后 token logits pass else: # Decode 专属:多流并行、原地更新 KV cache pass return logits def prefill(self, **kwargs): return self.forward(is_prefill=True, **kwargs) def decode(self, **kwargs): return self.forward(is_prefill=False, **kwargs) # === Runner 层 === class MyRunner: def model_inference(self, model_inputs, is_prefill=False): if is_prefill: return self.model.prefill(**model_inputs) else: return self.model.decode(**model_inputs) # 适合图模式

八、模块级改造指南

1. KV Cache 模块改造

改造目标:消除 KV Cache 动态扩展导致的 shape 变化,实现固定大小 cache 的原地更新。

核心思路:① 预分配策略——在模型初始化时分配固定大小的 cache;② 原地更新原则——使用原地更新算子写入新值,避免重新分配;③ 有效长度控制——通过参数控制实际参与计算的长度;④ 返回优化——图模式下不返回 KV cache(已原地更新)。

# 问题模式:动态扩展 KV cache key = torch.cat([past_key, new_key], dim=1) # shape 变化! # 改造模式:固定大小预分配 + 原地更新 # 1. 初始化时预分配 def _init_kv_cache(self, batch_size, max_seq_len, device): cache_shape = (batch_size, 1, max_seq_len, head_dim) self.kv_cache = torch.zeros(cache_shape, dtype=dtype, device=device) # 2. forward 中原地更新 def forward(self, ..., kv_len, past_key_value): torch_npu.scatter_update_(past_key_cache, kv_len, new_key_states, dim=-2)

常见问题

问题现象根因解决方案
每次 decode 触发重编译torch.cat扩展 KV cache预分配固定大小,原地更新
内存占用过大预分配浪费结合 PagedAttention 按 block 管理
返回 KV cache 开销大图模式下返回大量 tensor已原地更新,无需返回

2. Rotary Embedding 模块改造

改造目标:消除动态计算,实现静态图 cos/sin 查询。如果已经使用了融合算子、没有触发静态图的限制,则无需改造。

def forward(self, x, kv_len, is_prefill=True): if is_prefill: cos = self.cos_cached[:seq_len] # prefill:切片 else: cos = torch.index_select(self.cos_cached, dim=0, index=kv_len.view(-1)) # decode:索引 return cos.to(x.dtype), sin.to(x.dtype)

核心思路:预计算 cos/sin(初始化时计算所有位置值并缓存)、索引查询(通过index_select或切片获取)、外层计算优化(在模型外层统一计算,传入各层)。

3. Attention 模块改造

改造目标:使 Attention 计算图模式友好,支持 Flash Attention 等融合算子。核心思路:优先使用 NPU 提供的融合 attention 算子;通过参数控制有效长度,避免大规模 attention mask;使用模式参数区分 prefill/decode 计算路径。融合算子选型可参考仓库中的model-infer-fusionskill(.agents/skills/model-infer-fusion/SKILL.md)。

4. Buffer/Parameter 模块改造

改造目标:避免 buffer/parameter 地址变化触发 guard 失败。核心思路:初始化时分配最大可能大小;使用copy_()fill_()等原地操作;通过index_select、切片等只读方式访问。

5. 动态信息外部化设计

改造目标:将动态变化的信息从模型内部移到输入参数。

动态信息内部计算外部传入
位置索引position_ids = torch.arange(seq_len)作为参数传入
序列长度seq_len = hidden_states.size(1)actual_seq_lengths参数
写入位置内部计算kv_lenkv_len参数
模式切换内部判断is_prefill参数

forward 签名设计参考

def forward( self, input_ids: torch.LongTensor, # 位置相关(Tensor 形式支持图追踪) position_ids: Optional[torch.LongTensor] = None, kv_len: Optional[torch.IntTensor] = None, # KV 写入位置 # 序列长度(List[int] 传给 NPU 算子) actual_seq_lengths_kv: Optional[List[int]] = None, actual_seq_lengths_q: Optional[List[int]] = None, # 模式控制 is_prefill: bool = False, # KV Cache past_key_values: Optional[Tuple[torch.Tensor]] = None, # 预计算的 cos/sin(避免重复计算) cos: Optional[torch.Tensor] = None, sin: Optional[torch.Tensor] = None, ... ): pass

6. 不要在 forward 中使用.item()

.item()将 Tensor 转换为 Python 标量会强制触发 Graph Break:

# 错误写法 - 会导致 Graph Break max_pos_id = position_ids.max().item() + 1 # 正确写法 - 使用静态参数或预计算 max_pos_id = MAX_SEQ_LEN # 作为常量传入

7. 推荐配置

npugraph_ex 后端(推荐用于 LLM Decode)

import torch import torch_npu model = YourModel().npu() opt_model = torch.compile( model, backend="npugraph_ex", fullgraph=True, dynamic=False, # LLM decode 固定 shape options={ # FX图优化 "inplace_pass": True, "input_inplace_pass": True, "pattern_fusion_pass": True, # 内存优化 "reuse_graph_pool_in_same_fx": True, "clone_input": True, "clone_output": False, # 性能优化 "remove_noop_ops": True, } )

GE 图模式

import torch import torch_npu import torchair from torchair import patch_for_hcom patch_for_hcom() # 集合通信入图(有 TP/EP 并行时需调用) config = torchair.CompilerConfig() # 根据需要配置 inference_config, ge_config 等 npu_backend = torchair.get_npu_backend(compiler_config=config) opt_model = torch.compile(model, backend=npu_backend)

九、问题定界流程

问题定界应优先基于本 skill 内置的知识进行独立分析,避免盲目复制其他模型的图模式配置:

问题发生 │ ├─→ aot_eager 验证 ──失败──→ 修复用户脚本 │ ↓ 正常 │ ├─→ force_eager/run-eagerly ──失败──→ 修复用户脚本 │ ↓ 正常 │ └─→ 图模式问题 ├── 重编译问题 → 阅读 LLM 指南 + npugraph_ex 指南 ├── Graph Break 问题 → 阅读 TorchAir 在线文档中的典型案例 └── 其他问题 → 阅读对应模式文档(npugraph_ex-guide.md 或 ge-graph-guide.md)

调试知识来源(按优先级):① 本文档(SKILL.md)中的方法、原则和检查清单;② .agents/skills/model-infer-graph-mode/references/npugraph_ex-guide.md;③ .agents/skills/model-infer-graph-mode/references/llm-model-guide.md;④ .agents/skills/model-infer-graph-mode/references/ge-graph-guide.md;⑤ TorchAir 官方文档(按需查阅其在线文档中的案例与 FAQ 章节)。

十、图模式 + FA 融合算子快速 Debug

图模式与 FA 融合算子结合时,actual_seq_lengths参数的处理是最常见的出错点

问题现象

  • 编译报错:actual_seq_lengths类型不匹配;
  • 运行时报错:重编译(recompile)触发;
  • 性能问题:动态 shape 导致无法充分优化。

关键参数:actual_seq_lengths

FA 算子的actual_seq_lengths/actual_seq_qlen/actual_seq_kvlen参数在不同图模式下有不同的要求:

图模式FA 接口来源actual_seq_lengths 类型dynamic 设置执行模式约束说明
GE 模式(推荐)torchair FA 接口Tensordynamic=False仅支持 GE 图模式最佳方案,静态图
GE 模式(不推荐)torch_npu FA 接口list[int]dynamic=True+mark_static无限制需额外配置,易出错
npugraph_ex 模式torch_npu FA 接口list[int]dynamic=True无限制动态捕获模式
npugraph_ex 模式torch_npu FA 接口Tensor(如有)dynamic=False无限制需确认接口是否支持

GE 模式配置方案一:torchair FA 接口(推荐)

import torch import torch_npu import torchair from torchair.ge_concrete_graph.ge_graph import mark_static # 使用 torchair 提供的 FA 接口 # actual_seq_lengths 为 Tensor 类型 attn_output = torchair.ops.npu_fused_infer_attention_score( query, key, value, actual_seq_qlen=actual_seq_qlen_tensor, # Tensor 类型 actual_seq_kvlen=actual_seq_kvlen_tensor, # Tensor 类型 # ... 其他参数 ) # 编译配置 opt_model = torch.compile(model, backend=npu_backend, dynamic=False)

优点dynamic=False可获得更好的静态图优化;无需额外的mark_static配置;图编译更稳定。

约束:TorchAir FA 接口仅支持 GE 图模式,不支持 Eager 模式和 npugraph_ex 模式调用。

GE 模式配置方案二:torch_npu FA 接口(不推荐)

import torch import torch_npu import torchair from torchair.ge_concrete_graph.ge_graph import mark_static # 使用 torch_npu 的 FA 接口 # actual_seq_lengths 为 list[int] 类型 attn_output = torch.ops.npu.npu_fused_infer_attention_score( query, key, value, actual_seq_lengths=[seq_len], # list[int] 类型 actual_seq_lengths_kv=[kv_len], # ... 其他参数 ) # 必须配置 dynamic=True # 并使用 mark_static 标记除 actual_seq_lengths 外的静态输入 mark_static(input_ids) # 静态输入 mark_static(position_ids) # 静态输入 mark_static(attention_mask) # 静态输入 # actual_seq_lengths 保持动态 # 编译配置 opt_model = torch.compile(model, backend=npu_backend, dynamic=True)

缺点:需要配置dynamic=True,性能略逊于静态图;需要手动调用mark_static标记所有静态输入;配置繁琐,易遗漏导致问题。

npugraph_ex 模式配置方案一:list[int] 类型 + dynamic=True

import torch import torch_npu # 使用 torch_npu 的 FA 接口 # actual_seq_lengths 为 list[int] 类型 attn_output = torch.ops.npu.npu_fused_infer_attention_score( query, key, value, actual_seq_lengths=[seq_len], # list[int] 类型 actual_seq_lengths_kv=[kv_len], # ... 其他参数 ) # 必须配置 dynamic=True opt_model = torch.compile(model, backend="npugraph_ex", dynamic=True)

npugraph_ex 模式配置方案二:Tensor 类型 + dynamic=False(如有接口支持)

import torch import torch_npu # 查询是否有 Tensor 类型的 actual_seq_lengths 接口 # 通过 subagent 调用 model-infer-fusion 查询 # 如果有支持的接口: attn_output = torch.ops.npu.npu_fused_infer_attention_score( query, key, value, actual_seq_lengths=actual_seq_lengths_tensor, # Tensor 类型 actual_seq_lengths_kv=actual_seq_kvlen_tensor, # ... 其他参数 ) # 可配置 dynamic=False opt_model = torch.compile(model, backend="npugraph_ex", dynamic=False)

仓库中的 host list 转换实现

从源码看,仓库执行引擎 executor/core/engine/execution_engine.py 在 Decode 阶段为 npugraph_ex 做了专门的 host list 转换:当self.exe_mode == "npugraph_ex"且处于 decode(非 prefill)路径时,会将actual_seq_lengths_cu_kv/qactual_seq_lengths_kv/q等 Tensor 通过detach().cpu().numpy().tolist()转为List[int]形态,再通过set_forward_metadata()写入 executor/utils/forward_metadata.py 中定义的actual_seq_lengths_cu_list_kvactual_seq_lengths_cu_list_qactual_seq_lengths_list_kvactual_seq_lengths_list_q字段,供静态图路径使用;prefill 阶段这些 list 字段保持None。这与技能文档「npugraph_ex decode 用 host list 长度字段」的原则完全对应。

常见错误与修复

错误现象根因修复方案
编译报错:actual_seq_lengths 类型错误GE 模式下 torch_npu FA 接口传 Tensor改用 torchair FA 接口,或改用 list[int] + dynamic=True
运行时频繁重编译dynamic=False 但 actual_seq_lengths 为 list[int]改用 Tensor 类型 + torchair 接口,或设置 dynamic=True
性能不达预期dynamic=True 导致无法充分优化尽量使用 torchair FA 接口 + dynamic=False
npugraph_ex 模式报错actual_seq_lengths 为 Tensor 但接口不支持确认接口支持情况,或改用 list[int] + dynamic=True
Eager 或 npugraph_ex 模式调用 TorchAir FA 报错TorchAir FA 接口仅支持 GE 图模式改用 torch_npu FA 接口,或切换到 GE 图模式

Debug 检查清单

在图模式 + FA 场景下,按以下清单逐一排查:

    1. 确认使用的图模式:GE 还是 npugraph_ex
    1. 确认 FA 接口来源:torch_npu 还是 torchair
    1. 若使用 torchair FA 接口,确认当前为 GE 图模式(不支持 Eager 和 npugraph_ex)
    1. 检查 actual_seq_lengths 类型:GE+torchair→Tensor;GE+torch_npu→list[int]+dynamic=True;npugraph_ex→list[int]+dynamic=True
    1. 检查 dynamic 配置是否与 actual_seq_lengths 类型匹配
    1. 若使用 GE + torch_npu FA + list[int],检查是否已 mark_static 标记所有静态输入
    1. 如有疑问,调用model-infer-fusionskill 查询接口详情

十一、进阶阅读与文档索引

围绕图模式,仓库还提供了以下可直接查阅的资料:

  • 原理向:docs/cann/zh/npu_graph_optimization.md 详细解释了 eager 模式与图模式的执行差异、npugraph_ex 的「捕获一次、多次回放」原理(Dynamo compile → Guards → aclgraph Capture → Input 处理 → Replay)、编译缓存的落盘与命中机制,以及ge_graphnpugraph_ex的选择建议。
  • 技能文档:本主题的完整技能定义见 .agents/skills/model-infer-graph-mode/SKILL.md,三份参考指南分别对应 npugraph_ex-guide.md、llm-model-guide.md、ge-graph-guide.md。
  • 框架代码:图编译统一入口 executor/utils/graph_utils.py;执行模式与图相关配置定义及校验 executor/core/config/inference_config.py;Decode 阶段 host list 长度字段的构造 executor/core/engine/execution_engine.py;元数据载体 executor/utils/forward_metadata.py。
  • 真实配置样例:使用 npugraph_ex 并开启静态 kernel 的示例 models/deepseek_v4/config/ci_a3/deepseek_v4_flash_rank_128_128ep_w8a8.yaml。
  • 图模式与增强特性叠加:图模式通常与编译缓存、静态 kernel、多流(docs/cann/zh/multi_stream_principles.md)、预取(docs/cann/zh/prefetch_principles.md)、superkernel(docs/cann/zh/super_kernel.md)等能力组合使用。推荐的推进顺序是:先跑通 eager 并完成功能与精度验证 → 打开图模式,消除 graph break 和 recompile → 对比 eager 与 graph 输出(至少覆盖一轮 Prefill 和多轮 Decode)→ 再按需开启enable_cache_compileenable_static_kernel、多流、限核或enable_superkernel。其中enable_static_kernel当前仅用于 npugraph_ex 相关路径,enable_superkernel当前主要在 ge_graph 模式下尝试。

最后再次强调图模式适配的收尾标准:确认 warmup 阶段首次编译功能正常,正式推理 decode 阶段直接复用 warmup 编译的图、日志中无recompile标识。只有满足这一条件,图模式的性能收益才会真正落在正式推理的关键路径之外。

【免费下载链接】cann-recipes-infer本项目针对LLM与多模态模型推理业务中的典型模型、加速算法,提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-infer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询