Pull Request已成功合入, 合并人@ascend-robot
(感谢 黄桂军 的贡献)变更摘要
此 PR 主要优化 import torch_npu 的加载性能,将 torch._dynamo 和 torch._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_patch、patch_philox_rand_offset、patch_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属性


代码审查
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 |
💬 仅评论


Pull Request 已合并或已关闭。
If you want to solve this problem, you can click here to do it in the FAQs.




【合入来源】
【修改方案】
1. 背景与目标
原有
import torch_npu会间接加载torch._dynamo、torch._inductor及大量子模块,增加导入耗时、内存占用和编译器初始化副作用。本 PR 将图模式初始化从普通 import 阶段移出,同时保持公开接口的原有调用方式:
import torch_npu不加载torch._dynamo、torch._inductor、torch_npu._inductor。torch.compile的非 Inductor backend 不加载完整 NPU Inductor。2. 拆分 Dynamo 与 Inductor 初始化
_lazy_dynamo_setup()负责 NPU DeviceInterface、Dynamo Variable/Stream/Event/autocast 补丁、trace rules 和 backend 注册。_lazy_inductor_setup()仅在inductor、npugraphsbackend 使用时加载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.compile、torch.export.export、export_for_training、torch.onnx.export等公开函数,避免改变公开函数对象、签名、装饰器语义,以及提前绑定接口绕过 wrapper。import torch_npu只安装torch._dynamopost-import finder:torch._dynamo完成后,统一执行_lazy_dynamo_setup()。torch_npu前已经导入 Dynamo,则在import torch_npu时补充 NPU 初始化。sys.meta_pathfinder 查找真实模块,不绕过其他自定义导入器。torch.compiler.list_backends()本身会导入torch._dynamo,因此也会完成 NPU Dynamo 集成;该路径不会加载 NPU Inductor 或初始化 NPU 设备。三个 NPU backend 同时通过torch_dynamo_backendsentry point 暴露,首次 compile 前即可枚举:npunpugraph_exnpugraphs4. 公开接口和场景兼容处理
torch.compiler.list_backends()torch.compiler.npugraph_mark_step_begin()torch_npu.distributed.tensortensor子模块改为首次显式访问时导入;显式使用时继续执行原有 strategy 注册实现,不复制或修改 PyTorchregister_shardingtorch.export.export/export_for_training/export_for_inferencetorch.onnx.export(..., dynamo=True)/torch.onnx.dynamo_exporttorch.compile(..., backend="eager"/custom/"npu")torch_npu._inductortorch.compile(..., backend="inductor"/"npugraphs")No interface for device npunpu和npu:0~31,Stream 接口回归通过torch_npu.npu.npugraph_extorch_npu.npu时提前加载图模式模块__getattr__按需导入,公开属性访问方式不变5. DTensor 延迟导入与 NPUGraph step 状态拆分
register_sharding实现,也不改动 NPU DTensor 算子文件。普通import torch_npu不再主动导入torch_npu.distributed.tensor;用户显式访问该子模块时,沿用 v2.7.1 原有初始化和 strategy 注册路径。MarkStepBox和mark_step_begin()拆到轻量状态模块,公共 mark-step API 与完整 Graph Tree 共享计数状态,但不需要为一次标记加载完整编译器实现。6. 保留非编译器 import-time 行为
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,并保持公开函数对象不变。list_backends()可见三个 NPU backend。export、提前绑定export、提前绑定旧dynamo_export。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_compile、git diff --check通过。【CheckList】