已合并
perf: defer dynamo/inductor import for v2.7.1 (#2788) #43391
黄桂军创建于 21 天前
perf: defer dynamo/inductor import for v2.7.1 (#2788) #43391
已合并
黄桂军创建于 21 天前
黄桂军
黄桂军成员
21 天前

【合入来源】

关联社区 issue:https://gitcode.com/Ascend/pytorch/issues/2788

【修改方案】

1. 背景与目标

原有 import torch_npu 会间接加载 torch._dynamotorch._inductor 及大量子模块,增加导入耗时、内存占用和编译器初始化副作用。

本 PR 将图模式初始化从普通 import 阶段移出,同时保持公开接口的原有调用方式:

  • import torch_npu 不加载 torch._dynamotorch._inductortorch_npu._inductor
  • Dynamo、Inductor、TorchAir、NPUGraph 等能力在实际使用时初始化。
  • torch.compile 的非 Inductor backend 不加载完整 NPU Inductor。
  • Export、ONNX、FSDP、NPUGraph 等公开入口仍在使用前完成所需初始化。

2. 拆分 Dynamo 与 Inductor 初始化

  • _lazy_dynamo_setup() 负责 NPU DeviceInterface、Dynamo Variable/Stream/Event/autocast 补丁、trace rules 和 backend 注册。
  • _lazy_inductor_setup() 仅在 inductornpugraphs backend 使用时加载 torch_npu._inductor、NPU Inductor config 和 NPUGraph tree。
  • 初始化使用带并发保护的 run_once,成功步骤单独记录;后续步骤失败时,已成功步骤不重复执行,失败初始化允许重试。
  • torch.compile(options={"npu_backend": ...}) 在加载 NPU Inductor 前解析本次 options、全局 config 和环境变量,避免先按 default 初始化再切换 backend。

3. 使用统一 Dynamo post-import 触发器

不再包装 torch.compiletorch.export.exportexport_for_trainingtorch.onnx.export 等公开函数,避免改变公开函数对象、签名、装饰器语义,以及提前绑定接口绕过 wrapper。

import torch_npu 只安装 torch._dynamo post-import finder:

  • 首次导入 torch._dynamo 完成后,统一执行 _lazy_dynamo_setup()
  • 如果用户在 torch_npu 前已经导入 Dynamo,则在 import torch_npu 时补充 NPU 初始化。
  • finder 委托其余 sys.meta_path finder 查找真实模块,不绕过其他自定义导入器。
  • Export、ONNX Dynamo Export、compile 和提前绑定的公开入口都通过同一个 Dynamo 导入时机完成初始化。

torch.compiler.list_backends() 本身会导入 torch._dynamo,因此也会完成 NPU Dynamo 集成;该路径不会加载 NPU Inductor 或初始化 NPU 设备。三个 NPU backend 同时通过 torch_dynamo_backends entry point 暴露,首次 compile 前即可枚举:

  • npu
  • npugraph_ex
  • npugraphs

4. 公开接口和场景兼容处理

公开接口或场景 原始风险 当前处理
torch.compiler.list_backends() 首次 compile 前看不到 NPU backend 通过 entry point 保持三个 backend 可见;调用时初始化 Dynamo,但不加载 NPU Inductor
torch.compiler.npugraph_mark_step_begin() 首次 compile 前接口不存在,或调用时过度加载编译器 import 阶段暴露轻量无参接口;共享独立 step 状态,调用时不加载 Dynamo/Inductor
torch_npu.distributed.tensor import 阶段加载 DTensor experimental,继而传递导入 Dynamo/Inductor tensor 子模块改为首次显式访问时导入;显式使用时继续执行原有 strategy 注册实现,不复制或修改 PyTorch register_sharding
torch.export.export / export_for_training / export_for_inference NPU Stream、Event、autocast 等捕获支持未初始化;提前绑定可能绕过 wrapper 不包装公开函数,由统一 Dynamo post-import 触发;四种入口和绑定顺序均使用真实 NPU Export 验证
torch.onnx.export(..., dynamo=True) / torch.onnx.dynamo_export ONNX 路径可能绕过 Export wrapper 依赖统一 Dynamo post-import 触发;模块调用和两种提前绑定入口覆盖初始化链路
torch.compile(..., backend="eager"/custom/"npu") 无条件加载完整 NPU Inductor 只初始化 Dynamo,不加载 torch_npu._inductor
torch.compile(..., backend="inductor"/"npugraphs") NPU Inductor 尚未注册 backend lookup 前完成 Dynamo 初始化,确定为 Inductor 类 backend 后再加载 NPU Inductor
NPU DeviceInterface 延迟导入后可能报 No interface for device npu Dynamo 初始化时注册 npunpu:0~31,Stream 接口回归通过
FSDP patch import 阶段导入 FSDP 会间接加载 Dynamo 使用 FSDP post-import patch,覆盖 torch_npu 前后两种导入顺序
torch_npu.npu.npugraph_ex import torch_npu.npu 时提前加载图模式模块 使用模块 __getattr__ 按需导入,公开属性访问方式不变

5. DTensor 延迟导入与 NPUGraph step 状态拆分

  • 不在 torch_npu 中复制 PyTorch 的 register_sharding 实现,也不改动 NPU DTensor 算子文件。普通 import torch_npu 不再主动导入 torch_npu.distributed.tensor;用户显式访问该子模块时,沿用 v2.7.1 原有初始化和 strategy 注册路径。
  • MarkStepBoxmark_step_begin() 拆到轻量状态模块,公共 mark-step API 与完整 Graph Tree 共享计数状态,但不需要为一次标记加载完整编译器实现。

6. 保留非编译器 import-time 行为

  • 将不依赖 Inductor 的 RNG prim 和 decomposition patch 拆到 torch_npu/utils/_rng_prims_patch.py,普通 registry 继续执行这些基础 patch。
  • torch_npu.utils._inductor 保留兼容重导出,不再承担完整 NPU Inductor 初始化。
  • transfer_to_npu 在自身初始化入口显式导入实际需要修改的模块,不依赖 import torch_npu 的编译器隐式导入。

7. 测试看护

新增或扩展的测试覆盖:

  • 普通 import torch_npu 不加载 Dynamo/Inductor,并保持公开函数对象不变。
  • Dynamo 在 torch_npu 前后两种导入顺序。
  • backend lookup 前完成初始化,list_backends() 可见三个 NPU backend。
  • eager、自定义、npu、inductor、npugraphs backend 初始化边界。
  • Export 四种公开入口/提前绑定顺序及六类 NPU 捕获语义:record_stream、Stream/Event、autocast、current device、device properties、is_available。
  • ONNX 三种入口:模块 export、提前绑定 export、提前绑定旧 dynamo_export
  • FSDP 两种导入顺序。
  • NPUGraph mark-step 接口签名、计数及无 compiler import。
  • NPU DeviceInterface、初始化快照和既有 Stream/Event 捕获行为。

DTensor 的原有算子文件和 register_sharding 实现未修改,本 PR 不新增其实现副本或专项矩阵用例。

【资料变更】

不涉及。

【接口变更】

不涉及客户可见接口签名变更。torch.compile、Export/ONNX 公开函数不再被 torch_npu 包装;torch_npu.distributed.tensor 的公开访问方式不变,仅从 import 阶段加载调整为首次显式访问时加载。

【功能验证】

torch-npu-build-2.7.1-py311 环境使用真实 NPU 验证:

  • test/dynamo/test_compile_trigger.py 覆盖 import、Dynamo 触发、compile backend、Export、ONNX、FSDP、NPUGraph 和 DeviceInterface 路径。
  • test/test_torch_npu_init.py:13/13 通过。
  • test/npu/test_stream.py:10/10 通过。
  • test/dynamo/test_trace_stream_event.py:1/1 通过。
  • 显式访问 torch_npu.distributed.tensor 后,原有 NPU strategy 注册正常。
  • py_compilegit diff --check 通过。
  • 验证所需临时依赖和 Conda 文件均已恢复。

【CheckList】

likedislike
Pull Request已成功合入, 合并人@ascend-robot
(感谢 黄桂军 的贡献)
黄桂军黄桂军成员
21 天前 创建了 pull request,commit 60b03d20
黄桂军黄桂军成员
21 天前 关联了issue:【性能优化】import torch_npu 懒加载 dynamo/inductor
atomgit-bot
atomgit-bot
21 天前 评论:

变更摘要

此 PR 主要优化 import torch_npu 的加载性能,将 torch._dynamotorch._inductor 相关模块的初始化从 import 时延迟到首次 torch.compile 调用时触发。核心方式是通过补丁 _TorchCompileWrapper.__init__lookup_backend() 前执行一次性懒加载设置;同时将 import 阶段必需的 RNG prim 补丁和 _max_unpoolnd 补丁迁移到独立模块,并采用 post-import hook 模式延迟 FSDP 补丁和 Dynamo device interface 注册。

主要改动

  • 延迟 Dynamo/Inductor 初始化至首次 compile:在 torch_npu/utils/_dynamo.py 中新增 run_once 装饰器和 install_torch_compile_trigger 函数,通过替换 _TorchCompileWrapper.__init__,在每次 compile 前调用 _lazy_dynamo_setup() 一次性完成 Dynamo backend 注册、trace rules 注入、Inductor 导入及 npugraph tree 补丁
  • RNG prim 补丁独立化:将原来位于 torch_npu/utils/_inductor.py 中的 _max_unpoolnd_patchpatch_philox_rand_offsetpatch_register_philox_rand 等 RNG 补丁迁移至新建的 torch_npu/utils/_rng_prims_patch.py,由 registry_manager.py 新增的 _register_rng_prims() 在 import 时直接调用,不再经过 Dynamo 注册路径
  • FSDP 补丁改为按需触发torch_npu/_init/patches/distributed_patches.py 新增 _FSDPPostImportFinder/_FSDPPostImportLoader 类,当 torch.distributed.fsdp 首次被导入时才执行 _apply_fsdp_patches(),并在完成后从 sys.meta_path 移除探测器
  • Dynamo device interface 注册延迟:在 _dynamo.py 中新增 _DeviceInterfacePostImportFinder,当 torch._dynamo.device_interface 首次导入时自动调用 _dynamo_register_interface_for_device() 完成 NPU 设备接口注册
  • 移除 import 时的 forbid_in_graph 依赖torch_npu/npu/deterministic.py 不再从 torch._dynamo.decorators 导入 forbid_in_graph,改为使用本地实现的 _forbid_in_graph 函数,仅设置 _dynamo_forbidden = True 属性
likedislike
atomgit-bot
atomgit-bot
21 天前 评论:

代码审查

Now let me write the closing summary. I've reviewed all 15 files.


审查总结

按优先级统计

  • P0: 0
  • P1: 0
  • P2: 0
  • P3: 2

各文件审查确认

文件 结果
test/dynamo/test_compile_trigger.py 无问题
test/test_torch_npu_init.py 无问题
torch_npu/_inductor/utils.py 无问题
torch_npu/_init/patches/api_patches.py 无问题
torch_npu/_init/patches/distributed_patches.py P3 × 1_FSDPPostImportLoader finder 泄漏)
torch_npu/_init/patches/dynamo_patches.py 无问题
torch_npu/_init/registry/registry_manager.py 无问题
torch_npu/distributed/__init__.py 无问题
torch_npu/dynamo/__init__.py 无问题
torch_npu/npu/deterministic.py 无问题
torch_npu/npu/npugraph_ex/__init__.py 无问题
torch_npu/utils/__init__.py 无问题
torch_npu/utils/_dynamo.py P3 × 1_DeviceInterfacePostImportLoader finder 泄漏)
torch_npu/utils/_inductor.py 无问题
torch_npu/utils/_rng_prims_patch.py 无问题

整体风险评估

低风险。 此变更的核心设计(延迟 dynamo/inductor 加载到首次 torch.compile)实现正确且经过充分测试。run_once 并发控制、PEP 562 懒加载子模块、from __future__ import annotations 字符串化注解、以及 sys.meta_path post-import hook 等关键机制均使用得当。

两个 P3 发现均为同类模式:_FSDPPostImportLoader_DeviceInterfacePostImportLoader 在 post-import 回调抛异常时未清理 sys.meta_path 中的 finder。这属于防御性编程的改进建议,实际触发概率极低(仅在底层 patch 函数因环境异常而失败的场景下出现),且即使触发也不会导致系统崩溃——仅造成 finder 泄漏和对应 patch 未生效。建议在后续迭代中加固异常路径。

类型 数量
🔴 阻塞 0
🟡 建议 1

💬 仅评论

likedislike
此处折叠了518条消息 查看更多
renyujin成员
8 天前 评论:

/lgtm

likedislike
ascend-robotascend-robot成员
8 天前 添加了label:lgtm
ascend-robotascend-robot成员
8 天前 合入了pull request
ascend-robot
ascend-robot成员
8 天前 评论:

Pull Request 已合并或已关闭。

If you want to solve this problem, you can click here to do it in the FAQs.

likedislike
ascend-robot
ascend-robot成员
8 天前 评论:
流水线 pytorch_gitcode_PR_multiVersion#13915 [ commitID:ce0f0309 ] 已完成
likedislike