CANN ops-math 算子开发指南:aclnnAddV3 与 aclnnInplaceAddV3 带缩放系数的加法算子详解

发布时间:2026/9/20 21:17:06
CANN ops-math 算子开发指南:aclnnAddV3 与 aclnnInplaceAddV3 带缩放系数的加法算子详解 算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载aclnnAddV3 与 aclnnInplaceAddV3 是 CANN ops-math 仓库中面向 Ascend 950 系列产品提供的带缩放系数alpha的加法算子单算子 API计算out self alpha * other两者功能一致区别仅在于前者需要新建输出张量、后者在原张量内存上就地in-place写回。本文以 math/add/docs/aclnnAddV3aclnnInplaceAddV3.md 为主体结合 aclnn_add_v3.cpp 等源码与单元测试完整梳理两段式接口原型、全部参数约束、类型推导/转换规则、错误码含义以及可直接编译运行的调用示例帮助你在 NPU 上快速落地带系数的加法计算。产品支持情况两个接口均为 Ascend 950 系列产品专属能力当前仅支持以下硬件产品是否支持Ascend 950PR/Ascend 950DT支持Atlas A3 训练系列产品/Atlas A3 推理系列产品不支持Atlas A2 训练系列产品/Atlas A2 推理系列产品不支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品不支持仓库中 math/add/op_host/config/ascend950/add_binary.json 仅存在于ascend950/与ascend350/目录下从配置分布上印证了 Add 系列算子在 950 平台的 kernel 二进制配置如Add_FLOAT32、Add_FLOAT16、Add_BFLOAT16、Add_INT32、Add_INT8等 bin 条目是齐备的。另外注意文档中特别标注在 Atlas 训练系列产品与 Atlas 推理系列产品上不支持 BFLOAT16 数据类型详见下文参数说明。功能说明接口功能完成带缩放系数的加法计算。计算公式$$ out_i self_i \alpha \times other_i $$其中self为 aclScalar 标量other为 aclTensor 张量alpha为 aclScalar 标量系数。这与仓库中同为数学类算子的 math/addy x1 x2相比多出了一个标量系数 alpha 作用于other因此实现上并非一个简单的 Add kernel而是一个由多个底层算子拼接而成的复合流程详见后文源码级原理剖析。两段式接口与函数原型aclnnAddV3 和 aclnnInplaceAddV3 实现相同的计算功能使用时按输出方式区分aclnnAddV3需要新建一个输出张量对象out存储计算结果aclnnInplaceAddV3无需新建输出张量对象直接在输入张量other的内存中存储计算结果此时other既是输入也是输出。每个算子均采用 两段式接口 的调用范式必须先调用 GetWorkspaceSize 第一段接口获取计算所需 workspace 大小以及包含了算子计算流程的执行器aclOpExecutor再调用第二段接口执行计算。两段式接口的通用形式如下aclnnStatus aclxxXxxGetWorkspaceSize(const aclTensor *src, ..., aclTensor *out, ..., uint64_t *workspaceSize, aclOpExecutor **executor); aclnnStatus aclxxXxx(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream);其中 workspace 是指除输入/输出外算子在 NPU 上完成计算所需的临时内存第二段接口不能重复调用同一 executor 多次执行会出现异常。对应到本算子头文件声明见 math/add/op_api/aclnn_add_v3.hdomain aclnn_math原型如下。aclnnAddV3 第一段接口计算 workspace 大小aclnnStatus aclnnAddV3GetWorkspaceSize( const aclScalar* self, const aclTensor* other, const aclScalar* alpha, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)aclnnAddV3 第二段接口执行计算aclnnStatus aclnnAddV3( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)aclnnInplaceAddV3 第一段接口aclnnStatus aclnnInplaceAddV3GetWorkspaceSize( const aclScalar* selfRef, const aclTensor* other, const aclScalar* alpha, uint64_t* workspaceSize, aclOpExecutor** executor)aclnnInplaceAddV3 第二段接口aclnnStatus aclnnInplaceAddV3( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)从源码实现看inplace 版本的第一段接口实际上就是把other同时当作输出out直接转调 aclnnAddV3 的第一段接口aclnnStatus aclnnInplaceAddV3GetWorkspaceSize(...) { auto out const_castaclTensor*(other); return aclnnAddV3GetWorkspaceSize(selfRef, other, alpha, out, workspaceSize, executor); }这也是为什么 inplace 版本的参数表里other被标注为输入/输出的原因。aclnnAddV3GetWorkspaceSize 参数说明第一段接口的详细参数如下参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorselfaclScalar*输入公式中的输入 self数据类型与 other 的数据类型需满足数据类型推导规则参见互推导关系FLOAT、FLOAT16、INT32、INT8、BFLOAT16---otheraclTensor*输入公式中的输入 other数据类型与 self 的数据类型需满足数据类型推导规则参见互推导关系shape 需要与 out 的 shape 一致FLOAT、FLOAT16、INT32、INT8、BFLOAT16ND0-8√alphaaclScalar*输入公式中的 alpha数据类型需要可转换成 self 与 other 推导后的数据类型FLOAT、FLOAT16、INT32、INT8、BFLOAT16---outaclTensor*输出公式中的 out数据类型需要是 self 与 other 推导之后可转换的数据类型参见互转换关系shape 需要与 other 的 shape 一致FLOAT、FLOAT16、INT32、INT8、BFLOAT16ND0-8√workspaceSize输出返回需要在 Device 侧申请的 workspace 大小-----executor输出返回 op 执行器包含了算子计算流程-----要点解读支持的数据类型集中在 FLOATfloat32、FLOAT16、INT32、INT8、BFLOAT16 五类与源码中ADD_V3_DTYPE_SUPPORT_LIST的定义完全一致aclnn_add_v3.cpp 第 58-60 行static const std::initializer_listop::DataType ADD_V3_DTYPE_SUPPORT_LIST { op::DataType::DT_FLOAT, op::DataType::DT_INT32, op::DataType::DT_FLOAT16, op::DataType::DT_BF16, op::DataType::DT_INT8};other/out 支持非连续 Tensor表格中标注 √shape 允许 0-8 维格式为 ND。这是源码在计算流程末尾显式插入ViewCopy将结果写回可能非连续的输出张量的原因。空 Tensor源码中对other-IsEmpty()做了特判此时无需 workspace*workspaceSize 0直接返回成功空 tensor 计算由 kernel 层支持。数据类型推导互推导当 self 与 other 数据类型不一致时API 内部会按类似 PyTorch Type Promotion 的规则推导出一个公共计算类型并将输入转换到该类型后再计算完整的推导关系表见 互推导关系。例如 self 为 FLOAT16、other 为 FLOAT 时会推导为 FLOAT 计算。数据类型转换互转换计算类型与输出 out 类型不一致时API 会将计算结果转换成 out 的数据类型。转换需满足互转换关系整数类型间可转换、浮点类型间可转换、BOOL 可转整数/浮点/复数等不满足规则的转换会导致参数校验失败。返回值与第一段接口的入参校验返回类型为aclnnStatus返回状态码详见 aclnn返回码。第一段接口GetWorkspaceSize会完成入参校验出现以下场景时报错返回值错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 self、other、alpha 或 out 是空指针ACLNN_ERR_PARAM_INVALID161002other 的数据类型不在支持的范围之内ACLNN_ERR_PARAM_INVALID161002self 和 other 无法做数据类型推导ACLNN_ERR_PARAM_INVALID161002推导出的数据类型无法转换为指定输出 out 的类型ACLNN_ERR_PARAM_INVALID161002alpha 无法转换为 self 和 other 推导后的数据类型ACLNN_ERR_PARAM_INVALID161002other 的 shape 与 out 的 shape 不一致ACLNN_ERR_PARAM_INVALID161002other 的维度大于 8上述校验逻辑在源码 CheckParams 中可逐一对应先做CheckNotNull空指针检查返回ACLNN_ERR_PARAM_NULLPTR再检查 other 的 dtype 是否落在支持列表内、通过PromoteTypeScalarCheckPromoteType校验推导与转换关系其中CanCast不满足时返回ACLNN_ERR_PARAM_INVALID最后通过CheckShape校验维度不超过MAX_DIM_LEN8 维且 other/out 的 shape 一致。aclnnAddV3 参数说明第二段接口第二段接口负责真正把算子任务提交到指定 Stream 上执行参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnAddV3GetWorkspaceSize 获取executor输入op 执行器包含了算子计算流程stream输入指定执行任务的 Stream返回值为aclnnStatus状态码含义参见 aclnn返回码。源码中第二段接口的实现非常简洁固定调用框架的公共执行能力完成计算aclnnStatus aclnnAddV3(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream) { L2_DFX_PHASE_2(aclnnAddV3); return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); }aclnnInplaceAddV3GetWorkspaceSize 参数说明inplace 版本不需要 out 参数因为输出直接覆盖在other上参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorselfRefaclScalar*输入公式中的输入 self数据类型与 other 的数据类型需满足数据类型推导规则参见互推导关系FLOAT、FLOAT16、INT32、INT8、BFLOAT16---otheraclTensor*输入/输出输入输出 tensor即公式中的 other 与 out数据类型与 selfRef 的数据类型需满足数据类型推导规则参见互推导关系并且数据类型需要是 selfRef 与 other 推导之后可转换的数据类型参见互转换关系FLOAT、FLOAT16、INT32、INT8、BFLOAT16ND0-8√alphaaclScalar*输入公式中的 alpha数据类型需要可转换成 selfRef 与 other 推导后的数据类型FLOAT、FLOAT16、INT32、INT8、BFLOAT16---workspaceSize输出返回需要在 Device 侧申请的 workspace 大小-----executor输出返回 op 执行器包含了算子计算流程-----产品限制在 Atlas 训练系列产品 、 Atlas 推理系列产品 上本接口不支持 BFLOAT16 数据类型注意结合前文产品支持情况这两个系列本身就不支持 aclnnInplaceAddV3此处的附加限制进一步约束了历史 910/310P 平台上的使用边界。返回值与入参校验返回类型为aclnnStatus错误场景如下返回值错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 selfRef、other 或 alpha 是空指针ACLNN_ERR_PARAM_INVALID161002other 的数据类型不在支持的范围之内ACLNN_ERR_PARAM_INVALID161002selfRef 和 other 无法做数据类型推导ACLNN_ERR_PARAM_INVALID161002推导出的数据类型无法转换为 other 的类型ACLNN_ERR_PARAM_INVALID161002alpha 无法转换为 selfRef 和 other 推导后的数据类型ACLNN_ERR_PARAM_INVALID161002other 的维度大于 8由于 inplace 版本将other同时作为输出因此校验规则中推导出的数据类型无法转换为输出类型这一条对应的输出类型就是other本身的类型这与 aclnnAddV3 中针对显式out参数的校验在语义上完全一致。aclnnInplaceAddV3 参数说明第二段接口参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnInplaceAddV3GetWorkspaceSize 获取executor输入op 执行器包含了算子计算流程stream输入指定执行任务的 Stream返回值同样为aclnnStatus。约束说明确定性计算aclnnAddV3 与 aclnnInplaceAddV3 默认即为确定性实现即相同输入多次调用会得到完全一致的输出结果不引入随机性。关于确定性计算的更多背景可参见 确定性计算。源码级原理剖析从参数到算子的完整计算流程结合 aclnn_add_v3.cpp 源码第一段接口内部完整计算流程如下self other | | \ / Contiguous(workspace_0) Contiguous(workspace_2) \ / Cast(workspace_1) Cast(workspace_3) \ / Add(workspace_4) | Cast(workspace_5) | ViewCopy | result各步骤要点Contiguous将可能非连续的输入other转换为连续 tensorl0op::Contiguous。Cast将other转换为推导出的公共计算类型self标量通过ConvertToTensor转成张量参与计算。加法分支关键优化点当alpha等于 1 时!(alpha-ToFloat() 1 || alpha-ToFloat() 1)跳过乘法直接执行Add(self, otherCasted)避免一次多余的 Mul 计算当推导后的类型支持 AXPY源码中AXPY_DTYPE_SUPPORT_LIST {DT_FLOAT, DT_INT32, DT_FLOAT16}即IsSupportAxpy时调用l0op::Axpy将乘系数再相加融合为一步这也是本算子AddV3区别于普通 Add 的核心所在对应 math/axpy 模块否则退化为Mul(otherCasted, alphaTensor)再Add(self, otherRes)的两步实现。Cast将计算结果转换为输出out的数据类型满足互转换关系。ViewCopy将结果写回输出outout 可能是非连续 tensor。workspace 汇总通过uniqueExecutor-GetWorkspaceSize()汇总全流程所需临时内存大小并把 executor 转移给调用方。因此本算子在底层实际是一个复合算子流程workspace 大小会随数据类型、是否连续、alpha 取值是否走 Axpy 融合分支等因素变化——这也是两段式接口必须先调用 GetWorkspaceSize 的原因。调用示例完整可编译示例代码来自文档可在安装 aclnnop 头文件与运行环境后直接编译执行。以下代码在一个 main 中先后演示 aclnnAddV3 与 aclnnInplaceAddV3 的完整调用链路具体编译与运行流程参考编译与运行样例。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_add_v3.h #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vectorint64_t shape) { int64_t shapeSize 1; for (auto i : shape) { shapeSize * i; } return shapeSize; } int Init(int32_t deviceId, aclrtStream* stream) { // 固定写法资源初始化 auto ret aclInit(nullptr); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclInit failed. ERROR: %d\n, ret); return ret); ret aclrtSetDevice(deviceId); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSetDevice failed. ERROR: %d\n, ret); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); return ret); return 0; } template typename T int CreateAclTensor(const std::vectorT hostData, const std::vectorint64_t shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 auto ret aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMalloc failed. ERROR: %d\n, ret); return ret); // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 ret aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMemcpy failed. ERROR: %d\n, ret); return ret); // 计算连续tensor的strides std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1.固定写法device/stream初始化参考acl API手册 // 根据自己的实际device填写deviceId int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出需要根据API的接口自定义构造 std::vectorint64_t otherShape {4, 2}; std::vectorint64_t outShape {4, 2}; void* otherDeviceAddr nullptr; void* outDeviceAddr nullptr; aclScalar* self nullptr; aclTensor* other nullptr; aclScalar* alpha nullptr; aclTensor* out nullptr; std::vectorfloat otherHostData {1, 1, 1, 2, 2, 2, 3, 3}; std::vectorfloat outHostData(8, 0); float selfValue 1.2f; float alphaValue 1.2f; // 创建self aclScalar self aclCreateScalar(selfValue, aclDataType::ACL_FLOAT); CHECK_RET(self ! nullptr, return ret); // 创建other aclTensor ret CreateAclTensor(otherHostData, otherShape, otherDeviceAddr, aclDataType::ACL_FLOAT, other); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建alpha aclScalar alpha aclCreateScalar(alphaValue, aclDataType::ACL_FLOAT); CHECK_RET(alpha ! nullptr, return ret); // 创建out aclTensor ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_FLOAT, out); CHECK_RET(ret ACL_SUCCESS, return ret); uint64_t workspaceSize 0; aclOpExecutor* executor; // aclnnAddV3接口调用示例 // 3. 调用CANN算子库API // 调用aclnnAddV3第一段接口 ret aclnnAddV3GetWorkspaceSize(self, other, alpha, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnAddV3GetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 void* workspaceAddr nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); } // 调用aclnnAddV3第二段接口 ret aclnnAddV3(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnAddV3 failed. ERROR: %d\n, ret); return ret); // 4.固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 获取输出的值将device侧内存上的结果拷贝至host侧需要根据具体API的接口定义修改 auto size GetShapeSize(outShape); std::vectorfloat resultData(size, 0); ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy result from device to host failed. ERROR: %d\n, ret); return ret); for (int64_t i 0; i size; i) { LOG_PRINT(result[%ld] is: %f\n, i, resultData[i]); } // aclnnInplaceAddV3接口调用示例 // 3. 调用CANN算子库API LOG_PRINT(\ntest aclnnInplaceAddV3\n); // 调用aclnnInplaceAddV3第一段接口 ret aclnnInplaceAddV3GetWorkspaceSize(self, other, alpha, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnInplaceAddV3GetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); } // 调用aclnnInplaceAddV3第二段接口 ret aclnnInplaceAddV3(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnInplaceAddV3 failed. ERROR: %d\n, ret); return ret); // 4.固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 获取输出的值将device侧内存上的结果拷贝至host侧需要根据具体API的接口定义修改 ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), otherDeviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy result from device to host failed. ERROR: %d\n, ret); return ret); for (int64_t i 0; i size; i) { LOG_PRINT(result[%ld] is: %f\n, i, resultData[i]); } // 6. 释放aclTensor和aclScalar需要根据具体API的接口定义修改 aclDestroyScalar(self); aclDestroyTensor(other); aclDestroyScalar(alpha); aclDestroyTensor(out); // 7. 释放Device资源需要根据具体API的接口定义修改 aclrtFree(otherDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }对示例代码的要点说明调用范式固定为七步资源初始化 → 构造输入输出 → 第一段接口取 workspace → 申请 workspace 内存 → 第二段接口执行 → 同步等待 → 资源释放。CreateAclTensor辅助函数封装了申请 device 内存 → H2D 拷贝 → 计算连续 strides → aclCreateTensor的完整流程其中aclCreateTensor的最后一个参数为 device 侧数据地址。对于 inplace 分支结果直接通过otherDeviceAddr从 device 侧拷回 host无需读取 out。若workspaceSize 0例如空 tensor 场景可跳过 workspace 申请直接传入空指针调用第二段接口。编译时需链接libascendcl.so、libnnopbase.so、libopapi_math.so等库可参考 编译与运行样例 中的 CMakeLists 配置含include/aclnn头文件目录。测试与验证仓库提供了与本接口配套的单元测试与端到端测试可作为理解参数语义与校验行为的参考math/add/tests/ut/op_api/test_aclnn_add_v3.cpp覆盖正常场景如 shape{1,16,1,1}的 FLOAT 输入调用aclnnAddV3GetWorkspaceSize返回ACLNN_SUCCESS以及空指针入参返回ACLNN_ERR_PARAM_NULLPTR的负例校验与上文错误码表格一一对应。math/add/tests/ut/op_api/test_aclnn_inplace_add.cpp对应 inplace 版本接口的测试。math/add/tests/st/aclnnAddV3/atk_aclnnAddV3.jsonATK 框架下的 ST系统测试配置用于在真实 NPU 环境上验证算子输出正确性。此外 math/add/examples/test_aclnn_add.cpp 提供了 aclnnAdd/aclnnInplaceAdd不带 alpha 系数的版本的参考样例可与 AddV3 对照理解两者差异。总结aclnnAddV3 / aclnnInplaceAddV3 是 Ascend 950 平台上实现out self alpha * other的标准单算子 API两者共享同一套两段式调用范式与类型推导/转换规则区别仅在于输出是显式新建out还是就地覆盖other。源码层面该算子并非单一 kernel而是由 Contiguous → Cast → Add/Axpy/Mul → Cast → ViewCopy 组成的复合流程并在 alpha1 与可融合 AXPY 的场景下做了计算优化所有入参合法性均在第一段 GetWorkspaceSize 接口中完成校验。按本文的七步调用模板与参数约束即可在 NPU 上快速完成带缩放系数的加法运算。赞分享算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载相关推荐CANN ops-math 算子指南aclnnAddr 与 aclnnInplaceAddr 向量外积融合算子外积-加-缩放使用详解CANN ops math 算子指南aclnnAddr 与 aclnnInplaceAddr 向量外积融合算子外积 加 缩放使用详解 导读 本文围绕 CA算子库人工智能CANNCANN ops-math 算子开发指南aclnnBiasAdd 单算子接口详解与调用实践CANN ops math 算子开发指南aclnnBiasAdd 单算子接口详解与调用实践 本指南以 CANN ops math 开源仓库中 experime算子库人工智能CANNCANN ops-math 算子 C APIasc_simd开发实战以 AddExampleCApi 加法算子为例CANN ops math 算子 C APIasc_simd开发实战以 AddExampleCApi 加法算子为例 导读 本文基于 examples/ad算子库人工智能CANN上一篇DexHunter终极Android Dex文件自动脱壳工具一键破解加固难题下一篇突破数据库性能瓶颈DBeaver多线程查询监控实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考