opbase:CANN 所有算子的公共地基
翻开 CANN 任何一个算子仓库——ops-math、ops-nn、ops-blas、ops-fft、ops-rand——它们都依赖同一个基础库opbase。opbase 不提供面向用户的算子能力。它提供的是所有算子共享的基础设施Tensor 的内存管理和形状描述、Kernel 的注册和加载机制、Buffer 的分配和生命周期管理。opbase 在 CANN 中的位置上层算子库ops-math、ops-nn、ops-blas、ops-fft、ops-rand ……各自管一类算子 ↓ 全部依赖 opbase ┌──────────────────────────────┐ │ Tensor 数据结构 │ │ Buffer 内存管理 │ │ Kernel 注册框架 │ │ 通用类型定义 │ └──────────────────────────────┘ ↓ CANN 底层Runtime、driver每个新算子仓库启动时不需要从零写 Tensor 管理、Buffer 分配、Kernel 注册——这些在 opbase 中已就绪新仓库直接引用。为什么所有算子仓库都依赖 opbase一个算子从写到 Runtime 执行需要的公共能力包括Tensor 描述。每个算子需要知道输入 Tensor 的形状、数据类型、内存地址。opbase 定义了统一的TensorDesc结构——所有算子仓库都使用这个描述。ops-math 和 ops-nn 的算子之间传递 Tensor 信息时不需要做格式转换。Buffer 分配。算子执行过程中的临时 Tensor 需要分配显存。opbase 提供了opbase::AllocBuffer——封装了 Runtime 的aclrtMalloc但增加了算子级别的生命周期追踪。Buffer 在算子执行完后自动回收。Kernel 注册。写好的算子 Kernel 需要注册到 CANN 的算子表中才能被 GE 识别和调度。opbase 提供了REGISTER_KERNEL宏——开发者只需要在 Kernel 实现文件中加一行注册语句。#includeopbase/opbase.h// 自定义 Add Kernel__aicore__voidAddKernel(...){...}// 注册到算子表——一行搞定REGISTER_KERNEL(CustomAdd,AddKernel);// GE 在编译时就能在算子表中找到 CustomAddTensor 基础能力如何复用所有算子仓库中 Tensor 的创建和销毁走同一条路径// opbase 的 Tensor 创建——所有算子仓库共用opbase::Tensor tensoropbase::AllocTensor({batch,seq_len,hidden_dim},// Shapeopbase::FLOAT16,// 数据类型opbase::ND// 格式);// tensor 的内存由 opbase 管理// 算子执行完自动回收每个算子仓库不需要重新实现 Tensor 分配逻辑。Buffer 的生命周期管理也是复用的// ops-math 的 ReduceSum 算子内部voidReduceSumKernel(...){// opbase 管理的临时 Bufferautotempopbase::AllocBuffer(partial_sum_size);// 计算...// temp 在函数结束时自动回收}算子开发中的基础设施写一个新的 CANN 算子时opbase 提供的工作流继承 OpBase。新算子继承opbase::Operator基类获得输入输出解析、参数校验、生命周期管理等默认实现实现 Compute。只需要实现Compute()虚函数——算子的核心计算逻辑注册。使用REGISTER_KERNEL宏将算子注册到算子表classMyNewOp:publicopbase::Operator{public:OpBase::StatusInit(constOpDescdesc)override{// opbase 自动解析输入输出描述returnopbase::SUCCESS;}OpBase::StatusCompute(conststd::vectoropbase::Tensorinputs,std::vectoropbase::Tensoroutputs)override{// 只有这段代码需要开发者写autoinputinputs[0].datafloat16();autooutputoutputs[0].datafloat16();// 计算逻辑...returnopbase::SUCCESS;}};REGISTER_KERNEL(MyNewOp,MyNewOp);opbase 的类型系统opbase 定义了一套跨仓库统一的类型系统DataTypeFLOAT32、FLOAT16、INT8、INT32、INT64、BOOLFormatND、NZ、NHWC、NCHWShape动态 Shape 用 -1 表示支持 ShapeRange所有算子仓库都使用同一套类型。ops-math 的 ReduceSum 输出的 DataType 跟 ops-nn 的 Conv 输入的 DataType 是同一个枚举值——不需要类型转换。opbase 的 Kernel 注册表Kernel 注册表是 opbase 的另一个核心功能。每个算子库在加载时调用REGISTER_KERNEL把 Kernel 注册到全局表中。GE 在编译时查表找到对应算子的 Kernel。注册表是进程级的——跨模型共享。模型 A 加载了 ops-nn 的 Conv Kernel模型 B 加载同一个 Operator 时不需要重复注册。这个机制在多模型服务中节省了重复加载 Kernel 的时间。参考仓库opbase 算子基础组件库Ascend C 算子编程指南