news 2026/10/17 13:35:12

CANN 算子原型注册详解:使用 OpAICoreConfig::Input 按 AI 处理器型号差异化注册算子输入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN 算子原型注册详解:使用 OpAICoreConfig::Input 按 AI 处理器型号差异化注册算子输入
  • 人工智能
  • 深度学习
  • 算子库
  • CANN
  • Ascend

【免费下载链接】asc-devkit

本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C++标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。

项目地址:https://gitcode.com/cann/asc-devkit
点击查看免费下载

在昇腾 AI 处理器的算子开发中,同一个算子在不通的 AI 处理器型号(SoC)上往往需要支持不同的输入原型。本文以 asc-devkit 开源仓库中的原型注册与管理组件为背景,系统讲解OpAICoreConfig::Input(const char *name)接口的定位、函数原型、链式配置方法以及如何通过AddConfig与REGISTER_OP_AICORE_CONFIG将差异化输入绑定到具体芯片型号。读完本文,你将掌握在OpDef算子原型中为不同 SoC 分别声明输入名称、参数类型、数据类型与数据格式的完整实战方案。

一、接口定位:为什么需要按 AI 处理器型号注册差异化输入

在 算子原型定义 中,算子原型通过一个继承自OpDef的 C++ 类承载,类内使用Input、Output、Attr等接口声明算子对外暴露的接口,并用OP_ADD宏完成注册,从而让框架能够正确识别、编译和执行该算子。

然而在实际场景中,同一个算子在不同的 AI 处理器型号上,其支持的原型输入可能不同。例如某型号只接受DT_FLOAT16输入,而另一型号支持DT_FLOAT或DT_INT32;又或者某个输入在 A 型号上是必选(REQUIRED),在 B 型号上是可选(OPTIONAL)。如果把这些差异全部堆在通用原型里,会导致原型定义臃肿且无法精确表达每个型号的真实能力。

OpAICoreConfig::Input就是为此设计的:它允许开发者在OpAICoreConfig这一按 SoC 维度组织的配置结构中,针对不同的 AI 处理器型号注册差异化的算子原型输入,进而结合AddConfig把该配置与具体芯片型号关联起来。

继承与覆盖规则

从 算子原型定义 的说明可以确认两条核心规则:

  • OpAICoreConfig中未配置的输入输出,继承OpDef中的通用定义;
  • 重新配置的同名输入输出,覆盖通用定义。

也就是说,Input("x")既可以在通用OpDef构造函数中使用(声明算子默认输入),也可以在OpAICoreConfig中使用(为特定型号覆盖x的定义)。两种用法返回的都是OpParamDef引用,用于继续链式配置。

二、函数原型与参数说明

OpAICoreConfig::Input的函数原型如下:

OpParamDef &Input(const char *name)
参数输入/输出说明
name输入算子输入名称。

参数含义与OpDef层的同名接口一致:传入算子输入的名称字符串,用于声明该输入在原型中的身份标识。声明顺序会影响 aclnn 接口参数顺序和核函数(Kernel)入口参数顺序,因此在OpAICoreConfig中重新配置同名输入时,名称必须与通用原型中的输入名称保持一致,否则无法形成覆盖关系。

三、返回值:OpParamDef 及链式配置方法

调用Input后返回一个OpParamDef结构的引用,后续可以通过该结构继续配置算子的输入信息。OpParamDef是算子参数定义的通用载体,完整成员可参考 OpParamDef,其中在输入配置中最常用的是下面三个链式方法。

ParamType:声明参数类型

OpParamDef &ParamType(Option param_type)

Option取值为:

  • OPTIONAL:可选输入,部分场景可以省略;
  • REQUIRED:必选输入,每次调用都必须提供;
  • DYNAMIC:动态输入,数量随调用变化。

DataType:声明参数数据类型

OpParamDef &DataType(std::vector<ge::DataType> types)

传入ge::DataType枚举的列表,声明该输入支持的数据类型。多个数据类型按列表顺序与Format列表一一对应。

Format:声明参数数据格式

OpParamDef &Format(std::vector<ge::Format> formats)

传入ge::Format枚举的列表,声明该输入支持的数据格式。例如FORMAT_ND、FORMAT_NCHW、FORMAT_NCL等。DataType与Format两个列表按位置一一对应,例如DataType({ge::DT_FLOAT16, ge::DT_FLOAT})配合Format({ge::FORMAT_ND, ge::FORMAT_ND})表示支持 "DT_FLOAT16 + FORMAT_ND" 与 "DT_FLOAT + FORMAT_ND" 两组组合。

三个方法都返回OpParamDef &,因此可以连续链式调用:

aicConfig1.Input("x") .ParamType(OPTIONAL) .DataType({ ge::DT_FLOAT }) .Format({ ge::FORMAT_ND });

四、完整调用示例与逐行解析

原文档给出的调用示例完整展示了如何在OpDef构造函数内为两个不同 AI 处理器型号注册差异化输入:

class AddCustom : public OpDef { public: AddCustom(const char* name) : OpDef(name) { this->Input("x").DataType({ ge::DT_FLOAT16 }).ParamType(OPTIONAL); this->Output("y").DataType({ ge::DT_FLOAT16 }); OpAICoreConfig aicConfig1; OpAICoreConfig aicConfig2; aicConfig1.Input("x") .ParamType(OPTIONAL) .DataType({ ge::DT_FLOAT }) .Format({ ge::FORMAT_ND }); aicConfig2.Input("x") .ParamType(REQUIRED) .DataType({ ge::DT_INT32 }) .Format({ ge::FORMAT_ND }); this->AICore().AddConfig("ascendxxx1", aicConfig1); this->AICore().AddConfig("ascendxxx2", aicConfig2); } };

逐段说明:

  1. 通用原型定义:this->Input("x")声明算子通用输入x,默认支持DT_FLOAT16且为OPTIONAL;this->Output("y")声明输出y。这是所有型号共享的基线定义。
  2. 构造两个型号的差异化配置:OpAICoreConfig aicConfig1;与OpAICoreConfig aicConfig2;使用无参构造函数创建。
  3. 型号 1 覆盖输入x:aicConfig1.Input("x")将输入x重新定义为OPTIONAL、DT_FLOAT、FORMAT_ND。
  4. 型号 2 覆盖输入x:aicConfig2.Input("x")将输入x重新定义为REQUIRED、DT_INT32、FORMAT_ND。
  5. 绑定型号:this->AICore().AddConfig("ascendxxx1", aicConfig1)与AddConfig("ascendxxx2", aicConfig2)分别把两份差异化配置注册到两个 AI 处理器型号。示例中的ascendxxx1、ascendxxx2是占位符,实际应替换为真实的芯片型号。

这个模式与 OpAICoreConfig::Output 完全对称——输出差异化配置使用Output("y"),写法一致。

五、将差异化配置绑定到具体 AI 处理器:AddConfig

Input只负责声明输入,真正把配置和芯片型号绑定起来的是AICore().AddConfig(...),其接口定义参见 AddConfig:

void AddConfig(const char *soc) void AddConfig(const char *soc, OpAICoreConfig &aicore_config)
参数输入/输出说明
soc输入支持的 AI 处理器型号。填写规则请参考算子工程目录下编译配置项文件CMakePresets.json中的ASCEND_COMPUTE_UNIT字段,该字段取值在使用 msOpGen 创建工程时自动生成。
aicore_config输入AI Core 配置信息,即OpAICoreConfig定义。

使用注意事项:

  • 不传aicore_config时,OpAICoreConfig结构中的部分参数会配置为默认值,具体如下表(详见 AddConfig):
配置参数说明默认值
DynamicCompileStaticFlag标识该算子实现是否支持入图时的静态 Shape 编译true
DynamicFormatFlag标识是否根据SetOpSelectFormat设置的函数自动推导算子输入输出支持的 dtype 和 formattrue
DynamicRankSupportFlag标识算子是否支持 dynamicRank(动态维度)true
DynamicShapeSupportFlag标识该算子是否支持入图时的动态 Shape 场景true
NeedCheckSupportFlag标识是否在算子融合阶段调用算子参数校验函数进行 data type 与 Shape 的校验false
PrecisionReduceFlag用于 ATC 模型转换或网络调测时控制算子的精度模式true
  • 传入aicore_config时,除了输入输出原型外,还可以通过 DynamicShapeSupportFlag(bool flag) 这类方法逐个覆盖上述开关。例如在测试代码中可以看到链式写法:
aicConfig.DynamicCompileStaticFlag(true) .DynamicFormatFlag(true) .DynamicRankSupportFlag(true) .DynamicShapeSupportFlag(true) .NeedCheckSupportFlag(true) .PrecisionReduceFlag(true); this->AICore().AddConfig("ascend310p"); this->AICore().AddConfig("ascend910", aicConfig); this->AICore().AddConfig("ascendxxx", aicConfig);

上述代码来自仓库测试用例 test_ops.cpp,它演示了"部分型号使用默认配置、部分型号使用差异化配置"的混合注册方式。

六、OpAICoreConfig 构造函数与初始化行为

OpAICoreConfig共有三个构造函数,详见 OpAICoreConfig 构造函数:

OpAICoreConfig() OpAICoreConfig(const char *soc) OpAICoreConfig(const OpAICoreConfig &aicore_config)
参数名输入/输出描述
soc输入AI 处理器型号。
aicore_config输入已构造完成的 OpAICoreConfig,用于拷贝构造 OpAICoreConfig。

需要特别注意的是三种构造函数的行为差异:

  • 传入soc的构造函数会对OpAICoreConfig结构中的部分参数进行初始化:DynamicCompileStaticFlag、DynamicFormatFlag、DynamicRankSupportFlag、DynamicShapeSupportFlag、PrecisionReduceFlag初始化为true,NeedCheckSupportFlag初始化为false;
  • 无入参的默认构造函数不会初始化上述参数;
  • 拷贝构造函数会复制被拷贝对象中已配置的输入、输出和配置项信息,适合在已有配置基础上派生新型号配置。

构造函数同样支持在REGISTER_OP_AICORE_CONFIG独立注册场景中使用(见下一节)。

七、独立文件注册:REGISTER_OP_AICORE_CONFIG

当差异化配置较多、希望按芯片或模块拆分维护时,可以不修改原有原型注册文件,而是通过REGISTER_OP_AICORE_CONFIG宏在独立文件中注册,详见 REGISTER_OP_AICORE_CONFIG。该宏"在不改变原有注册的基础上,允许单独新增文件来注册算子在不同硬件形态上的差异化信息"。

使用该注册宏需要包含头文件:

#include "register/op_config_registry.h"

宏原型:

REGISTER_OP_AICORE_CONFIG(opType, socVersion, opFunc)
参数输入/输出说明
opType输入算子类型。
socVersion输入支持的 AI 处理器型号。
opFunc输入返回 OpAICoreConfig 的回调函数指针,回调函数原型为OpAICoreConfig (*)()。

调用示例:假设已有原型注册文件op_host/add_custom.cpp实现了AddCustom并配置了型号ascendxxx1,可以新增文件op_host/add_custom_xxx.cpp,使用该宏单独注册型号ascendxxx2:

#include "register/op_config_registry.h" namespace ops { REGISTER_OP_AICORE_CONFIG(AddCustom, ascendxxx2, []() { ops::OpAICoreConfig config("ascendxxx2"); return config; }); }

回调函数体内可以像在构造函数中一样调用config.Input("x").ParamType(...).DataType(...).Format(...)完成输入原型配置后返回。

优先级约束:若算子同时使用AddConfig注册算子支持的 AI 处理器型号及OpAICoreConfig信息,且 AI 处理器型号相同时,通过AddConfig方式注册的配置优先级更高,会覆盖REGISTER_OP_AICORE_CONFIG宏注册的OpAICoreConfig信息。这一规则在 REGISTER_OP_AICORE_CONFIG 与 算子原型定义 中均有明确说明。

八、仓库中的真实应用佐证

1. 测试用例中的多型号差异化输入

在 test_ops.cpp 中,AddTik2算子即为一个完整的差异化原型示例:通用原型定义了x1、x2两个输入(分别为OPTIONAL与DYNAMIC),随后构造aicConfig为x1、x2分别配置了不同的ParamType、DataType、Format以及(废弃的)UnknownShapeFormat,最后对ascend310p使用默认配置、对ascend910与ascendxxx使用差异化配置注册。这印证了"一个算子、多份配置、按型号分发"的标准用法。

2. 样例工程中的实际注册

在 add_custom_host.cpp 中,AddCustom算子的原型定义展示了最简注册路径:

namespace ops { class AddCustom : public OpDef { public: explicit AddCustom(const char* name) : OpDef(name) { this->Input("x").ParamType(REQUIRED).DataType({ge::DT_FLOAT16}).Format({ge::FORMAT_ND}); this->Input("y").ParamType(REQUIRED).DataType({ge::DT_FLOAT16}).Format({ge::FORMAT_ND}); this->Output("z").ParamType(REQUIRED).DataType({ge::DT_FLOAT16}).Format({ge::FORMAT_ND}); this->SetInferShape(ge::InferShape).SetInferDataType(ge::InferDataType); this->AICore().SetTiling(optiling::TilingFunc).AddConfig("ascend910b"); } }; OP_ADD(AddCustom); } // namespace ops

这里AICore().AddConfig("ascend910b")使用无aicore_config的重载,即为型号ascend910b采用默认配置注册。开发者可在此基础上按第四节示例扩展为多型号差异化输入注册。

九、使用约束与最佳实践

  • 名称必须一致:OpAICoreConfig中Input("x")的名称要与OpDef通用原型中的输入名称一致,才能形成"同名覆盖";未在OpAICoreConfig中声明的输入继承通用定义。
  • 关注声明顺序:输入注册顺序会影响 aclnn 接口参数顺序和核函数(Kernel)入口参数顺序,差异化覆盖时不宜打乱原有顺序。
  • dtype 与 format 按位置对应:DataType与Format均为列表且按位置一一对应,多组组合要逐项对齐;若希望某输入与已定义输入完全一致,可考虑使用 Follow 简化表达。
  • 型号命名以工程配置为准:AddConfig的soc参数应参考算子工程CMakePresets.json中ASCEND_COMPUTE_UNIT字段(msOpGen 创建工程时自动生成),不要随意捏造型号名。
  • 两种注册方式按需选择:在构造函数内使用AICore().AddConfig(...)适合配置较少、内聚性强的场景;REGISTER_OP_AICORE_CONFIG独立文件注册适合按芯片或模块拆分维护,但同型号下前者优先级更高。
  • 配置项覆盖要谨慎:OpAICoreConfig的六个 Flag 控制静态编译、动态 Shape、动态 Rank、format 推导、融合校验与精度模式等编译期行为,仅在确实需要差异时才显式覆盖,避免与算子实际能力不符导致入图或编译失败。

通过OpAICoreConfig::Input与AddConfig/REGISTER_OP_AICORE_CONFIG的组合,开发者可以用一套算子代码精确描述多芯片形态下的输入契约,这也是 CANN 算子原型注册与管理体系(参见 原型注册与管理)的核心能力之一。

  • 人工智能
  • 深度学习
  • 算子库
  • CANN
  • Ascend

【免费下载链接】asc-devkit

本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C++标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。

项目地址:https://gitcode.com/cann/asc-devkit
点击查看免费下载

相关推荐

上一篇:ESP32 PID 温控实战:3 步搭好温控系统,新手避开 3 个坑
下一篇:Reflex 组织团队(Teams)管理指南:按组批量授予项目访问权限

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 13:33:22

帝肯Centris注射泵串口通信与状态机控制实战指南

简介&#xff1a;本资源为帝肯&#xff08;Tecan&#xff09;Cavro Centris注射泵的官方操作手册中文指令解读资料&#xff0c;面向生物医学、分析化学及自动化实验室技术人员与设备运维工程师&#xff0c;解决精密液体输送设备参数设置、指令执行、日常维护与典型故障响应等实…

作者头像 李华
网站建设 2026/10/17 13:32:37

C# RSA 2048双向加解密实战:公钥加密私钥解密与签名验签完整指南

1. 为什么要在 C# 里把 RSA 双向加解密都跑通RSA 这套非对称加密算法&#xff0c;做过服务端对接的人应该都不陌生。但很多同行在实际项目里只用了它的一半能力——要么只用公钥加密、私钥解密来传敏感数据&#xff0c;要么只用私钥签名、公钥验签来做身份确认。真正把“公钥加…

作者头像 李华
网站建设 2026/10/17 13:32:31

摩斯密码原理与手动编解码实操:从点划间隔到应急通信

这个系列我打算认真写一写。每次只拆一种密码或者编码方式&#xff0c;从原理到手动实操&#xff0c;再到训练技巧&#xff0c;尽量讲透。今天这一篇是系列的第一篇&#xff0c;选择了最经典也最容易被低估的摩斯密码。很多人以为摩斯密码只是“点划组合”&#xff0c;背张表就…

作者头像 李华
网站建设 2026/10/17 13:32:20

Multi-Agent LLMs as Ethics Advocates for AI-Based Systems

文章主要内容总结 本文聚焦于在AI系统需求工程中整合伦理考量的挑战,提出了一个名为MALEA(Multi-Agent LLM Ethics-Advocate Framework) 的多智能体大型语言模型(LLM)框架,用于自动生成伦理需求草案。 研究背景指出,伦理需求的人工获取虽有效,但依赖多方利益相关者输…

作者头像 李华
网站建设 2026/10/17 13:32:13

rea 怎么装:REA 逆向分析工具从零到跑通的完整安装指南

rea 怎么装&#xff1a;REA 逆向分析工具从零到跑通的完整安装指南 【免费下载链接】rea Reverse engineer anything with agents, from app behavior down to native binaries. 项目地址: https://gitcode.com/GitHub_Trending/rea2/rea REA&#xff08;Reverse Engine…

作者头像 李华