Pull Request已成功合入, 合并人@ascend-robot
(感谢 黄桂军 的贡献)变更摘要
本次 PR 将 v2.9.0_import 分支的 15 个 import 优化 commit 同步到 v2.12.0,核心目标是将 torch._dynamo 和 torch._inductor 的初始化从 import torch_npu 时延迟到首次 torch.compile 调用时。主要手段包括:引入 _DynamoPostImportFinder/_DynamoPostImportLoader 在 Dynamo 首次被导入时触发 NPU 集成;将 RNG prim patches 从 _inductor.py 提取到独立的 _rng_prims_patch.py 模块;重构 registry_manager.py 移除 import 时的 Dynamo/Inductor 注册;新增线程安全的 run_once 装饰器和 fork 安全的锁重置机制;以及通过 setup.py 的 torch_dynamo_backends entry_points 替换 import 时后端注册。
主要改动
-
延迟初始化架构:在
torch_npu/utils/_dynamo.py中新增_DynamoPostImportFinder和_DynamoPostImportLoader,当torch._dynamo首次被导入时自动调用_lazy_dynamo_setup()完成 NPU 集成;_setup_inductor_for_compile()在首次torch.compile时触发_lazy_inductor_setup(),将 Inductor 后端加载延迟到实际编译路径。 -
RNG patches 模块化分离:将
torch_npu/utils/_inductor.py中的patch_philox_rand_offset、patch_register_philox_rand、patch_register_run_and_save_rng_state_op等 RNG prim patches(约 220 行)提取到新增的torch_npu/utils/_rng_prims_patch.py,通过apply_rng_prims_patches()在 import 时统一调用,registry_manager.py的_register_rng_prims()替代了原来的_register_inductor()。 -
注册管理重构:
registry_manager.py移除_register_dynamo()和_register_inductor(),不再在import torch_npu时注册 Dynamo 后端、trace rules 和 Inductor device op overrides;Dynamo 后端注册移至dynamo/__init__.py的_register_backends()(带去重保护),Inductor 注册由_InductorNpuRegistry在首次编译时按需执行。 -
线程安全与 fork 安全:
run_once装饰器改为基于threading.Condition的实现,支持并发等待和 fork 后状态重置;_NpuBackendScope改为在__enter__/__exit__中使用_INDUCTOR_NPU_BACKEND_LOCK保护;_reset_compiler_locks_after_fork通过os.register_at_fork在 fork 后重置锁和run_once的Condition。 -
编译入口点与 entry_points:
setup.py新增torch_dynamo_backendsentry_points,声明npu、npugraph_ex、npugraphs三个后端入口;dynamo/__init__.py新增_npu_backend_entrypoint、_npugraph_ex_backend_entrypoint和_NpugraphsBackendEntryPoint类,每个入口在调用时先触发_lazy_dynamo_setup(),并处理与 setuptools entry point 的去重逻辑。


代码审查
审查总结
已完成对全部 8 个变更文件的逐文件审查:
| 文件 | 审查结果 |
|---|---|
setup.py |
无问题 — 新增 torch_dynamo_backends entry_points,引用的符号经验证存在 |
test/dynamo/test_compile_trigger.py |
无问题 — 新增 1440 行测试,覆盖 lazy import、fork 安全、并发安全、导出语义等场景 |
test/test_torch_npu_init.py |
无问题 — 从 EXPECTED_LOADED_MODULES 移除 torch_npu.utils._inductor,加入 EXPECTED_NOT_LOADED_MODULES,并移除对已失效 eager 注册的断言 |
torch_npu/_compat/utils.py |
1 个 P3 问题 — 版本兼容注释中的版本号引用不准确 |
torch_npu/_inductor/utils.py |
无问题 — compile_fx 显式导入确保模块在 patch_has_triton 调用前已加载 |
torch_npu/_init/patches/dynamo_patches.py |
无问题 — 移除的 apply_npugraph_tree_patch 已迁移至 lazy Inductor 初始化路径 |
torch_npu/_init/registry/registry_manager.py |
无问题 — _register_dynamo/_register_inductor 替换为 _register_rng_prims,Dynamo/Inductor 注册推迟至首次 torch.compile |
torch_npu/contrib/transfer_to_npu.py |
无问题 — 显式导入 Dynamo/Inductor 模块替代 torch_npu 的副作用导入,filesystem 引用方式变更语义等价 |
发现统计:P0: 0,P1: 0,P2: 0,P3: 1
总体风险评估:低风险。该 PR 将 Dynamo/Inductor 初始化推迟到首次 torch.compile 调用,变更逻辑清晰,配套测试覆盖全面(lazy import 语义、fork 安全、并发安全、后端注册、入口点加载等),唯一发现为注释措辞不准确,不影响运行时行为。
审查总结
逐文件审查结果
| 文件 | 审查结论 |
|---|---|
torch_npu/distributed/__init__.py |
无新增问题:__getattr__/__dir__ 延迟加载模式正确 |
torch_npu/distributed/fsdp/__init__.py |
无新增问题:import torch.distributed.fsdp 确保补丁依赖可用 |
torch_npu/distributed/tensor/__init__.py |
无新增问题:导入重排 + experimental 延迟加载正确 |
torch_npu/distributed/tensor/_dtensor_patch.py |
发现 2 个问题(见下) |
torch_npu/dynamo/__init__.py |
无新增问题:延迟注册 / entrypoint 架构合理(_allowed_list 限制为已有问题) |
torch_npu/npu/_graph_tree.py |
无新增问题:MarkStepBox/mark_step_begin 移动到轻量模块,导入链保持完整 |
torch_npu/npu/_graph_tree_state.py |
无新增问题:新模块定义与原定义一致 |
torch_npu/npu/deterministic.py |
无新增问题:本地 _forbid_in_graph 与原始实现功能等价 |
发现的问题
| 优先级 | 数量 |
|---|---|
| P1 | 1 |
| P3 | 1 |
总体风险判断
中风险。P1 问题(字符串版本号比较)会导致 DTensor 补丁在 PyTorch 2.1~2.9 全系列上静默不生效,可能造成 DTensor 算子分片策略不完整。建议在合入前修复该版本比较逻辑。其余变更结构合理,延迟加载架构设计正确。
现在我已完成对所有 6 个文件的审查,以下是我的最终报告。
审查摘要
| 优先级 | 数量 | 文件位置 |
|---|---|---|
| P3 | 3 | utils/__init__.py、_graph_tree.py、_dynamo.py |
| P0–P2 | 0 | — |
各文件审查结果:
-
torch_npu/npu/npugraph_ex/__init__.py— 无问题。将fwd_only从模块级导入改为register_replacement内的延迟导入,模式正确。TYPE_CHECKING守卫与from __future__ import annotations配合使用以进行仅用于类型检查的导入,是正确的惰性加载设计。 -
torch_npu/utils/__init__.py— 1 个 P3 发现问题:第 14 行的死导入_max_unpoolnd_patch。该函数被导入但从未在此文件中使用;实际的补丁应用通过registry_manager.py中的apply_rng_prims_patches()进行。 -
torch_npu/utils/_dynamo.py— 1 个 P3 发现问题:_normalize_compile_options(第 174-189 行)在将连字符替换为下划线后,如果输入字典同时包含"npu-backend"和"npu_backend",会静默丢弃重复的键。其余大规模重构(run_once装饰器配合Condition、_NpuBackendScope配合RLock锁管理、_DynamoPostImportFinder/Loader惰性触发、fork 安全的锁重置)设计合理,无正确性或死锁问题。 -
torch_npu/utils/_graph_tree.py— 1 个 P3 发现问题:第 362-368 行,npugraphs将**compile_kwargs传递给aot_npugraphs(aot_autograd的返回值),后者不接受额外的关键字参数。目前,由于 Dynamo 的后端分发机制不传递额外的 kwargs,因此compile_kwargs始终为空,问题尚未触发,但这是一个潜在的 bug。 -
torch_npu/utils/_inductor.py— 无问题。RNG 补丁已提取到_rng_prims_patch.py;剩余的DeviceOpOverrides代码未发生变化。 -
torch_npu/utils/_rng_prims_patch.py— 无问题。新文件正确地将 RNG 补丁从旧的_inductor.py提取并封装到apply_rng_prims_patches()中,并附带一个额外的patch_max_unpoolnd()。aten = torch.ops.aten模块级赋值供新的_max_unpoolnd_patch函数使用。当run_and_save_rng_state/run_with_rng_state不可用时的潜在崩溃问题在移动前即已存在,并非由本次 diff 引入。
总体风险判断: 低风险。本次 diff 是一个结构良好的惰性初始化重构。未发现任何 P0–P2 级别的正确性或安全性问题。3 个 P3 发现均为次要问题:两个是死代码/脆性代码(死导入、潜在的未来 kwargs 冲突),一个是输入验证的边界情况(键冲突静默丢弃)。核心惰性加载架构——run_once 配合条件变量、RLock 保护的注册表、sys.meta_path 钩子以及 fork 安全重置——设计正确且线程安全。
| 类型 | 数量 |
|---|---|
| 🔴 阻塞 | 2 |
| 🟡 建议 | 1 |
⛔ 需要修改


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




同步 v2.9.0_import 分支的 15 个 import optimization commits 到 v2.12.0,将 Dynamo 和 Inductor 初始化延迟到首次 torch.compile 调用。详见 v2.12.0_syn.md 逐文件分类和冲突解决记录。
【合入来源】
【修改方案】
同步 v2.9.0_import 的 lazy import optimization(15 commits)到 v2.12.0。将 Dynamo/Inductor 初始化从 import 时延迟到首次 torch.compile。主要改动包括:
PyTorch 2.12 适配: EventVariable 在 streams, _ConfigEntry 需要 name, _TorchCompileInductorWrapper.init 有 name=None
【资料变更】
不涉及
【接口变更】
不涉及
【功能验证】
conda torch-npu-build-2.12.0-py311 验证:
【CheckList】