已开启
[Feature]: torch_npu 多版本兼容(COMPAT)贡献指南和检查工具 #4424
li_jing_hw创建于  21 天前
li_jing_hw成员
21 天前 创建

提交提案之前,请先检索仓库内是否已有相同的提案,如已有请在同一提案中进行讨论。

💻 需求背景、当前现状、期望实现的功能内容、具体的设计方案、以及测试方案

torch_npu 多版本兼容(COMPAT)贡献指南

本RFC涉及文档和工具。背景如下:

1. 背景与总体原则

torch_npu 用一个代码分支同时支持多个上游 PyTorch 版本(当前支持下限 2.13)。为了让业务代码不散落版本判断,所有版本差异都被隔离在统一的「兼容适配层」:

  • Python 侧torch_npu/_compat/ 下的包装函数,运行时读取 torch.__version__ 判断;
  • C++ 侧torch_npu/csrc/_compat/ 下的头文件与编译期宏,构建时读取 TORCH_VERSION_MAJOR / TORCH_VERSION_MINOR 判断。

核心原则:业务代码优先调用_compat层提供的统一接口/符号,不写版本判断。 版本差异只存在于 _compat 层内。

2. Python 侧方案

Python 兼容点都遵循「包装函数 + 运行时 if」模式:

  1. _compat 的某个模块里新增一个包装函数;
  2. 函数内部用 if CURRENT_VERSION >= (X, Y) 走新/旧 API;
  3. 业务代码只 from torch_npu._compat.xxx import 包装函数 并调用,不感知版本。

示例(utils.make_config_entry):

flowchart TD
    ROOT["业务代码调用<br/>make_config_entry(config, name='npu_backend')"]
    V["version.py<br/>CURRENT_VERSION = _parse(torch.__version__)"]
    D{"CURRENT_VERSION >= (2,12)?"}
    D -- "是" --> B1["_ConfigEntry(config, name=name)<br/>新签名"]
    D -- "否" --> B2["_ConfigEntry(config)<br/>旧签名,不传 name"]
    B1 --> UPNEW["上游 PyTorch >= 2.12<br/>_ConfigEntry.__init__ 带 name 参数"]
    B2 --> UPOLD["上游 PyTorch 2.10 / 2.11<br/>_ConfigEntry.__init__ 无 name 参数"]
    ROOT --> D
    V -. 提供版本号 .-> D

Python 侧标注规范(写在每个兼容块上方):

# COMPAT(>= 2.12): 上游 _ConfigEntry.__init__ 增加必填 name 参数
# CAN REMOVE when MIN_SUPPORTED >= (2, 12): 直接构造 _ConfigEntry(config, name=name)
def make_config_entry(config, *, name: str):
    from torch.utils._config_module import _ConfigEntry
    if CURRENT_VERSION >= (2, 12):
        return _ConfigEntry(config, name=name)
    return _ConfigEntry(config)  # 旧版本没有 name 参数

4. C++ 侧方案

C++ 兼容点遵循「头文件 + 编译期宏」模式:

  1. #include <torch_npu/csrc/_compat/version.h>
  2. _compat 头文件里用 #if TORCH_NPU_VERSION_GE(X, Y) 分出新旧实现

示例(autograd.hGradFnPtr,省略号表示中间有 make_grad_fn 等 helper):

flowchart TD
    ROOT["业务代码 include<br/>torch_npu/csrc/_compat/autograd.h"]
    V["version.h<br/>TORCH_NPU_VERSION_GE(MAJOR, MINOR)<br/>基于 &lt;torch/version.h&gt;"]
    D{"TORCH_NPU_VERSION_GE(2, 13)?"}
    D -- "1(是)" --> B1["GradFnPtr = c10::intrusive_ptr&lt;T&gt;<br/>make_grad_fn = c10::make_intrusive&lt;Op&gt;(...)"]
    D -- "0(否)" --> B2["GradFnPtr = std::shared_ptr&lt;T&gt;<br/>make_grad_fn = shared_ptr&lt;Op&gt;(new Op, deleteNode)"]
    B1 --> UPNEW["上游 PyTorch >= 2.13<br/>grad_fn 改 intrusive_ptr(上游 #181782)"]
    B2 --> UPOLD["上游 PyTorch <= 2.12<br/>grad_fn 用 shared_ptr + deleteNode"]
    ROOT --> D
    V -. 编译期提供宏 .-> D

C++ 侧标注规范:

// COMPAT(>= 2.13): grad_fn 从 shared_ptr 迁移到 c10::intrusive_ptr(上游 #181782)
// CAN REMOVE the version branches below when MIN_SUPPORTED >= (2, 13)
#if TORCH_NPU_VERSION_GE(2, 13)
template <typename T>
using GradFnPtr = c10::intrusive_ptr<T>;
#else
template <typename T>
using GradFnPtr = std::shared_ptr<T>;
#endif

5. 新增一个兼容点的流程

  1. 确认上游变化:明确改动发生在哪个版本 X.Y、影响哪些 API/符号;
  2. Python 侧:在 _compat 对应模块加包装函数(或改现有函数),内部 if CURRENT_VERSION >= (X, Y)
  3. C++ 侧:在 _compat 对应头文件加 #if TORCH_NPU_VERSION_GE(X, Y) 条件编译宏;
  4. 改业务代码:把不同版本的调用统一成对_compat层接口的单一调用;
  5. tools/check_compat.py,确保没有引入过期块。(本提交涉及的工具)
  6. 验证:在支持的多个上游版本(2.13+)分别构建/运行确认;

替代方案

补充说明

欢迎加入社区,感谢您对社区的贡献 🎉!

likedislike
Lli_jing_hw成员
21 天前 添加了label:feature
TorchNPU-BotTorchNPU-Bot成员
21 天前 添加了label:triage-review
TorchNPU-Bot
TorchNPU-Bot成员
21 天前 评论:

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

likedislike
Lli_jing_hw成员
21 天前 关联了pull request:Add tools to check version compatibility
TorchNPU-BotTorchNPU-Bot成员
21 天前 添加了label:bot-triaged;删除了label:triage-review
TorchNPU-Bot
TorchNPU-Bot成员
21 天前 评论:

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

likedislike