文件最后提交记录最后更新时间
Checkout v2r13 Co-authored-by: Chansinging<1183520536@qq.com> Co-authored-by: chansinging<chenxingying2@huawei.com> # message auto-generated for no-merge-commit merge: !4923 merge main_sync_20260511 into master Checkout v2r13 Created-by: chansinging Commit-by: Chansinging;chansinging Merged-by: ascend-robot Description: <!-- PR描述模板更新日期:20260203 --> # 【合入来源】 参考社区演进和以往PR记录 - [ ] 需求 - [ ] 问题单 - [x] issue/工单[社区演进](https://gitcode.com/Ascend/op-plugin/issues/77) - [ ] 重构优化 - [ ] 资料更新 # 【修改方案】 参考社区演进和以往PR记录 # 【资料变更】 不涉及 # 【接口变更】 不涉及 # 【功能验证】 ![image.png](https://raw.gitcode.com/user-images/assets/7403085/f9dd5824-f779-4cf3-b3ae-7547de2625e8/image.png 'image.png') # 【CheckList】 > PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] - [x] 代码注释完备,正确记录错误日志 - [x] 代码实现进行了返回值、空指针等校验 - [x] PR标题正确使用类型标签,如:feat、fix、refactor、docs、test等 - [x] PR持续集成流水线(CI)执行通过,代码检查无异常 See merge request: Ascend/op-plugin!492322 天前
!1713 fix ops * fix ops 1 年前
Generate ATB public C++ interface wrappers from dispatcher schema registrations. Co-authored-by: wang_ziqi<wangziqi4@huawei.com> # message auto-generated for no-merge-commit merge: !4825 merge atb-cpp-api-interface into master Generate ATB public C++ interface wrappers from dispatcher schema registrations. Created-by: wang-ziqi-code Commit-by: wang_ziqi Merged-by: ascend-robot Description: <!-- PR描述模板更新日期:2026-04-25 --> # 【合入来源】> <font color="red">**如有社区 issue,请关联 issue 链接**</font>\ > <font color="red">**请勿携带内部流程信息(需求链接、问题单、内部 issue 等)**</font> - [ ] 需求 - [ ] 问题单 - [x] issue/工单 https://gitcode.com/Ascend/op-plugin/issues/69 - [ ] 重构优化 - [ ] 资料更新 # 【修改方案】 本次补充 ATB C++ 公共接口暴露机制,并同步收敛配置和生成器口径。 当前 ATB 算子原本主要通过 TORCH_LIBRARY_FRAGMENT(atb, m) / m.impl(...) 注册到 dispatcher,再由 Python 侧通过 torch.ops.atb 使用;本次在此基础上新增 at_npu::native::atb 命名空间下的 C++ public interface,用于 torch_npu 同构环境中的 C++ 调用方直接访问。 整体链路如下: ```text ::atb::implementation -> TORCH_LIBRARY_FRAGMENT(atb, m).def(...) / m.impl(...) -> torch.ops.atb (Python dispatcher entry) #python层接口 -> atb_ops.yaml + gen_atb_ops.py -> at_npu::native::atb::* (public C++ interface) #cpp层接口 ``` 具体修改如下: 1. **新增并收敛 ATB C++ 接口生成器 torchnpugen/gen_atb_ops.py** - 以 ::atb::* 实现函数签名作为 public C++ interface 的真值来源; - 以 m.def(...) / m.impl(...) 作为注册约束校验; - 读取 op_plugin/config/atb_ops.yaml 中的 cpp_name -> impl_name 映射,生成: - op_plugin/include/AtbOpsInterface.h - op_plugin/ops/atb/AtbOpsInterface.cpp - 生成器会校验: - 对应 ::atb::* 实现签名可从 op_plugin/ops/atb/*.cpp 中唯一解析。 2. **新增配置文件 op_plugin/config/atb_ops.yaml** - 维护 public C++ interface 与 ::atb::* 实现之间的映射; - 当前共覆盖 34 个 ATB 接口; - 配置写法为: ```yaml - cpp_name: "at_npu::native::atb::_npu_reshape_and_cache" impl_name: "atb::_npu_reshape_and_cache" ``` - 生成器内部会解析并校验 cpp_name: - 必须以 at_npu::native::atb:: 开头; - 必须能提取出合法的末尾函数名; 3. **新增模板文件 torchnpugen/templates/AtbOpsInterface.hAtbOpsInterface.cpp** - 通过 string.Template 渲染 public declaration、forward declaration 和 wrapper definition; - 生成的 wrapper 统一位于 namespace at_npu::native::atb 下; - wrapper 最终按参数原样转发到对应 ::atb::* 实现。 4. **新增统一 include 入口 op_plugin/include/atb_ops.h** - 作为 C++ 使用方的统一头文件入口; - 当前仅包含 AtbOpsInterface.h。 5. **集成到代码生成流程** - 在现有代码生成链路中加入 gen_atb_ops.py; - 保证构建过程中自动生成最新接口文件。 ### 生成产物示例 以 _npu_group_topk 为例,生成结果如下: **AtbOpsInterface.h** ```cpp namespace at_npu { namespace native { namespace atb { TORCH_NPU_API void _npu_group_topk(const at::Tensor &self, int64_t k, int64_t group_num, int64_t n); } // namespace atb } // namespace native } // namespace at_npu ``` **AtbOpsInterface.cpp** ```cpp namespace atb { void _npu_group_topk(const at::Tensor &self, int64_t k, int64_t group_num, int64_t n); } // namespace atb namespace at_npu { namespace native { namespace atb { void _npu_group_topk(const at::Tensor &self, int64_t k, int64_t group_num, int64_t n) { ::atb::_npu_group_topk(self, k, group_num, n); } } // namespace atb } // namespace native } // namespace at_npu ``` # 【资料变更】 不涉及 # 【接口变更】 涉及 C++ public interface 新增。 新增 AtbOpsInterface.h,在 at_npu::native::atb 命名空间下暴露 34 个 ATB public C++ API;接口签名与对应 ::atb::* 实现保持一致。C++ 调用方通过: ```cpp #include "atb_ops.h" ``` 即可访问对应接口,链接目标为 libop_plugin_atb.so。 - 在 torch_npu 同构运行环境中,at_npu::native::atb::* 作为额外 C++ ABI 可用; - 接口签名与 ::atb::* 实现保持一致; - public 符号边界位于 libop_plugin_atb.so。 # 【功能验证】 1. **生成回归** - 执行 python -m torchnpugen.gen_atb_ops --config op_plugin/config/atb_ops.yaml --header op_plugin/include/AtbOpsInterface.h --source op_plugin/ops/atb/AtbOpsInterface.cpp --atb-src-dir op_plugin/ops/atb - 连续执行两次,确认生成结果稳定、无无关 diff。 2. **源码契约检查** - 执行 python test/check_atb_cpp_api_contract.py --check-source - 校验: - cpp_name -> impl_name -> m.impl -> m.def 映射成立; - wrapper 声明与 ::atb::* 实现签名一致; - wrapper 参数透传顺序一致。 3. **配置校验** - atb_ops.yamlcpp_name 采用全限定写法; - 非法 cpp_name(缺前缀、缺函数名)会在生成器配置解析阶段直接报错。 4. **编译链接验证** - op-plugin 全量编译通过; - at_npu::native::atb::* public 符号由 libop_plugin_atb.so 承载。 # 【CheckList】 > PR 提交人对以下 CheckList 自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] - [x] 代码注释完备,正确记录错误日志 - [x] 代码实现进行了返回值、空指针等校验 - [x] PR 标题正确使用类型标签,如:feat、fix、refactor、docs、test 等 - [x] PR 持续集成流水线(CI)执行通过,代码检查无异常 See merge request: Ascend/op-plugin!482515 天前
Add warn for pre-deprecated interfaces Co-authored-by: SCh_zx<1325467101@qq.com> # message auto-generated for no-merge-commit merge: !4695 merge master into master Add warn for pre-deprecated interfaces Created-by: SCh_zx Commit-by: SCh_zx Merged-by: ascend-robot Description: <!-- PR描述模板更新日期:20260203 --> # 【合入来源】 > <font color="red">**如有社区issue,请关联issue链接**</font>\ > <font color="red">**请勿携带内部流程信息(需求链接、问题单、内部issue等)**</font> - [ ] 需求 - [ ] 问题单 - [ ] issue/工单 - [ ] 重构优化 - [ ] 资料更新 # 【修改方案】 > 请描述修改内容的具体实现,涉及哪些组件之间进行交互,可以用1、2、3、...进行罗列\ > 如果是需求或者重构类的PR,需要补充详细设计文档(说明上下游组件关系、时序图、类图、DFX能力等内容) 为预废弃接口添加废弃告警 ![5CD6F849-C791-41F9-AF0A-578A99FB1C0B.png](https://raw.gitcode.com/user-images/assets/7403085/830d6653-2dc8-47df-9452-d059a2be2149/5CD6F849-C791-41F9-AF0A-578A99FB1C0B.png '5CD6F849-C791-41F9-AF0A-578A99FB1C0B.png') # 【资料变更】 > 请确认是否涉及资料变更。如涉及,需要在PR中体现,并简要说明修改内容。如不涉及,需填写“不涉及” # 【接口变更】 > 请确认是否涉及跨代码仓或者客户面可见的接口变更。如涉及,需要详细说明接口以及对应的变更内容,同时需要在资料中体现。如不涉及,需填写“不涉及” # 【功能验证】 > 说明测试场景,测试方法。如果本次测试方式与常规单元测试不同,请详细说明您的测试步骤\ > 新增/变更内容是否已新增/适配UT测试用例看护,并补充测试自验证截图 # 【CheckList】 > PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] - [ ] 代码注释完备,正确记录错误日志 - [ ] 代码实现进行了返回值、空指针等校验 - [ ] PR标题正确使用类型标签,如:feat、fix、refactor、docs、test等 - [ ] PR持续集成流水线(CI)执行通过,代码检查无异常 See merge request: Ascend/op-plugin!46951 个月前
[feat] add npu_moe_gating_top_k_backward Co-authored-by: licheng261<licheng261@huawei.com> # message auto-generated for no-merge-commit merge: !5012 merge moe_gating_top_k_backward into master [feat] add npu_moe_gating_top_k_backward Created-by: licheng261 Commit-by: licheng261 Merged-by: ascend-robot Description: <!-- PR描述模板更新日期:20260203 --> # 【合入来源】 > <font color="red">**如有社区issue,请关联issue链接**</font>\ > <font color="red">**请勿携带内部流程信息(需求链接、问题单、内部issue等)**</font> - [x] 需求 [#110](https://gitcode.com/Ascend/op-plugin/issues/110) - [ ] 问题单 - [ ] issue/工单 - [ ] 重构优化 - [ ] 资料更新 # 【修改方案】 > 请描述修改内容的具体实现,涉及哪些组件之间进行交互,可以用1、2、3、...进行罗列\ > 如果是需求或者重构类的PR,需要补充详细设计文档(说明上下游组件关系、时序图、类图、DFX能力等内容) 新增npu_moe_gating_top_k算子的反向算子npu_moe_gating_top_k_backward # 【资料变更】 > 请确认是否涉及资料变更。如涉及,需要在PR中体现,并简要说明修改内容。如不涉及,需填写“不涉及” 新增算子资料 # 【接口变更】 > 请确认是否涉及跨代码仓或者客户面可见的接口变更。如涉及,需要详细说明接口以及对应的变更内容,同时需要在资料中体现。如不涉及,需填写“不涉及” 新增接口 # 【功能验证】 > 说明测试场景,测试方法。如果本次测试方式与常规单元测试不同,请详细说明您的测试步骤\ > 新增/变更内容是否已新增/适配UT测试用例看护,并补充测试自验证截图 ![image.png](https://raw.gitcode.com/user-images/assets/7403085/eaacafbc-59bb-41e1-bedc-d15ccf556f86/image.png 'image.png') # 【CheckList】 > PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] - [x] 代码注释完备,正确记录错误日志 - [x] 代码实现进行了返回值、空指针等校验 - [x] PR标题正确使用类型标签,如:feat、fix、refactor、docs、test等 - [x] PR持续集成流水线(CI)执行通过,代码检查无异常 See merge request: Ascend/op-plugin!50126 天前
[feat]新增swiglu_backward_mx_quant_with_dual_axis接口 Co-authored-by: ZhangW<zhangwei1176@huawei.com> # message auto-generated for no-merge-commit merge: !4927 merge swiglu_backward into master [feat]新增swiglu_backward_mx_quant_with_dual_axis接口 Created-by: ZhangWei1176 Commit-by: ZhangW Merged-by: ascend-robot Description: <!-- PR描述模板更新日期:20260203 --> # 【合入来源】 > <font color="red">**如有社区issue,请关联issue链接**</font>\ > <font color="red">**请勿携带内部流程信息(需求链接、问题单、内部issue等)**</font> - [x] 需求https://gitcode.com/Ascend/op-plugin/issues/128 - [ ] 问题单 - [ ] issue/工单 - [ ] 重构优化 - [ ] 资料更新 # 【修改方案】 > 请描述修改内容的具体实现,涉及哪些组件之间进行交互,可以用1、2、3、...进行罗列\ > 如果是需求或者重构类的PR,需要补充详细设计文档(说明上下游组件关系、时序图、类图、DFX能力等内容) 本次PR新增了一个名为 _npu_swiglu_backward_mx_quant_with_dual_axis 的自定义算子。该算子支持在双轴(dual axis)模式下进行混合精度量化,旨在为深度学习模型推理提供更灵活、高效的量化选项,以优化计算性能和内存使用。 首先,在YAML配置文件中注册了该算子的接口定义。其次,在C++层实现了算子的核心API,包括输入校验、输出张量形状计算、内存分配,并最终调用底层硬件加速内核执行计算。同时,在JSON配置文件中更新了算子API模式测试的schema。最后,新增了对应的Python单元测试,用于验证算子在特定数据类型(如float8_e4m3fn)的功能正确性。整个方案覆盖了算子生命周期的配置、实现与验证环节。 # 【资料变更】 > 请确认是否涉及资料变更。如涉及,需要在PR中体现,并简要说明修改内容。如不涉及,需填写“不涉及” 不涉及 # 【接口变更】 > 请确认是否涉及跨代码仓或者客户面可见的接口变更。如涉及,需要详细说明接口以及对应的变更内容,同时需要在资料中体现。如不涉及,需填写“不涉及” 不涉及 # 【功能验证】 > 说明测试场景,测试方法。如果本次测试方式与常规单元测试不同,请详细说明您的测试步骤\ > 新增/变更内容是否已新增/适配UT测试用例看护,并补充测试自验证截图 ut通过截图: ![image.png](https://raw.gitcode.com/user-images/assets/7403085/a8eefc7f-3e4f-487f-92da-5318bd7b9571/image.png 'image.png') # 【CheckList】 > PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] - [x] 代码注释完备,正确记录错误日志 - [x] 代码实现进行了返回值、空指针等校验 - [x] PR标题正确使用类型标签,如:feat、fix、refactor、docs、test等 - [x] PR持续集成流水线(CI)执行通过,代码检查无异常 See merge request: Ascend/op-plugin!492718 小时前
README.md

API适配开发流程

适配文件结构

├── op_plugin
│   ├── config  # 算子配置文件目录
│   │   ├── deprecated.yaml # 生成废弃接口告警配置文件
│   │   ├── derivatives.yaml # 算子前反向绑定配置文件
│   │   └── op_plugin_functions.yaml # 算子对外接口配置文件
│   ├── ops # 算子适配文件目录
│   │   ├── aclops # aclop算子适配目录
│   │   │   ├── AbsKernelNpu.cpp
│   │   │   └── ...
│   │   └── opapi # aclnn算子适配目录
│   │       ├── sparse # sparse相关算子适配目录
│   │       │   └── SparseTensorUtils.h
│   │       ├── AbsKernelNpuOpApi.cpp
│   │       └── ...
│   └── ...
└──...

NPU适配算子开发

算子Yaml配置

算子的aten ir定义位于op_plugin/config/op_plugin_functions.yaml文件中,所有版本的定义都在这个文件里面,通过配置不同版本来区分。

# op_plugin_functions.yaml
all_version: [v1.11, v2.0, v2.1, v2.2, v2.3, v2.4, v2.5, v2.6, v2.7, v2.8, v2.9, v2.10, v2.11, v2.12, v2.13]
# 官方算子
official:
  - func: abs(Tensor self) -> Tensor
    acl_op: all_version
    op_api: v1.11, v2.1, v2.2, v2.3, v2.4, v2.5, v2.6, v2.7, v2.8, v2.9, v2.10, v2.11, v2.12, v2.13
    gen_opapi:
      structured_inherit: abs.out
# 自定义算子
custom:
  - func: my_abs(Tensor self) -> Tensor
    acl_op: v1.11, v2.1, v2.2, v2.3, v2.4, v2.5, v2.6, v2.7, v2.8, v2.9, v2.10, v2.11, v2.12, v2.13
    op_api: all_version
symint:
  - func: zeros(SymInt[] size, *, ScalarType? dtype=None, Layout? layout=None, Device? device=None, bool? pin_memory=None) -> Tensor
    acl_op: [v2.1, newest]

其中:

  • all_version表示当前pytorch支持的所有版本
  • officialcustom分别表示该字段下的算子为原生和自定义算子;symint字段表明该算子支持symint类型的入参,该种算子后面详细介绍。
  • func定义了算子的schema,主要有名称、入参和返回参数,具体规则可参考原生定义。
  • acl_op字段后面填版本名称,表示在该版本支持acl_op调用。如果支持的版本与all_version表示的版本一致,则可以用"all_version"表示;也可以用一个左闭右闭的区间表示,如acl_op: [v2.1, newest]或者acl_op: [v2.1, v2.4]newest表示最新版本,具体可查看all_version。可选字段。
  • op_api字段后面填版本名称,表示在该版本支持op_api调用。使用方式参考acl_op字段。可选字段。
  • gen_opapi对于支持op_api调用的算子,如果适配代码简单,可以直接调用底层算子,不需要额外的适配,则可以考虑用结构化适配的方式自动生成适配代码,详见章节结构化适配介绍

如果存在某个Aten IR有两个版本不一致,则需要两个都加上,如std.correction在1.11和2.1及以上的入参名称不同,则需要分开写成两个,通过version区分。

  - func: std.correction(Tensor self, int[1]? dim, *, int? correction, bool keepdim=False) -> Tensor
    acl_op: v1.11
    op_api: v1.11

  - func: std.correction(Tensor self, int[1]? dim=None, *, Scalar? correction=None, bool keepdim=False) -> Tensor
    acl_op: [v2.1, newest]
    op_api: [v2.1, newest]

适配代码实现

当前支持适配ACLOP算子和ACLNN算子两类算子,ACLOP算子适配文件位于op_plugin/ops/aclopsACLNN算子适配文件位于op_plugin/ops/opapi目录。一个算子所有版本的适配代码都在一个文件中,通过编译宏VERSION_BETWEEN来区分不同版本。

ACLOP算子适配

如果所有版本的适配代码一致,则不需要额外添加编译宏,适配文件路径为:op_plugin/ops/aclops/AbsKernelNpu.cpp,文件命名规范为算子名称+KernelNpu,算子名称首字母大写。

// 算子适配实现文件路径 op_plugin/ops/aclops/AbsKernelNpu.cpp
// 1. 引入依赖头文件
// 对外接口头文件,包含op_plugin所有aclop算子对外的函数原型
#include "op_plugin/AclOpsInterface.h"
// torch调用ACLOP算子时,所依赖的基础函数对应的头文件
#include "op_plugin/utils/OpAdapter.h"

// 2. 算子接口适配实现
// opplugin内适配的算子对外接口都定义在op_plugin命名空间中,外部调用方式为op_plugin::abs、op_plugin::abs_out;内部不同类型的算子适配采用不同的命名空间
// CANN算子定义在acl_op命名空间中,
namespace acl_op {
using npu_preparation = at_npu::native::OpPreparation;
using npu_utils = at_npu::native::NpuUtils;
// 不对外暴露的接口,都定义在匿名空间中。常见为xx_nocheck等,直调ACLOP算子,不做内存、shape校验的函数。
namespace{
at::Tensor& abs_out_nocheck(at::Tensor& result, const at::Tensor& self) {
    at_npu::native::OpCommand cmd;
    cmd.Name("Abs")
       .Input(self)
       .Output(result)
       .Run();
    return result;
}
} // namespace

// abs_out api实现函数,参数与torch api一致。
at::Tensor& abs_out(const at::Tensor& self, at::Tensor& result) {
    // CheckOut作用:校验result的size、dtype等是否符合预期。若dtype不符合预期,则抛错。若size不符合则进行resize操作
    npu_preparation::CheckOut({self}, result, self);
    // check_match作用:校验result是否为连续。因ACLOP算子无法支持非连续输出,result非连续时,需要单独处理。
    if (!npu_utils::check_match(&result)) {
      // 若result非连续,创建连续tensor(contig_tensor),接收ACLOP算子(abs)的输出。再将contig_tensor拷贝到原始输出result。
      at::Tensor contiguous_result = npu_utils::format_contiguous(result);
      abs_out_nocheck(contigTensor, self);
      npu_utils::format_fresh_view(result, contiguous_result);
    } else {
     // 若result连续,直接调用ACLOP算子。
      abs_out_nocheck(result, self);
  }
    return result;
}

// abs api实现函数,参数与torch api一致。
at::Tensor abs(const at::Tensor& self) {
    // 构造输出tensor,调用ACLOP算子。
    auto output_size = op_infer::infershape_for_elewise(self);
    at::Tensor result = npu_preparation::apply_tensor(self, output_size);
    abs_out_nocheck(result, self);
    return result;
}

// abs_ api实现函数,参数与torch api一致。该接口为inplace操作,即输出结果存放在输入tensor中。
at::Tensor& abs_(at::Tensor& self) {
    // 调用out接口,避免因self作为输出时,非连续场景下,直调ACLOP算子结果出错。
    acl_op::abs_out(self, self);
    return self;
}
} // namespace acl_op

不同版本间适配代码有差异的,所有代码均放在同一个文件中,用编译宏来区分

#include "op_plugin/AclOpsInterface.h"
#include "op_plugin/utils/custom_functions/aclops/inner_compute.h"

namespace acl_op {
// 1.11的函数入参和2.0及以上版本有区别,因此用宏来控制
#if VERSION_BETWEEN(V1R11, V1R11)
at::Tensor embedding(
    const at::Tensor& weight,
    const at::Tensor& indices,
    int64_t padding_idx,
    bool scale_grad_by_freq,
    bool sparse) {
    return embedding_common_nocheck(weight, indices);
}
#endif
// 2.0及以上版本的代码都一致
#if VERSION_BETWEEN(V2R0, VERSION_NEWEST)
at::Tensor embedding_symint(
    const at::Tensor& weight,
    const at::Tensor& indices,
    c10::SymInt padding_idx,
    bool scale_grad_by_freq,
    bool sparse) {
    return embedding_common_nocheck(weight, indices);
}
#endif

} // namespace acl_op

ACLNN算子适配

ACLNN算子适配与ACLOP类似,也是如果所有版本的适配代码一致,则不需要额外添加编译宏,适配文件路径为:op_plugin/ops/opapi/AbsKernelNpuOpApi.cpp,文件命名规范为算子名称+KernelNpuOpApi,算子名称首字母大写。

//算子适配实现路径/op_plugin/ops/base_ops/opapi/AbsKernelNpuOpApi.cpp
// 1. 引入依赖头文件
// 对外接口头文件,包含op_plugin所有ACLNN算子对外的函数原型
#include "op_plugin/OpApiInterface.h"
// 引用 ACLOP 算子声明头文件
#include "op_plugin/AclOpsInterface.h"
// torch调用ACLNN算子时,所依赖的基础函数对应的头文件
#include "op_plugin/utils/op_api_common.h"

// 2. 算子接口适配实现
// ACLNN算子定义在op_api命名空间中,
namespace op_api {
using npu_preparation = at_npu::native::OpPreparation;

// abs_out api实现函数,参数与torch api一致。
at::Tensor& abs_out(const at::Tensor& self, at::Tensor& result) {
    // 查找ACLNN算子实现,查找失败则使用ACLOP算子实现
    DO_COMPATIBILITY(aclnnAbs, acl_op::abs_out(self, result));
    npu_preparation::check_tensor({self}, result, self);
    // 异步调用npu执行
    EXEC_NPU_CMD(aclnnAbs, self, result);
    return result;
}

// abs api实现函数,参数与torch api一致。
at::Tensor abs(const at::Tensor& self) {
    DO_COMPATIBILITY(aclnnAbs, acl_op::abs(self));

    // construct the output tensor of the NPU
    at::Tensor result = npu_preparation::apply_tensor_without_format(self);

    // calculate the output result of the NPU
    EXEC_NPU_CMD(aclnnAbs, self, result);
    return result;
}

// abs_ api实现函数,参数与torch api一致。该接口为inplace操作,即输出结果存放在输入
at::Tensor& abs_(at::Tensor& self) {
    DO_COMPATIBILITY(aclnnAbs, acl_op::abs_(self));
    op_api::abs_out(self, self);
    return self;
}
}  // namespace op_api

不同版本间适配代码有差异的,所有代码均放在同一个文件中,用编译宏来区分

#include "op_plugin/AclOpsInterface.h"
#include "op_plugin/OpApiInterface.h"
#include "op_plugin/utils/op_api_common.h"

namespace op_api {
using npu_preparation = at_npu::native::OpPreparation;

// 1.11的函数入参和2.0及以上版本有区别,需要单独实现,因此用宏来控制
#if VERSION_BETWEEN(V1R11, V1R11)
at::Tensor embedding(const at::Tensor& weight, const at::Tensor& indices, int64_t padding_idx, bool scale_grad_by_freq,
                     bool sparse)
{
  DO_COMPATIBILITY(aclnnEmbedding, acl_op::embedding(weight, indices, padding_idx, scale_grad_by_freq, sparse));
  // calculate the output size
  auto output_size = op_infer::array_to_small_vector(indices.sizes());
  output_size.emplace_back(weight.size(weight.dim() - 1));
  // construct the output tensor of the NPU
  at::Tensor result = npu_preparation::apply_tensor_without_format(output_size, weight.options());
  // calculate the output resugt of the NPU
  EXEC_NPU_CMD(aclnnEmbedding, weight, indices, result);
  return result;
}
#endif

#if VERSION_BETWEEN(V2R0, VERSION_NEWEST)
at::Tensor embedding_symint(
    const at::Tensor& weight,
    const at::Tensor& indices,
    c10::SymInt padding_idx,
    bool scale_grad_by_freq,
    bool sparse)
{
    DO_COMPATIBILITY(aclnnEmbedding, acl_op::embedding_symint(weight, indices, padding_idx, scale_grad_by_freq, sparse));
    // calculate the output size
    auto output_size = op_infer::array_to_small_vector(indices.sizes());
    output_size.emplace_back(weight.size(weight.dim() - 1));
    // construct the output tensor of the NPU
    at::Tensor result = npu_preparation::apply_tensor_without_format(output_size, weight.options());
    // calculate the output resugt of the NPU
    EXEC_NPU_CMD(aclnnEmbedding, weight, indices, result);
    return result;
}
#endif

} // namespace op_api

自动前反向绑定算子配置

Pytorch的算子自动反向微分依赖于算子的前反向绑定,即前向函数和反向函数的绑定。对于原生的算子,官方已有前反向绑定逻辑,插件侧有对应前向算子和反向算子适配即可(只需要在op_plugin_functions.yaml里面配置)。对于自定义算子,则需要在插件侧配置前反向自动绑定。

针对需要绑定前反向的算子(包括自定义算子和前反向绑定逻辑与原生不一致的原生算子)提供自动绑定前向算子和反向算子的功能。

  • 适配前向和反向算子: 与上节算子适配开发中一致,分别适配前向算子和反向算子,并在op_plugin_functions.yaml中配置前向和反向算子。
  • 配置前反向绑定,将前向和反向算子进行绑定: Op-plugin与原生PyTorch一致,通过derivatives.yaml,配置算子的前反向绑定关系,如下所示:
# derivatives.yaml
- name: l1_loss(Tensor self, Tensor target, int reduction=Mean) -> Tensor
  self: l1_loss_backward(grad, self, target, reduction)
  target: l1_loss_backward(grad, self, target, reduction) * -1
  version: [v2.0, newest]

所有版本的算子前反向绑定都在同一个derivatives.yaml里面,通过version字段来区分版本。

结构化适配介绍

结构化适配指通过在op_plugin_functions.yaml中进行配置,可自动生成算子实现Kernel。仅支持op_api对应的算子。

如何判断是否可结构化:opapi对应的Aclnn算子与Aten IR的语义对齐,适配层除申请output tensor,无其他适配逻辑。

自动生成的适配文件位于op_plugin/ops/opapi/StructKernelNpuOpApi.cpp

Yaml配置说明

每个结构化适配的函数必须在op_plugin_functions.yaml中配置, 具有如下格式: 方式一(常规场景):

- func: func_name(ArgType arg0[=default], ArgType arg1[=default], ...) -> Return
  op_api: v2.1
  gen_opapi:
    out:
      size: arg0
      dtype: arg1.scalar_type()
      name: arg0
    new_params:
      arg3: arg0.value_or(0)
    exec: aclnnFuncName, arg0, arg1, out, arg3

各个字段的含义如下:

  • gen_opapi: 表示对应API可结构化,其他字段需要配置在此字段下

  • out: 表示函数的输出,此字段下面包含size和dtype字段,如果包含多个输出,可配置成out0、out1等。对于out类接口,此字段不可自定义,需要与Aten IR定义的输出参数名相同。对于inplace类接口,不需要配置此字段。

  • size: 配置输出tensor的shape大小,如果大小和schema中的某个参数相同,可以配置成输入参数的名字。也可配置成自定义infershape函数,infershape函数需在KernelNpuOutputSize.h中实现。对于out类接口,如果输出shape不变,可省略此字段。配置方式主要包含以下几种:

Aten IR定义:
- func: func_name(ArgType arg0, ArgType arg1, ...) -> Return
方式一: 和输入参数相同
  size: arg0
方式二:枚举每个维度的值
  size: '{4, arg0.size(0), arg0.size(1), arg1.size(0)}'
方式三:条件表达式
  size: 'arg1 == 1? arg0.sizes(): at::ArrayRef<int64_t>()'
方式四:在KernelNpuOutputSize.h中自定义infershape函数, 例如broadcast_ops_npu_output_size
  size: broadcast_ops_npu_output_size(arg0, arg1)
  • dtype: 配置输出tensor的dtype大小,如果大小和schema中的某个参数相同,可以配置成输入参数的名字。也可配置成自定义inferdtype函数,inferdtype函数需在KernelNpuOutputDtype.h中实现。对于out类接口,如果输出dtype不需要check,可省略此字段。配置方式主要包含以下几种:
Aten IR定义:
- func: func_name(ArgType arg0, ArgType arg1, ...) -> Return
方式一: 和输入参数相同
  dtype: arg0
方式二:配置成已知的dtype类型
  dtype: at::kFloat
方式三:条件表达式
  dtype: 'isIntegralType(arg0.scalar_type(), true) ? at::kFloat : arg0.scalar_type()'
方式四:在KernelNpuOutputDtype.h中自定义inferdtype函数。
  dtype: inferdtype(arg0, arg1)
  • name: 输出结果涉及named tensor逻辑,可配置此字段,当前仅支持name和输入参数相同的配置。不涉及可忽略。

  • new_params: 可选字段,支持新增自定义变量,配置格式如下:

    new_params:
      arg0: func(arg1)
  • exec: 配置EXEC_NPU_CMD对应的参数。如果除aclnnname(原函数可排除out参数),其它参数顺序和Aten IR的顺序相同,可只配置aclnnname。以abs为例,exec字段可以配置成下面两种方式。
    - func: abs.out(Tensor self, *, Tensor(a!) out) -> Tensor(a!)
      方式一:
      exec: aclnnAbs, self, out
      方式二:
      exec: aclnnAbs

方式二(继承场景):

- func: func_name(ArgType arg0[=default], ArgType arg1[=default], ...) -> Return
  op_api: v2.1
  gen_opapi:
    structured_inherit: func_name.out
  • structured_inherit:如果原函数或inplace类接口的字段配置与out类接口的字段配置相同,可通过此字段继承对应的out类接口。 以abs为例,原函数和out类函数的out属性和exec相同,可通过structured_inherit字段继承。
  - func: abs.out(Tensor self, *, Tensor(a!) out) -> Tensor(a!)
    op_api: [v1.11, newest]
    gen_opapi:
      out:
        size: self
        dtype: self
        name: self
      exec: aclnnAbs, self, out
  - func: abs(Tensor self) -> Tensor
    op_api: [v1.11, newest]
    gen_opapi:
      structured_inherit: abs.out

NPU自定义接口添加废弃告警

Yaml配置说明

当自定义接口的aten需要废弃时,可以通过位于op_plugin/config/deprecated.yaml文件自动添加废弃告警。

deprecated:
  # 废弃且无替换
  - name: npu_nms_rotated
  # 废弃且有替换
  - name: npu_broadcast
    replace: 'torch.broadcast_to'
  - name: npu_broadcast.out
    replace: 'torch.broadcast_to'

其中:

  • name表示当前将要废弃的aten名称,需要注意的是该名称需要包括重载名,例如样例中npu_broadcast.out即为npu_broadcast的out重载变体
  • replace表示对应aten的替换方案,例如torch.broadcast_tonpu_broadcast的替换方案。

当存在replace时,生成告警信息格式为:

f'TORCH_WARN_ONCE("{name} is deprecated and will be removed in future version. Use {replace} instead.");'

其中name不会包含重载名。以npu_broadcast.out为例,生成告警为:

'TORCH_WARN_ONCE("npu_broadcast is deprecated and will be removed in future version. Use torch.broadcast_to instead.");'

当不存在replace时,生成告警信息格式为:

f'TORCH_WARN_ONCE("{name} is deprecated and will be removed in future version.");'

该场景下name同样不会包含重载名。以npu_nms_rotated为例,生成告警为:

'TORCH_WARN_ONCE("npu_nms_rotated is deprecated and will be removed in future version.");'