- 人工智能
- 深度学习
- 算子库
- CANN
- Ascend
【免费下载链接】asc-devkit
本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C++标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。
导读
OpAICoreConfig是 CANN asc-devkit 原型注册体系中用于描述 AI Core 算子差异化配置的核心类,承载输入/输出参数定义、动态 Shape/Format 支持标志、精度模式等多项配置。本文围绕其赋值运算符重载operator=(const OpAICoreConfig &)展开,说明该接口如何实现OpAICoreConfig对象的深拷贝,并通过源码与测试用例印证其在实际算子原型生成流程(opbuild)中的典型使用场景。读者阅读后可以准确掌握该运算符的语义、与默认拷贝构造的区别,以及在多 AI 处理器型号配置复用时的正确写法。
OpAICoreConfig 类简介
在 原型注册与管理 体系中,OpAICoreConfig用于承载某个算子在某类 AI 处理器型号(SoC)上的差异化原型信息。它通过 AddConfig 与具体的 socVersion 绑定注册,也可以通过 REGISTER_OP_AICORE_CONFIG 宏单独注册。
OpAICoreConfig类的主要成员能力见 OpAICoreConfig 总览,包括:
- 输入/输出原型配置:
Input(name)、Output(name),返回OpParamDef用于继续配置 ParamType、DataType、Format 等; - 动态能力标志:
DynamicCompileStaticFlag、DynamicFormatFlag、DynamicRankSupportFlag、DynamicShapeSupportFlag、NeedCheckSupportFlag、PrecisionReduceFlag; - 扩展配置:
ExtendCfgInfo(key, value); - 生命周期管理:构造函数(默认构造、带 soc 入参构造、拷贝构造)以及本文重点的赋值运算符重载
operator=。
由于该对象内部持有输入/输出参数定义、标志位、扩展配置等多份动态信息,对象的复制不能依赖编译器生成的浅拷贝,必须显式提供"深拷贝"语义,这正是operator=的职责所在。
operator= 函数原型与语义
赋值运算符重载的函数原型定义在 operator.md 中:
OpAICoreConfig &operator=(const OpAICoreConfig &aicore_config)功能说明
赋值运算符重载实现OpAICoreConfig类对象的深拷贝:将右侧对象(被拷贝方)中已配置的输入、输出以及各项配置项信息完整复制到左侧对象,而不是简单地复制指针或句柄。这样左侧对象与右侧对象各自持有独立的数据副本,互不影响,避免了共享内部状态带来的隐患。
参数说明
| 参数 | 输入/输出 | 说明 |
|---|---|---|
| aicore_config | 输入 | 被拷贝的OpAICoreConfig对象 |
返回值说明
返回对拷贝结果对象(即赋值运算符左侧对象)的引用,返回值类型为OpAICoreConfig &。这与 C++ 赋值运算符的常规约定一致,可以支持链式赋值(如a = b = c)。
约束说明
无额外约束,任何已构造完成的OpAICoreConfig对象均可作为被拷贝方。
深拷贝的工程意义:为什么不能依赖默认赋值
OpAICoreConfig内部管理的配置数据(输入/输出OpParamDef定义、各 Flag、扩展配置键值对等)通常以动态容器方式组织。如果使用编译器默认生成的按成员浅拷贝赋值:
- 内部容器会复制一份(值语义的容器在 C++ 中本身是深拷贝),但如果类内部存在指针、句柄或共享资源引用,浅拷贝会导致两个对象共享同一份底层数据;
- 后续对任一对象的修改可能意外影响另一个对象,在多 AI 处理器型号配置复用场景下会引入难以排查的副作用。
因此 asc-devkit 显式重载operator=并提供深拷贝语义,保证赋值后左侧对象拥有与右侧对象完全等价、且相互独立的配置快照。这一点与 OpAICoreConfig 构造函数 中拷贝构造函数的语义保持一致:拷贝构造函数会复制被拷贝对象中已配置的输入、输出和配置项信息,赋值运算符则是对已构造对象执行同样的复制操作。
源码印证:opbuild 中的真实赋值场景
从源码结构看,operator=在算子原型配置文件生成链路(opbuild 的 CfgGenerator)中被广泛使用,用于按 AI 处理器型号逐个实例化配置对象。
在 tools/build/opbuild/op_cfg_generator.cpp 中,生成器遍历ASCEND_COMPUTE_UNIT指定的 compute unit(SoC 型号)列表,对每个型号执行:
OpAICoreConfig aicoreConfig; if (cfgIter == allAICoreConfig.end()) { aicoreConfig = OpAICoreConfig(socVer.c_str()); // 使用带 soc 入参的构造 + 赋值 } else { aicoreConfig = cfgIter->second; // 从注册表中取出配置并赋值 }这两处恰好展示了operator=的两个典型用法:
aicoreConfig = OpAICoreConfig(socVer.c_str()):将临时构造的、带 AI 处理器型号入参的配置对象赋值给局部变量,赋值完成后临时对象析构,左侧对象仍持有完整、独立的配置数据;aicoreConfig = cfgIter->second:将AddConfig注册表中保存的OpAICoreConfig拷贝赋值给局部变量,用于后续逐 SoC 生成对应的原型配置文件(见ParseSingleComputeUnitOfOp调用)。
同样的复制语义在 tests/tools/utils/opbuild/test_ops.cpp 的测试用例中也有体现:测试算子AddTik2构造了统一的aicConfig,随后通过this->AICore().AddConfig("ascend910", aicConfig)与AddConfig("ascendxxx", aicConfig)将其同时注册到多个 AI 处理器型号上——AddConfig接收配置对象并保存,与赋值拷贝一起构成了"一份配置、多型号复用"的典型模式。
完整调用示例:赋值与多型号配置复用
以下示例综合 operator.md、OpAICoreConfig 构造函数 与 AddConfig 的调用方式,演示如何通过赋值运算符快速生成多个型号的差异化配置:
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 }); // 使用带 soc 入参的构造函数 OpAICoreConfig aicConfig1("ascendxxx1"); OpAICoreConfig aicConfig2("ascendxxx2"); 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 }); // 使用拷贝构造函数 OpAICoreConfig aicConfig3(aicConfig1); // 使用赋值运算符:在已有对象基础上覆盖式复制 OpAICoreConfig aicConfig4; aicConfig4 = aicConfig2; // 深拷贝 aicConfig2 的全部配置 aicConfig4.Input("x") .ParamType(REQUIRED) .DataType({ ge::DT_FLOAT16 }) .Format({ ge::FORMAT_ND }); // 赋值后独立修改,不影响 aicConfig2 this->AICore().AddConfig("ascendxxx1", aicConfig1); this->AICore().AddConfig("ascendxxx2", aicConfig2); this->AICore().AddConfig("ascendxxx3", aicConfig3); this->AICore().AddConfig("ascendxxx4", aicConfig4); } };要点说明:
aicConfig4 = aicConfig2之后,aicConfig4拥有与aicConfig2等价的输入、输出与配置项副本;- 随后对
aicConfig4的修改(如重新设置Input("x")的 DataType 与 Format)不会回写aicConfig2,这正是深拷贝语义的价值所在; - 每个
AddConfig将配置对象与 AI 处理器型号绑定注册,同一个配置对象可注册给多个型号,参考 AddConfig 的约束说明:不传入aicore_config参数时,框架会为部分配置参数填充默认值(DynamicCompileStaticFlag、DynamicFormatFlag、DynamicRankSupportFlag、DynamicShapeSupportFlag、PrecisionReduceFlag默认为true,NeedCheckSupportFlag默认为false)。
与构造函数、REGISTER_OP_AICORE_CONFIG 的配合
赋值运算符通常与以下接口配合使用,构成完整的差异化配置注册链路:
- OpAICoreConfig 构造函数:带
soc入参的构造函数会对DynamicCompileStaticFlag、DynamicFormatFlag、DynamicRankSupportFlag、DynamicShapeSupportFlag、NeedCheckSupportFlag、PrecisionReduceFlag等参数进行默认初始化;无入参的默认构造函数不初始化这些参数;拷贝构造函数复制已配置信息; - REGISTER_OP_AICORE_CONFIG:通过回调函数返回
OpAICoreConfig,在不改变原有注册的基础上单独注册算子在某硬件形态上的差异化信息;当与AddConfig注册的 AI 处理器型号相同时,AddConfig方式注册的配置优先级更高,会覆盖宏注册的信息; - AddConfig:完成型号与配置对象的最终绑定。
小结
OpAICoreConfig::operator=是 asc-devkit 原型注册体系中的一个基础而关键的生命周期接口:
- 语义上提供深拷贝,赋值后两侧对象配置等价但相互独立;
- 原型上返回
OpAICoreConfig &,符合 C++ 惯例,支持链式赋值; - 工程上支撑"一份基础配置、多型号差异化复用"的注册模式,在 opbuild 配置生成器与测试用例中均有实际使用印证。
理解该接口后,开发者可以在自定义算子原型注册时放心地通过赋值运算复用既有配置对象,再针对不同 AI 处理器型号进行增量调整,从而保持原型注册代码的简洁与可维护性。
- 人工智能
- 深度学习
- 算子库
- CANN
- Ascend
【免费下载链接】asc-devkit
本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C++标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。
相关推荐
JSON for Modern C++ 赋值运算符 operator= 深度解析:拷贝与交换策略的工程实践
JSON for Modern C++ 赋值运算符 operator= 深度解析:拷贝与交换策略的工程实践 operator= 是 nlohmann::json
序列化asc-devkit 算子原型注册:OpAICoreConfig 构造函数详解与差异化配置实践
asc devkit 算子原型注册:OpAICoreConfig 构造函数详解与差异化配置实践 导读 本文深入解析 CANN asc devkit 算子程序开发
人工智能深度学习算子库CANNAscendasc-devkit 算子开发:OpAICoreConfig::DynamicShapeSupportFlag 动态 Shape 支持开关详解
asc devkit 算子开发:OpAICoreConfig::DynamicShapeSupportFlag 动态 Shape 支持开关详解 导读 在 CAN
人工智能深度学习算子库CANNAscend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考