CANN opbase aclOpExecutor 算子执行器接口全面解析:从 Tensor 分配到任务执行与 cache 优化

CANN opbase aclOpExecutor 算子执行器接口全面解析:从 Tensor 分配到任务执行与 cache 优化 CANN opbase aclOpExecutor 算子执行器接口全面解析从 Tensor 分配到任务执行与 cache 优化【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase导读本文聚焦 CANN opbase 算子库基础框架中的aclOpExecutor算子执行器接口族系统讲解 L2 阶段 aclnn 算子实现中如何通过该执行器申请 device/host 侧 Tensor、构造标量与数组、组织输入输出、计算 workspace、最终在指定 stream 上执行算子任务以及如何通过AbandonCache关闭 aclnn cache 达到特殊场景下的性能控制。读完本文你将掌握aclOpExecutor全部公开接口的函数原型、参数语义、数据类型约束与调用规范并能结合 op_executor.cpp 源码理解其底层实现直接应用于自定义算子的 host 侧 API 开发。一、aclOpExecutor 是什么L2 阶段算子实现的上下文枢纽aclOpExecutor是 CANN opbase 中用于记录整个 host 侧 API 运行信息的上下文结构host 侧 API 中几乎所有操作都以该数据结构为媒介详见 预留接口 中对aclOpExecutor()构造函数的说明。从调用层次看aclnn 算子对外暴露的接口分为两个阶段L2 一阶段aclnnXxxGetWorkspaceSize负责根据输入参数构造执行上下文、申请算子所需的输入输出资源、执行 infer shape并输出所需workspaceSize和aclOpExecutor指针。一阶段内部会调用各种L0 接口如AllocTensor、CreatAiCoreKernelLauncher等完成资源与任务的登记L2 二阶段aclnnXxx用户申请好 workspace 后调用二阶段接口在指定 stream 上真正执行算子任务。aclOpExecutor正是贯穿这两个阶段的上下文对象一阶段通过CREATE_EXECUTOR()宏创建UniqueExecutor并在其上调用来登记任务与资源二阶段则通过CommonOpExecutorRun根据其中记录的任务队列完成执行。在 op_executor.cpp 中aclOpExecutor的各个成员方法均有对应实现例如AllocTensor、AllocHostTensor、ConvertToTensor、AbandonCache等。二、Tensor 资源申请AllocTensor 与 AllocHostTensor2.1 AllocTensor申请 device 侧 TensorAllocTensor用于申请一个 device 侧 tensor提供多个重载函数以指定不同的属性aclTensor* AllocTensor(const op::Shape shape, op::DataType dataType, op::Format format op::Format::FORMAT_ND) aclTensor* AllocTensor(const op::Shape storageShape, const op::Shape originShape, op::DataType dataType, op::Format storageFormat, op::Format originFormat) aclTensor* AllocTensor(op::DataType dataType, op::Format storageFormat, op::Format originFormat)参数说明参数输入/输出说明shape输入将 aclTensor 的 StorageShape 和 OriginShape 都设置为指定的 shape。dataType输入指定 aclTensor 的数据类型。format输入将 aclTensor 的 StorageFormat 和 OriginFormat 都设置为指定的 format。storageShape输入将 aclTensor 的 StorageShape 设置为指定 shape。originShape输入将 aclTensor 的 OriginShape 设置为指定 shape。storageFormat输入将 aclTensor 的 StorageFormat 设置为指定 format。originFormat输入将 aclTensor 的 OriginFormat 设置为指定 format。返回值返回申请得到的 aclTensor申请失败则返回nullptr。约束入参指针不能为空。调用示例申请一个 int64 类型、shape 为[1, 2, 3, 4, 5]的 ND tensorvoid Func(aclOpExecutor *executor) { gert::Shape newShape; for (int64_t i 1; i 5; i) { newShape.AppendDim(i); } aclTensor *tensor executor-AllocTensor(newShape, DT_INT64, ge::FORMAT_ND); }从源码看op_executor.cpp三个重载均会构造 tensor 对象并登记到执行器上下文当申请失败时会记录OP_LOGE(ACLNN_ERR_INNER, aclOpExecutor::AllocTensor failed.)错误日志并释放已创建对象后返回nullptr。值得说明的是第一个重载的默认参数format op::Format::FORMAT_ND表明不显式指定 format 时默认按 ND 格式申请第二个重载允许将存储态 shape/format 与逻辑态 shape/format 分离设置这是支撑算子内部格式转换如 NCHW 与 5HD 等存储格式切换的基础能力。2.2 AllocHostTensor申请 host 侧 TensorAllocHostTensor用于申请一个 host 侧 tensor同样提供多个重载分为两组组一根据输入信息组合申请 host 侧 tensoraclTensor *AllocHostTensor(const op::Shape shape, op::DataType dataType, op::Format format op::Format::FORMAT_ND) aclTensor *AllocHostTensor(const op::Shape storageShape, const op::Shape originShape, op::DataType dataType, op::Format storageFormat, op::Format originFormat)组二申请 host 侧 tensor并将指定数据类型的内存作为该 tensor 内容aclTensor *AllocHostTensor(const int64_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const uint64_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const bool *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const char *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const int32_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const uint32_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const int16_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const uint16_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const int8_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const uint8_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const double *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const float *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const op::fp16_t *value, uint64_t size, op::DataType dataType) aclTensor *AllocHostTensor(const op::bfloat16 *value, uint64_t size, op::DataType dataType)参数说明组一各参数语义与AllocTensor一致format默认FORMAT_ND组二参数如下参数输入/输出说明value输入指向不同数据类型的源数据。size输入源数据的元素个数。dataType输入将源数据转为 dataType 指定的数据类型后写入 tensor。返回值返回申请得到的 aclTensor申请失败则返回nullptr。约束入参指针不能为空。调用示例申请一个 host 侧 tensor并将myArray中的数据拷贝到 tensor 中void Func(aclOpExecutor *executor) { int64_t myArray[10]; aclTensor *tensor executor-AllocHostTensor(myArray, 10, DT_INT64); }从源码实现看op_executor.cpp组二为每种基础类型含fp16_t、bfloat16等扩展浮点类型都提供了专门的AllocHostTensor重载实现时统一将源数据按dataType转换后写入 host tensor并沿用“失败记录OP_LOGE(ACLNN_ERR_INNER)日志并返回nullptr”的统一错误处理路径。host 侧 tensor 通常用于算子中的常量输入如权重初值、shape 参数等以及需要在 host 侧完成的形状计算。三、标量与数组资源申请AllocScalar / AllocIntArray / AllocFloatArray / AllocBoolArray / 列表接口除了 Tensor算子入参还可能是标量scalar与数组array。opbase 为这些非 tensor 输入提供了统一的申请接口返回值在申请失败时统一为nullptr约束均为“入参指针不能为空”。3.1 AllocScalar申请并赋值标量aclScalar *AllocScalar(const void *data, op::DataType dataType) aclScalar *AllocScalar(float value) aclScalar *AllocScalar(double value) aclScalar *AllocScalar(op::fp16_t value) aclScalar *AllocScalar(op::bfloat16 value) aclScalar *AllocScalar(int32_t value) aclScalar *AllocScalar(int64_t value) aclScalar *AllocScalar(int16_t value) aclScalar *AllocScalar(int8_t value) aclScalar *AllocScalar(uint32_t value) aclScalar *AllocScalar(uint64_t value) aclScalar *AllocScalar(uint16_t value) aclScalar *AllocScalar(uint8_t value) aclScalar *AllocScalar(bool value)参数输入/输出说明data输入源数据指针。dataType输入源数据的数据类型。value输入将 aclScalar 的内容指定为 value。调用示例初始化一个值为 5、数据类型为 int64 的 aclScalar 对象void Func(aclOpExecutor *executor) { int64_t val 5; aclScalar *scalar executor-AllocScalar(val); scalar executor-AllocScalar(val, DT_INT64); }3.2 数组申请AllocIntArray / AllocFloatArray / AllocBoolArrayaclIntArray *AllocIntArray(const int64_t *value, uint64_t size) aclFloatArray *AllocFloatArray(const float *value, uint64_t size) aclBoolArray *AllocBoolArray(const bool *value, uint64_t size)参数输入/输出说明value输入源数据用于初始化对应的 Array 对象。size输入源数据的元素个数。调用示例三者结构一致以 AllocIntArray 为例// 申请一个长度为10的aclIntArray void Func(aclOpExecutor *executor) { int64_t myArray[10]; aclIntArray *array executor-AllocIntArray(myArray, 10); }3.3 列表申请AllocTensorList / AllocScalarList当算子的某个入参是一组 tensor 或一组 scalar如 concat、gather 类算子时需要使用列表接口aclTensorList *AllocTensorList(const aclTensor *const *tensors, uint64_t size) aclScalarList *AllocScalarList(const aclScalar *const *scalars, uint64_t size)参数输入/输出说明tensors / scalars输入源数据用于初始化对应的 List 对象。size输入源数据的元素个数。调用示例初始化 5 个 aclTensor 并将其组装为一个 aclTensorListvoid Func(aclOpExecutor *executor) { gert::Shape newShape; for (int64_t i 1; i 5; i) { newShape.AppendDim(i); } std::vectoraclTensor * tensors; for (int64_t i 1; i 5; i) { aclTensor *tensor executor-AllocTensor(newShape, DT_INT64, ge::FORMAT_ND); tensors.push_back(tensor); } aclTensorList *tensorList executor-AllocTensorList(tensors.data(), tensors.size()); }调用示例初始化 5 个 aclScalar 并将其组装为一个 aclScalarListvoid Func(aclOpExecutor *executor) { int64_t val 5; std::vectoraclScalar * scalars; for (int64_t i 1; i 5; i) { aclScalar *scalar executor-AllocScalar(val); scalars.push_back(scalar); } aclScalarList *scalarList executor-AllocScalarList(scalars.data(), scalars.size()); }四、类型转换ConvertToTensorConvertToTensor将不同数据类型的 host 侧数据转换为一个 host 侧 aclTensor 对象提供 7 个重载前 6 个为非模板重载最后 1 个为模板重载const aclTensor *ConvertToTensor(const aclIntArray *value, DataType dataType) const aclTensor *ConvertToTensor(const aclBoolArray *value, DataType dataType) const aclTensor *ConvertToTensor(const aclFloatArray *value, DataType dataType) const aclTensor *ConvertToTensor(const aclFp16Array *value, DataType dataType) const aclTensor *ConvertToTensor(const aclBf16Array *value, DataType dataType) const aclTensor *ConvertToTensor(const aclScalar *value, DataType dataType) templatetypename T const aclTensor *ConvertToTensor(const T *value, uint64_t size, DataType dataType)参数输入/输出说明value输入host 侧源数据。size输入源数据的元素个数。dataType输入将源数据转换为指定数据类型后写入 aclTensor。返回值返回转换后的 host 侧 tensor。约束入参指针不能为空。各接口参数数据类型约束各重载对源数据与目标dataType的支持范围如下这些约束直接决定了调用时允许的取值组合接口value 类型约束dataType 支持范围接口1ConvertToTensor(const aclIntArray*, DataType)aclIntArray 类型内部存储 int64_t 数据DT_FLOAT、DT_FLOAT16、DT_BF16、DT_INT8、DT_INT16、DT_UINT16、DT_UINT8、DT_INT32、DT_INT64、DT_UINT32、DT_UINT64、DT_BOOL、DT_DOUBLE接口2ConvertToTensor(const aclBoolArray*, DataType)aclBoolArray 类型内部存储 bool 数据同上接口3ConvertToTensor(const aclFloatArray*, DataType)aclFloatArray 类型内部存储 float 数据同上接口4ConvertToTensor(const aclFp16Array*, DataType)aclFp16Array 类型内部存储 fp16_t 数据同上接口5ConvertToTensor(const aclBf16Array*, DataType)aclBf16Array 类型内部存储 bfloat16 数据同上接口6ConvertToTensor(const aclScalar*, DataType)aclScalar 类型支持 DT_BOOL、DT_INT8、DT_UINT8、DT_INT16、DT_UINT16、DT_INT32、DT_UINT32、DT_INT64、DT_UINT64、DT_FLOAT、DT_DOUBLE、DT_FLOAT16、DT_BF16、DT_COMPLEX64、DT_COMPLEX128、DT_FLOAT8_E5M2、DT_FLOAT8_E4M3FN、DT_FLOAT8_E8M0、DT_FLOAT6_E3M2、DT_FLOAT6_E2M3、DT_FLOAT4_E2M1、DT_FLOAT4_E1M2、DT_HIFLOAT8与 value 相同的数据类型全集接口7ConvertToTensor(const T*, uint64_t, DataType)模板类型 T 支持int64_t、uint64_t、int32_t、uint32_t、int8_t、uint8_t、int16_t、uint16_t、float、double、bool、char、op::bfloat16、op::fp16_tsize 为 uint64_t表示元素个数DT_FLOAT、DT_FLOAT16、DT_BF16、DT_INT8、DT_INT16、DT_UINT16、DT_UINT8、DT_INT32、DT_INT64、DT_UINT32、DT_UINT64、DT_BOOL、DT_DOUBLE从数据类型全集可以看出接口 6aclScalar 来源对目标类型支持最广覆盖了 opbase 中定义的低精度浮点扩展类型FP8、FP6、FP4、HIFLOAT8 等对应仓库中的 float8_e4m3fn.h、float8_e5m2.h、float6_e3m2.h、float4_e2m1.h 等头文件适合将标量常量转换为 host tensor 参与 shape 相关计算。调用示例分别将一个 aclScalar 和 int64_t 转为 host 侧 tensorvoid Func(aclOpExecutor *executor) { int64_t val 5; aclScalar *scalar executor-AllocScalar(val); const aclTensor *tensor executor-ConvertToTensor(scalar, DT_INT64); tensor executor-ConvertToTensor(val, 1, DT_INT64); }五、workspace 计算与任务执行GetWorkspaceSize / ReleaseTo / CommonOpExecutorRun这三个接口构成 aclnn 算子两阶段 API 的骨架在aclnnXxxGetWorkspaceSize与aclnnXxx中几乎固定出现属于 L2 接口的标准写法。5.1 GetWorkspaceSize计算一阶段所需 workspace根据 L2 一阶段中调用的 L0 接口计算需要的 workspace 大小uint64_t GetWorkspaceSize()无入参返回 L2 接口在运行中需要的 workspace 大小。典型用法aclnn 固定写法void aclnnAddGetWorkspaceSize(..., uint64_t *workspaceSize, aclOpExecutor **executor) { auto uniqueExecutor CREATE_EXECUTOR(); ...... *workspaceSize uniqueExecutor-GetWorkspaceSize(); }5.2 ReleaseTo输出 executor 指针将UniqueExecutor中保存的aclOpExecutor指针传递到 L2 一阶段输出的executor中void ReleaseTo(aclOpExecutor **executor)参数输入/输出说明executor输出出参将 UniqueExecutor 中的 aclOpExecutor 指针赋值给*executor。约束executor非空。典型用法void aclnnAddGetWorkspaceSize(..., uint64_t *workspaceSize, aclOpExecutor **executor) { auto uniqueExecutor CREATE_EXECUTOR(); ...... uniqueExecutor.ReleaseTo(executor); }5.3 CommonOpExecutorRun二阶段执行任务队列根据 workspace、stream执行算子 executor 上下文中的所有任务aclnnStatus CommonOpExecutorRun(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)参数输入/输出说明workspace输入根据 L2 一阶段接口计算出的 workspaceSize在 device 侧申请的片上内存指针。workspaceSize输入L2 一阶段接口计算出的 workspaceSize。executor输入L2 一阶段接口调用后生成的 op 执行器对象。stream输入指定流执行 executor 中的算子任务。返回值执行成功返回ACLNN_SUCCESS否则返回 aclnn 错误码。约束executor 不能为空workspaceSize 大于 0 时workspace 不能为空。调用示例aclnnAdd 的二阶段函数执行 executor 任务队列中的算子aclnnStatus aclnnAdd(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream) { return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); }从执行器的内部结构看详见 预留接口aclOpExecutor内部维护了任务执行队列通过AddToKernelLauncherList系列接口登记 AI Core 任务、DVPP 任务、数据拷贝类任务与 AI CPU 任务Run()负责运行执行队列中的任务GetStream()/SetStream()负责读写当前执行流。CommonOpExecutorRun本质上就是基于传入的 workspace 与 stream 触发这一任务队列的完整执行。六、aclnn cache 与 AbandonCacheAbandonCache用于关闭 aclnn cache 缓存功能void AbandonCache(bool disableRepeat false)参数输入/输出说明disableRepeat输入设置 aclOpExecutor 是否支持复用。默认为 false不复用。该功能背景是首次调用 aclnn 算子后框架会记录 cache 缓存后续再次调用时跳过一阶段aclnnXxxGetWorkspaceSize函数从而提升性能。当应用场景要求一阶段aclnnXxxGetWorkspaceSize必须每次都执行时需要在该函数中显式调用AbandonCache关闭缓存void aclnnAddGetWorkspaceSize(..., uint64_t *workspaceSize, aclOpExecutor **executor) { auto uniqueExecutor CREATE_EXECUTOR(); ...... uniqueExecutor.get()-AbandonCache(); }从源码实现看op_executor.cppAbandonCache由OpExecutorImpl提供实现默认参数disableRepeat false表示默认仅关闭缓存但保持不可复用语义。与之配套的执行器缓存机制还包括FinalizeCache()完成 cache 最终数据保存、RepeatRunWithCache()复用场景下尝试利用 cache 完成任务执行、AddCache()/DeleteCache()/GetOpExecCache()cache 的全局保存、删除与获取以及IsRepeatable()/SetRepeatable()可复用状态查询与设置等接口见 预留接口。七、预留接口一览理解执行器内部能力边界以下接口为预留接口后续可能变更或废弃官方不建议开发者直接使用但理解其语义有助于掌握aclOpExecutor的完整能力边界完整说明见 预留接口接口定义功能说明aclOpExecutor()记录整个 host 侧 API 运行信息的上下文结构host 侧 API 中几乎所有操作都以该数据结构为媒介。CreateView(const aclTensor *tensor, const op::Shape shape, int64_t offset)针对已有 aclTensor 创建 view 类 tensor两者共享 device 内存可指定后者的 shape 和 offset。CreateView(const aclTensor *tensor, const op::Shape oriShape, const op::Shape storageShape, const op::Strides oriStride, int64_t offset)创建 view 类 tensor可指定 originShape、storageShape、originStride 和 offset。UpdateTensorAddr(void *workspaceAddr, const size_t size)在 workspace 地址分配后刷新每个 workspace 的地址。GetWorkspaceAddr() / GetWorkspaceSize() / GetWorkspaceOffsets()获取 workspace 起始指针、大小与 offset 列表。SetWorkspaceOffsets(const op::FVectoruint64_t workspaceOffsets)设置要记录的 workspace offset 列表。Run()运行 aclOpExecutor 执行队列中的任务。GetStream() / SetStream(aclrtStream stream)获取/设置当前执行流。GetInputTensors() / GetOutputTensors()获取 host 侧 API 接口中的输入/输出 aclTensor。GetLogInfo() / SetLogInfo(const op::internal::OpLogInfo logInfo)获取/设置日志相关信息。GetOpConfigInfo() / SetOpConfigInfo(const op::OpConfigInfo opConfigInfo)获取/设置算子运行时相关配置信息。AddTensorRelation(const aclTensor *tensorOut, const aclTensor *tensorMiddle)记录两个 aclTensor 间的地址等价关系用于 aclnn cache。UpdateStorageAddr()在 aclOpExecutor 复用场景中刷新 aclTensor 地址。SetRepeatable() / IsRepeatable()设置/判断当前 aclOpExecutor 是否可复用。FinalizeCache()完成 aclnn cache 最终的数据保存工作。RepeatRunWithCache(void *workspaceAddr, const aclrtStream stream)复用场景下尝试利用 aclnn cache 完成任务执行。CheckLauncherRepeatable()判断任务列表中的每个任务都允许 aclOpExecutor 复用。AddCache() / DeleteCache() / GetOpExecCache()aclnn cache 的保存、删除与获取。SetIOTensorList()记录 host 侧 API 的输入/输出 aclTensor。GetGraph()获取 host 侧 API 的执行图。GetMagicNumber()获取 magic number用于不同对象的区分。UniqueExecutor(const char *funcName) / UniqueExecutor() / get()UniqueExecutor 是 aclOpExecutor 的构造工厂get() 获取其中的 aclOpExecutor 指针。ReleaseTo(aclOpExecutor **executor)将 UniqueExecutor 中的 aclOpExecutor 指针传递给目标 aclOpExecutor 指针。GetOpExecCacheFromExecutor(aclOpExecutor *)尝试将外部 aclOpExecutor 转为 aclnn cache 对象。InitL2Phase1Context / InitL2Phase2Context / InitL0Context初始化 host 侧 API 一阶段、二阶段及 L0 接口中的部分 DFX 变量值。CreatAiCoreKernelLauncher / CreatDSAKernelLauncher创建 AI Core 任务对象 / DSA 任务对象。InferShape(uint32_t optype, op::OpArgList inputs, op::OpArgList outputs, op::OpArgList attrs)执行指定算子的 infer shape。AddToKernelLauncherList / AddToKernelLauncherListDvpp / AddToKernelLauncherListCopyTask / AddToKernelLauncherListAiCpu分别向执行队列添加 AI Core、DVPP、数据拷贝、AI CPU 任务。CommonOpExecutorRun(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)根据外部给出的 aclOpExecutor 及 workspace、stream执行上下文中的所有任务。八、组合使用一段完整的 L2 一阶段接口范式综合上述接口一个典型的 aclnn 算子 L2 一阶段函数会按如下顺序组织创建UniqueExecutor→ 用AllocTensor/AllocHostTensor/AllocScalar等申请资源 → 调用InferShape等完成形状推导 → 通过GetWorkspaceSize输出 workspace 大小 → 通过ReleaseTo输出 executor 指针必要时调用AbandonCache。伪代码结构如下aclnnStatus aclnnXxxGetWorkspaceSize(..., uint64_t *workspaceSize, aclOpExecutor **executor) { auto uniqueExecutor CREATE_EXECUTOR(); // 1. 申请输入/输出 tensor 与标量、数组资源 aclTensor *in uniqueExecutor-AllocTensor(inShape, DT_FLOAT, FORMAT_ND); aclTensor *out uniqueExecutor-AllocTensor(outShape, DT_FLOAT, FORMAT_ND); aclScalar *alpha uniqueExecutor-AllocScalar(1.0f); // 2. 登记算子任务AI Core / AI CPU 等执行 infer shape // 3. 输出 workspace 大小与 executor *workspaceSize uniqueExecutor-GetWorkspaceSize(); uniqueExecutor.ReleaseTo(executor); return ACLNN_SUCCESS; }九、源码与文档定位速查接口头文件include/nnopbase/opdev/op_executor.haclOpExecutor声明核心实现op_executor.cppAllocTensor、AllocHostTensor、AbandonCache等实现接口文档目录docs/zh/api/nnopbase/opdev/op_executor关联类型接口StorageShape/OriginShape/Format 等访问器docs/zh/api/nnopbase/opdev/common_types数据类型定义op::DataType及 FP8/FP6/FP4 等扩展类型include/nnopbase/opdev/data_type_utils.h 及 include/nnopbase/opdev 下各浮点类型头文件英文版接口文档docs/en/api/nnopbase/opdev/op_executor说明本文所介绍的接口面向 CANN 算子 host 侧 APIaclnn 算子开发场景其使用形态为在算子实现源码中调用具体可用性与行为以当前仓库及配套 CANN 工具链版本为准。【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考