已关闭
【RFC】Add an in-tree Fx graph executor backend fxrt. #4733
chz34创建于  9月10日关闭于  17 天前
chz34
chz34成员
9月10日 创建

状态 (Status): Draft
作者 (Authors): @chz34
创建日期 (Created): 2026-09-10
更新日期 (Updated): 2026-09-10
相关 Issue/PR: pytorch!45813


1. 概述

1.1 简介

FXRT 是一个面向推理的图运行时:接收一张 Torch FX 图,转换成自有的 C++ 图 IR,由自己的执行器在 Ascend / CPU 上执行,并返回一个可调用对象替代 PyTorch 执行该图。它对上不关心图从哪来(Dynamo 直出、Inductor 调度融合后的产物都可以),对下不绑定单一执行方式(逐算子在线下发、整图 AclGraph 捕获)。

本 RFC 提议把 FXRT 引入 torch_npu,作为 torch.compile 的一个可选后端随 wheel 一起交付。作为pytorch在npu硬件上的差异化能力补充。

1.2 动机

torch_npu 当前的图执行版图

现有路径 图表达 host 侧执行 主要约束
eager 无 Python 逐算子分发 每个算子都付一遍 Python 与 dispatch 开销
Inductor Python wrapper 源码 解释器逐行驱动分配与 launch wrapper 是源码而非结构化数据,图级分析与产物固化无从下手(上游fx_wrapper特性未适配)
torchair / GE GE 图 GE ExecuteGraph 执行 优化与融合方案与社区有差异,用户存在学习成本
npugraph / AclGraph 捕获的执行流 一次下发 要求图结构与地址稳定

缺口:社区Inductor方案已经把 lowering、调度与融合做得很好,但它的产物交给 Python 解释器执行,host 侧的内存分配、算子下发顺序、生命周期管理全都留在 Python 层;而 GE 与 AclGraph 这类整图方案要求的静态性,很多推理模型给不到。中间缺的是"结构化图 + C++ 侧图运行时"这一层:既把 host 开销压掉,又不要求整图固化,同时兼容现有的pytorch fx graph的技术生态。同时后续可以兼容gert此类npu上极致优化的专属运行时。

flowchart TB
    subgraph Source["图来源(PyTorch 侧)"]
        direction LR
        Dynamo[Dynamo 捕获图]:::external
        Inductor[Inductor<br/>lowering / 调度 / 融合]:::external
        AotAutograd[make_fx捕获图]:::external
    end

    subgraph Acquire["图接入层"]
        direction TB
        FxWrapper[fx_wrapper<br/>接管 Inductor 代码生成产物]:::module
        Entry([统一入口<br/>torch.fx.GraphModule]):::data
        FxWrapper --> Entry
    end

    subgraph Convert["图转换层"]
        direction LR
        DirectConv[直接映射转换器<br/>fx_backend]:::process
    end

    subgraph Core["内部图表达"]
        CppIr([C++ 图 IR<br/>Graph / Node / Value / Op]):::data
    end

    subgraph Exec["执行层"]
        direction LR
        Eager[Eager 参照基线]:::planned
        Online[fxrt 在线运行时<br/>算子调度下发]:::module
        Om2[gert 后端<br/>在线执行 / 离线 codegen]:::planned
    end

    Callable([可执行对象<br/>compiled_callable]):::data

    Dynamo --> Entry
    Inductor --> FxWrapper
    AotAutograd -.-> Entry
    Entry --> DirectConv
    Entry -. 旁路 .-> Eager
    DirectConv --> CppIr
    CppIr --> Online
    CppIr -.-> Om2
    Eager --> Callable
    Online --> Callable
    Om2 -.-> Callable

    classDef module fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef process fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef data fill:#ffedd5,stroke:#ea580c,color:#7c2d12
    classDef external fill:#f1f5f9,stroke:#94a3b8,color:#475569
    classDef planned fill:#fef9c3,stroke:#ca8a04,color:#713f12,stroke-dasharray: 4 3
    style Source fill:#f8fafc,stroke:#94a3b8
    style Acquire fill:#f0f9ff,stroke:#38bdf8
    style Convert fill:#f0fdf4,stroke:#16a34a
    style Core fill:#fff7ed,stroke:#ea580c
    style Exec fill:#faf5ff,stroke:#a855f7

1.3 目标

目标

  • 为 torch_npu 补上一条 FX 图 → C++ 图 IR → 运行时执行的路径,用户可以以 torch.compile 后端形式选用。
  • 该路径与 torch_npu 现有机制共用底座:同一个显存池、同一条下发流水、同一批融合算子,不另起一套资源管理。
  • 能承接 Inductor 的 FX 产物,对接上游fx_wrapper能力,将Inductor 的融合结果与 FXRT 的执行能力叠加,而不是二选一。
  • 随 torch_npu wheel 交付,装完即用,并保留一键关闭的构建开关。

非目标

  • 不设为 torch.compile 的默认后端,由用户显式指定。
  • 不替代 Inductor 的 lowering / 调度 / 融合决策,也不替代 torchair 的整图下沉路线。
  • 不承诺训练场景,当前定位为推理。

2. FXRT 带来什么

2.1 面向host bound的更广泛优化

在aclgraph的限制之外,提供更加高效的运行时调度能力。

收益点 机制
去 Python 开销 构图、图优化、Kernel 绑定、执行器编排都在编译期一次完成,执行期不回 Python 层做逐算子分发
硬件资源管理兼容 内存管理,流管理,线程管理与pytorch_npu复用同一资源池,相互兼容
并行与流水下发 执行器按依赖组织下发,可重叠 host 侧准备与 device 侧执行;可选多线程分组并行下发
高效infer shape 利用torch.compile 提供的符号信息,节省耗时的aten算子meta计算与校验,重整两阶段算子下发流程
整图地址规划(可选) 开启 kernel launch group 后,首轮 trace 每个 kernel 的输出与 workspace 地址区间,按区间并集合并为少量大块,后续执行只申请这几块并按 offset 重定位,热路径上不再逐算子申请释放
图捕获兼容(可选) 同一份 IR 之下可切到 AclGraph 捕获,进一步消除 host 下发开销
可调试 可退回语义等价的 eager 执行,把问题快速切分为"取图阶段"还是"转换与执行阶段"

2.2 与 torch_npu 现有能力的协同

FXRT 不是并行的第二套运行时,它与 torch_npu 的底座兼容。

  • 共用显存池:Ascend 上的申请与释放直接走 c10_npu::NPUCachingAllocator 的 raw_alloc / raw_delete,与 eager 张量共享同一个缓存池。上面那套提前释放因此立刻有意义:块回到池里就能被后续算子或 eager 张量复用,也不存在两套池各留一份显存的问题。
  • 共用下发流水:pipeline 模式下算子经 at_npu::native::OpCommand::RunOpApiV2 下发,即复用 torch_npu 的 task queue,受同一个 TASK_QUEUE_ENABLE 控制,与 eager 混跑时的下发时序一致。
  • 共用图捕获的内存池语义:AclGraph 捕获通过 caching allocator 的 beginAllocateToPool / endAllocateToPool 进行,与 torch_npu 自己的 npugraph 走同一套 mempool 机制。
  • 承接 Inductor 的 FX 产物:PyTorch 2.13 的 WrapperFxCodegen 可以让 Inductor 的 wrapper 层输出 FX GraphModule 而不是 Python 源码。FXRT 提供了对应的 fx_wrapper 接入,把这份 host FX 图路由到自己的运行时执行。这条路上 Inductor 负责融合、FXRT 负责执行,两者叠加而非互斥。
  • 融合算子保真传递:torch_npu / DVM 的融合 kernel 能以 higher-order op 的形式留在 host FX 图里,而不会被原生 WrapperFxCodegen 拒绝;fxrt.torch 另外提供 register_dvm_op / get_dvm_payload 供 DVM 侧对接。
  • 算子扩展入口:提供自定义算子注册的 C API 与 kernel lib 加载机制,新算子接入不必改运行时本体。

2.3 周边关联关系

关联对象 关系
eager FXRT 只接管被 torch.compile 圈住的子图,圈外仍是 eager,两者共享显存池与下发流水
Inductor 互补。Inductor 出融合与调度结果,FXRT 接住其 FX 产物负责 host 侧执行
torchair / GE 并列的两条路线。torchair 将fx graph整体转换到AIR后提供完整独立的图优化,编译,执行路径。FXRT 依然对接fx graph 表达,图编译优化仍依赖torch机制,只提供高效运行时
npugraph / AclGraph FXRT 把整图捕获作为自身 IR 之下的一种执行模式,共用 caching allocator 的 mempool,而非另做一套捕获

2.4 前提与当前限制

  • 收益集中在 host bound 的场景;device bound 的模型收益有限
  • 算子覆盖以 FXRT 已支持的集合为界,未覆盖算子按fallback路径处理,保证基础功能可用。
  • 动态 shape 由 symbolic shape 机制支持,覆盖范围以实测为准。
  • FXRT提供与gert(om2)的对接能力,但是相关实现待gert发布并验证稳定对接后再合入,目前仅实现fxgraph对接部分与复用torch_npu运行机制的极简运行时方案

3. 使用方法

安装 torch_npu wheel 即可,FXRT 已包含在内:

  1. 手动指定torch.compile的backend
import torch
import torch_npu
from torch_npu.fxrt import backend          # 等价于 from torch_npu.fxrt.torch import backend


def model(x, y):
    z = x + y
    z = z.view(4, -1)                   # view 类算子走零拷贝路径
    return torch.relu(z)


x = torch.randn(2, 8).npu()
y = torch.randn(2, 8).npu()

compiled = torch.compile(model, backend=backend)
print(compiled(x, y).shape)
  1. 与 Inductor 叠加使用时,使能fxrt时,默认打开 Inductor 的 fx_wrapper 开关,并接管当前fx_wrapper路径,生成的 host FX 图即路由到 FXRT(pytorhc_npu中暂无其他fx_wrapper路径对接)。 不主动使能fxrt的情况下,原有inductor的路径不受fxrt的任何影响,用户主动设置fx_wrapper之后,也只会对接原社区默认fx_wrapper实现。
torch._inductor.config.patch({"fx_wrapper": True})  # 原社区接口仅控制社区实现,不接入fxrt
torch_npu.fxrt.register_fx_wrapper()   # 设置fxrt使能后,内部会同步设置fx_wrapper=True,并接入fxrt实现, 可以不用torch._inductor.config.patch({"fx_wrapper": True}) 

约束:运行期需要匹配版本的 CANN,与 torch_npu 一致;import fxrt 需发生在 import torch_npu 之后,或直接由 import torch_npu 触发加载。

4. 落地方式

采用与 torchair 一致的 in-tree 集成:FXRT 源码以顶层 fxrt/ 目录随主仓演进,fxrt/fxrt/ 是 CMake 构建入口。选择源码目录而非 submodule,是因为 FXRT 直接依赖 torch_npu 的 C++ 符号,需要跟随主仓改接口并当次验证。

位置 改动
CMakeLists.txt BUILD_FXRT 开关下 add_subdirectory(fxrt/fxrt),位置在 torch_npu 目标创建之后
setup.py 检测到 fxrt/fxrt 存在时追加 -DBUILD_FXRT=on 与 -DFXRT_INSTALL_DST=<staging>/torch_npu/fxrt
ci/build.sh 新增 --disable_fxrt,落到 DISABLE_INSTALL_FXRT 环境变量

几个关键点:

  • Ascend 接口沿用 torch_npu 已有的一套方案:头文件取主仓自带的精简副本(third_party/acl/inc 与 third_party/hccl/inc),链接期用 third_party/acl/libs 下的桩库消解引用,真符号在运行期由 dlopen 加 dlsym 解析。FXRT 的 acl 与 hccl 调用本来就是同样的 dlsym 结构,因此 aclnn、内存、通信各类算子都按同一条路径接入,构建机无需安装 CANN。
  • FXRT 内部使用绝对 fxrt.* 导入,因此 torch_npu/__init__.py 的 _load_fxrt() 按顶层名 fxrt 从物理路径加载,再把 fxrt.* 镜像为 torch_npu.fxrt.*,两种写法拿到同一批模块对象;加载失败静默回滚,--disable_fxrt 的 wheel 行为与合入前一致。
  • 首期版本裁剪了对接(GE ExecuteGraph / ModelV2)相关能力与测试,只保留纯 FX 图运行时,相关能力待成熟后开放。

5. 测试设计

torch_npu测试验证

  1. 构建打包安装行为不影响torch-npu的包。
  2. 不主动使能fxrt情况下,原有torch-npu行为不受fxrt任何影响。

fxrt测试验证

  • 构建门禁:默认开启 FXRT 的完整源码构建;另跑一次 --disable_fxrt,确认关闭路径产物与合入前一致。
  • 导入用例:import torch_npu 后校验 fxrt 与 torch_npu.fxrt 指向同一模块对象。
  • 功能用例:torch.compile(fn, backend=backend) 在 NPU 上跑通基础算子、view 类算子与端到端推理模型,与 eager 对拍。
  • 协同用例:Inductor fx_wrapper 开启后的端到端执行,含 DVM,autofuse融合算子的图。
  • 性能基线:选取 host bound 的推理模型,给出 eager / Inductor / FXRT 的时延与峰值显存对照,作为后续演进的基线。
  • FXRT 自带用例:fxrt/tests/ 保留上游 ST / UT,按需接入主仓门禁。

6. 未解决问题

CI 需要适配:主仓门禁目前不认识 fxrt/ 目录,改动挑不到 FXRT 用例,用例落位、门禁分层、构建时长、性能基线的门禁形态等都待定。

likedislike
TorchNPU-BotTorchNPU-Bot成员
9月10日 添加了label:triage-review
TorchNPU-Bot
TorchNPU-Bot成员
9月10日 评论:

issue待分派,添加triage-review标签

likedislike
TorchNPU-BotTorchNPU-Bot成员
9月10日 添加了label:bot-triaged;删除了label:triage-review
TorchNPU-Bot
TorchNPU-Bot成员
9月10日 评论:

检测到当前 issue 已关联 PR,自动添加标签:bot-triaged

likedislike
chz34chz34成员
9月10日 修改了issue 的描述
此处折叠了12条事件消息 查看更多
chenrayraychenrayray成员
9月24日 关联了里程碑:v26.2.0
zyli2020成员
9月29日 评论:

【漏洞分析】
经典 rpath 漏洞模式不存在:

  1. 全部以 $ORIGIN 开头——无纯相对路径、无空分量(:: 或首尾 : 会解析为 CWD,是经典注入点)
  2. BUILD_WITH_INSTALL_RPATH TRUE 防构建机绝对路径泄漏进 wheel
  3. JIT 用 --disable-new-dtags(DT_RPATH 优先于 LD_LIBRARY_PATH),算子库的 libfxrt.so 等解析无法被用户环境变量劫持
likedislike
chenrayraychenrayray成员
21 天前 移除了里程碑
chz34chz34成员
17 天前 issue状态由 TODO 改变为 DONE
chz34chz34成员
17 天前 关闭了 issue
ascend-robotascend-robot成员
17 天前 添加了label:resolved
Zzyli2020成员
3 天前 修改了issue 的描述
Zzyli2020成员
3 天前 修改了issue 的描述