恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

CANN ops-math 张量标量加法算子 aclnnAdds 与 aclnnInplaceAdds 完整实战指南

  • 首页
  • 资讯中心
  • /
  • CANN ops-math 张量标量加法算子 aclnnAdds 与 aclnnInplaceAdds 完整实战指南

相关资讯

OpenResearch实战:Claude Code、Codex、OpenCode与Cursor工具链协同指南 2026/9/20 9:05:17
GitHub热榜上的迷你小模型:本地部署与量化实践指南 2026/9/20 9:05:17
Qt for MCUs 2.11 LTS 与 Qt 5.15.19:嵌入式 GUI 的进与退 2026/9/20 9:05:17

最新资讯

QQ空间备份教程:5 分钟扫一次码,历史说说 Excel+网页全量导出
Python多线程为何越跑越慢?一文讲透GIL与并发选型
PPTAgent 走 MCP 出学术 PPT,Token 老不够用?TaoToken 这样改模型地址
QTextBrowser 加载脚本高亮不一致,把 Codex 的 Base URL 改到 TaoToken 后排查
给Homebrew套上图形界面:BrewUI开发实践与踩坑记录
AI赋能冒烟测试:从用例生成到结果判定的全流程智能化落地实践

今日推荐

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

CANN ops-math 张量标量加法算子 aclnnAdds 与 aclnnInplaceAdds 完整实战指南

发布时间:2026/9/20 9:05:17
CANN ops-math 张量标量加法算子 aclnnAdds 与 aclnnInplaceAdds 完整实战指南 CANN ops-math 张量标量加法算子 aclnnAdds 与 aclnnInplaceAdds 完整实战指南【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-mathaclnnAdds / aclnnInplaceAdds 是 CANN ops-math 算子库中 Add 系列面向张量 标量场景的 aclnn 单算子 API实现了out self alpha × other的带缩放标量加法语义。本文以 math/add/docs/aclnnAddsaclnnInplaceAdds.md 为骨架结合 math/add/op_api/aclnn_add.cpp 的源码实现与 math/add/tests/st/aclnnAdds/atk_aclnnAdds.json 的测试用例完整讲解接口原型、参数约束、两段式调用流程、底层计算图构建原理与可直接编译运行的调用示例帮助开发者在 Ascend NPU 上快速、正确地完成张量加标量的加速计算。产品支持情况根据官方文档与 math/add/README.md 的算子说明aclnnAdds 与 aclnnInplaceAdds 在以下产品上支持情况如下产品支持情况Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品支持Atlas 训练系列产品支持注意aclnnAdds与aclnnInplaceAdds在 Atlas 推理系列产品310p上支持而双张量版本的aclnnAdd/aclnnInplaceAdd在该产品上不支持选用接口时请按目标硬件核对支持矩阵。功能说明接口功能完成张量 标量的加法计算其中标量可以乘以缩放系数alpha。计算公式$$ out_i self_i alpha \times other $$其中self为张量other与alpha均为标量aclScalar。当alpha 1时公式退化为out self other此时接口内部会走专门的快速路径见下文源码分析。该接口语义与 PyTorch 的torch.add(input, other, alpha1)张量加标量形式一致从 atk_aclnnAdds.json 的测试用例可以看出其基准对标函数即torch.add。函数原型与两段式接口aclnnAdds与aclnnInplaceAdds实现相同的计算功能二者的区别仅在于输出结果的存储方式aclnnAdds需要调用方新建一个输出张量对象out来存储计算结果输入张量在计算前后保持不变。aclnnInplaceAdds无需新建输出张量对象直接在输入张量selfRef的内存中就地写入计算结果可减少一次输出张量的内存申请与搬运。与 CANN 单算子 API 的通用规范一致每个算子都遵循两段式接口设计必须先调用第一段...GetWorkspaceSize接口获取本次计算所需的 workspace 大小以及封装了算子计算流程的执行器aclOpExecutor再调用第二段接口执行真正的计算。两段式接口的完整形态如下// aclnnAdds 第一段参数校验 获取 workspace 大小与执行器 aclnnStatus aclnnAddsGetWorkspaceSize( const aclTensor* self, // 输入张量 const aclScalar* other, // 输入标量 const aclScalar* alpha, // 缩放标量 aclTensor* out, // 输出张量 uint64_t* workspaceSize, // 输出workspace 大小 aclOpExecutor** executor) // 输出算子执行器 // aclnnAdds 第二段执行计算 aclnnStatus aclnnAdds( void* workspace, // Device 侧申请的 workspace 内存地址 uint64_t workspaceSize, // 由第一段接口获取的大小 aclOpExecutor* executor, // 第一段接口返回的执行器 aclrtStream stream) // 指定执行任务的 Stream // aclnnInplaceAdds 第一段 aclnnStatus aclnnInplaceAddsGetWorkspaceSize( const aclTensor *selfRef, // 输入/输出张量结果写回该张量 const aclScalar *other, const aclScalar *alpha, uint64_t *workspaceSize, aclOpExecutor **executor) // aclnnInplaceAdds 第二段 aclnnStatus aclnnInplaceAdds( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)关于两段式接口需要特别注意的是workspace 是指除输入/输出外算子在 NPU 上完成计算所需的临时内存workspaceSize表示该临时内存的大小具体数值由第一段接口根据计算图动态推算第一段接口仅做入参校验与计算图构建不会真正执行计算第二段接口aclnnAdds(...)不能重复调用同一个 executor 调用两次属于异常用法若workspaceSize为 0则无需申请 workspace第二段接口可直接传入nullptr。aclnnAddsGetWorkspaceSize 参数说明参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensorself输入公式中的输入 self-FLOAT、FLOAT16、DOUBLE、INT32、INT64、INT16、INT8、UINT8、BOOL、COMPLEX128、COMPLEX64、BFLOAT16ND不高于8维√other输入公式中的 other标量-FLOAT、FLOAT16、DOUBLE、INT32、INT64、INT16、INT8、UINT8、BOOL、COMPLEX128、COMPLEX64、BFLOAT16---alpha输入公式中的 alpha标量数据类型需要可转换成 self 与 other 推导后的数据类型FLOAT、FLOAT16、DOUBLE、INT32、INT64、INT16、INT8、UINT8、BOOL、COMPLEX128、COMPLEX64、BFLOAT16---out输出公式中的 out数据类型需要是 self 与 other 推导之后可转换的数据类型参见互转换关系FLOAT、FLOAT16、DOUBLE、INT32、INT64、INT16、INT8、UINT8、BOOL、COMPLEX128、COMPLEX64、BFLOAT16ND与 self 一致√workspaceSize输出返回需要在 Device 侧申请的 workspace 大小-----executor输出返回 op 执行器包含了算子计算流程-----不同产品上的类型约束差异Atlas 推理系列产品、Atlas 训练系列产品不支持 BFLOAT16 数据类型self 与 other 数据类型需满足互推导关系。Atlas A2 训练系列产品 / Atlas A2 推理系列产品、Atlas A3 训练系列产品 / Atlas A3 推理系列产品self 与 other 数据类型需满足互推导关系。Ascend 950PR / Ascend 950DTother 数据类型与 self 需满足 TensorScalar 互推导关系。返回值aclnnStatus返回状态码具体参见 aclnn返回码。第一段接口完成入参校验出现以下场景时报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 self、other、out 或 alpha 是空指针。ACLNN_ERR_PARAM_INVALID161002self 的数据类型不在支持的范围之内。ACLNN_ERR_PARAM_INVALID161002self 和 other 无法做数据类型推导。ACLNN_ERR_PARAM_INVALID161002推导出的数据类型无法转换为 out 的类型。ACLNN_ERR_PARAM_INVALID161002alpha 无法转换为 self 和 other 推导后的数据类型。ACLNN_ERR_PARAM_INVALID161002self 与 out 的 shape 不一致。ACLNN_ERR_PARAM_INVALID161002self 与 out 的维度大于 8。说明ACLNN_ERR_PARAM_NULLPTR161001与ACLNN_ERR_PARAM_INVALID161002均为参数校验类错误运行时类错误以361xxx开头API 内部异常以561xxx开头完整的错误码语义可查阅 docs/zh/context/aclnn_return_code.md。aclnnAdds 参数说明参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址。workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnAddsGetWorkspaceSize 获取。executor输入op 执行器包含了算子计算流程。stream输入指定执行任务的 Stream。返回值aclnnStatus具体参见 aclnn返回码。aclnnInplaceAddsGetWorkspaceSize 参数说明参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorselfRef输入/输出公式中的输入 selfRef计算完成后结果直接写回该张量-FLOAT、FLOAT16、DOUBLE、INT32、INT64、INT16、INT8、UINT8、BOOL、BFLOAT16ND不超过8维√other输入公式中的 other标量-FLOAT、FLOAT16、DOUBLE、INT32、INT64、INT16、INT8、UINT8、BOOL、BFLOAT16---alpha输入公式中的 alpha标量数据类型需要可转换成 selfRef 与 other 推导后的数据类型FLOAT、FLOAT16、DOUBLE、INT32、INT64、INT16、INT8、UINT8、BOOL、BFLOAT16---workspaceSize输出返回需要在 Device 侧申请的 workspace 大小-----executor输出返回 op 执行器包含了算子计算流程-----不同产品上的类型约束差异Atlas 训练系列产品不支持 BFLOAT16 数据类型selfRef 与 other 需满足互推导关系且需要是推导之后可转换的数据类型参见互转换关系。Atlas A2 训练系列产品 / Atlas A2 推理系列产品、Atlas A3 训练系列产品 / Atlas A3 推理系列产品selfRef 与 other 需满足互推导关系且需要是推导之后可转换的数据类型。Ascend 950PR / Ascend 950DTselfRef 与 other 需满足 TensorScalar 互推导关系且需要是推导之后可转换的数据类型。返回值aclnnStatus返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 selfRef、other 或 alpha 是空指针。ACLNN_ERR_PARAM_INVALID161002selfRef 的数据类型不在支持的范围之内。ACLNN_ERR_PARAM_INVALID161002selfRef 和 other 无法做数据类型推导。ACLNN_ERR_PARAM_INVALID161002推导出的数据类型无法转换为 selfRef 的类型。ACLNN_ERR_PARAM_INVALID161002alpha 无法转换为 selfRef 和 other 推导后的数据类型。aclnnInplaceAdds 参数说明参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址。workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnInplaceAddsGetWorkspaceSize 获取。executor输入op 执行器包含了算子计算流程。stream输入指定执行任务的 Stream。返回值aclnnStatus具体参见 aclnn返回码。约束说明确定性计算aclnnAdds 与 aclnnInplaceAdds 默认采用确定性实现同一输入下多次执行结果可复现。精度约束other参数对于 float 无精度损失对于 int32、int64 数据类型当other参数大于 2^24 时可能存在精度损失。此时推荐改用双张量版本的 aclnnAdd / aclnnInplaceAdd避免标量精度损失问题。源码级实现解析理解了接口与约束后我们再深入 math/add/op_api/aclnn_add.cpp看第一段接口内部到底做了什么。这有助于理解参数校验规则和 workspace 的来源。第一段接口的完整流程aclnnAddsGetWorkspaceSize的源码实现aclnn_add.cpp大致分为以下几个步骤创建执行器调用框架宏CREATE_EXECUTOR()创建aclOpExecutor失败返回ACLNN_ERR_INNER_CREATE_EXECUTOR。入参校验调用CheckParamsScalar完成空指针、数据类型、推导关系、shape 一致性等全部校验该校验逻辑与文档中的错误码表格一一对应。空张量短路若self-IsEmpty()直接返回workspaceSize 0并释放执行器kernel 层支持空张量。类型推导与计算图构建根据PromoteTypeScalar推导出的计算类型promoteType将标量other通过ConvertToTensor转换为张量然后按分支构建计算图见下文。结果类型转换与写回将计算结果Cast为out的数据类型再通过ViewCopy写入输出张量out 可能是非连续张量。返回 workspace通过uniqueExecutor-GetWorkspaceSize()汇总整张计算图所需临时内存并通过ReleaseTo(executor)将执行器所有权转移给调用方。标量类型推导规则 PromoteTypeScalarPromoteTypeScalaraclnn_add.cpp负责确定self张量与other标量参与运算的最终计算类型若self为浮点类型FLOAT推导结果直接取self的类型若推导结果为 FLOAT16 或 BFLOAT16则进一步检查other与alpha是否能无损转成该半精度类型若不能则提升为 FLOAT避免精度损失若推导出 COMPLEX32则统一提升为 COMPLEX64若self为 BOOL 或other为浮点类型则按op::PromoteType通用推导规则计算。这也解释了文档中alpha 的数据类型需要可转换成 self 与 other 推导后的数据类型这一约束的来历——CheckPromoteType会调用CanCast校验 alpha 能否无损转换到推导类型。计算图构建的四种分支aclnnAddsGetWorkspaceSize在构建计算图时会针对不同情况选择不同的底层算子组合aclnn_add.cpp分支条件底层计算图说明alpha 等于 1Add(self, other)免去标量乘法直接调用 L0 层 Add支持 AxpyAxpy(self, other, alpha)将 乘加 融合为单算子性能最优支持 AxpyV2仅 RegBase 架构AxpyV2(self, other, alphaTensor)alpha 以张量形式传入的融合乘加其他情况Mul(other, alphaTensor)后再Add(self, otherRes)通用拆解路径其中IsEqualToOneaclnn_add.cpp用于判断 alpha 是否等于 1IsSupportAxpy/IsSupportAxpyV2依据当前 NPU 架构与推导类型决定能否走融合算子。此外在进入上述分支前源码还会视需要插入Contiguous转连续张量与Cast隐式类型转换节点在输出侧统一追加Cast转回 out 类型与ViewCopy写回输出节点。整个流程可以概括为self / other(标量) ── Contiguous ── Cast(promoteType) └─ Add / Axpy / AxpyV2 / MulAdd │ v Cast(out类型) ── ViewCopy ── out一个值得注意的细节是 BOOL 类型的特殊处理aclnn_add.cpp当 self、other、alpha 均为 BOOL 且 out 非 BOOL、other alpha为真时会额外插入一次Cast 到 BOOL 再 Cast 回来的中间节点防止 BOOL 相加出现值为 2 的错误结果。Inplace 版本的实现方式aclnnInplaceAddsGetWorkspaceSize的实现非常简洁aclnn_add.cpp它将selfRef通过const_cast直接作为out传入aclnnAddsGetWorkspaceSize复用同一套校验与构图逻辑最终计算结果通过ViewCopy写回selfRef所在的内存。这就是就地计算、无需新建输出张量的实现本质。从更底层的 L0 视角看l0op::Add会先对self与other做 broadcast shape 推导若输入为混合数据类型如 FP16FP32、BF16FP32则自动输出 FLOAT 类型中间结果见 math/add/op_api/add.cpp而AddInplace则额外校验 broadcast 后的 shape 必须与输出张量一致add.cpp。测试用例佐证atk_aclnnAdds.json 中的 ATKAscend Test Kit用例以torch.add为基准函数覆盖了 fp32、fp16、bf16、fp64、int8、int16、int32、int64、bool 等数据类型shape 覆盖 1~4 维与[1,1,1,1]等边界形态以及nan、inf、-inf、[-inf, inf]等特殊输入值。其中绝大部分用例将alpha固定为 1对应alpha 等于 1 走快速路径的分支同时也有alpha为一般值的用例覆盖通用 MulAdd 路径可作为回归验证的参考。调用示例以下示例代码来自仓库 math/add/examples/test_aclnn_adds.cpp在同一程序中依次演示aclnnAdds输出到新建张量 out与aclnnInplaceAdds结果写回 self 内存的完整调用流程。具体编译和执行过程请参考编译与运行样例。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_add.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); aclFinalize(); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); aclrtResetDevice(deviceId); aclFinalize(); 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 selfShape {4, 2}; std::vectorint64_t outShape {4, 2}; void* selfDeviceAddr nullptr; void* outDeviceAddr nullptr; aclTensor* self nullptr; aclScalar* other nullptr; aclScalar* alpha nullptr; aclTensor* out nullptr; std::vectorfloat selfHostData {0, 1, 2, 3, 4, 5, 6, 7}; std::vectorfloat outHostData(8, 0); float otherValue 2.0f; float alphaValue 1.2f; // 创建self aclTensor ret CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_FLOAT, self); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建other aclScalar other aclCreateScalar(otherValue, aclDataType::ACL_FLOAT); CHECK_RET(other ! nullptr, 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); // 3. 调用CANN算子库API需要修改为具体的API名称 uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnAdds第一段接口 ret aclnnAddsGetWorkspaceSize(self, other, alpha, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnAddsGetWorkspaceSize 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); } // 调用aclnnAdds第二段接口 ret aclnnAdds(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnAdds 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]); } // aclnnInplaceAdds接口调用示例 // 3. 调用CANN算子库API LOG_PRINT(\ntest aclnnInplaceAdds\n); // 调用aclnnInplaceAdds第一段接口 ret aclnnInplaceAddsGetWorkspaceSize(self, other, alpha, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnInplaceAddsGetWorkspaceSize 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); } // 调用aclnnInplaceAdds第二段接口 ret aclnnInplaceAdds(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnInplaceAdds 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]), selfDeviceAddr, 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的接口定义修改 aclDestroyTensor(self); aclDestroyScalar(other); aclDestroyScalar(alpha); aclDestroyTensor(out); // 7. 释放device资源 aclrtFree(selfDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例运行结果说明输入self {0,1,2,3,4,5,6,7}、other 2.0、alpha 1.2则out_i self_i 1.2 × 2.0 self_i 2.4aclnnAdds输出{2.4, 3.4, 4.4, 5.4, 6.4, 7.4, 8.4, 9.4}随后aclnnInplaceAdds基于已被修改的 self 再执行一次同样的运算结果{4.8, 5.8, 6.8, 7.8, 8.8, 9.8, 10.8, 11.8}写回 self 内存。该示例同时演示了两段式接口的固定套路初始化 → 构造张量/标量 → 第一段取 workspace → 按需申请 Device 内存 → 第二段执行 → 同步 Stream → 拷贝结果 → 释放资源。示例关键点提示头文件#include aclnnop/aclnn_add.h是 aclnnAdds / aclnnInplaceAdds 等 Add 系列接口的声明头文件。标量创建other与alpha都通过aclCreateScalar(value, aclDataType::ACL_FLOAT)创建需要传入值的指针与数据类型示例中将其声明为aclScalar*并通过aclDestroyScalar释放。workspace 申请只有workspaceSize 0时才需要aclrtMalloc申请 Device 内存否则workspaceAddr保持nullptr即可。Inplace 语义aclnnInplaceAddsGetWorkspaceSize只接受selfRef、other、alpha三个参数没有 out计算完成后从selfDeviceAddr对应的内存读取结果。总结aclnnAdds / aclnnInplaceAdds 是 ops-math 中张量 标量场景的标准解法二者语义相同、仅输出方式不同前者需要独立输出张量后者直接原地写回输入。掌握其两段式接口调用范式GetWorkspaceSize → 申请 workspace → 执行 → 同步理解第一段接口内部的类型推导、alpha1 快速路径、Axpy 融合与 Inplace 复用机制即可在目标 NPU 产品上高效、正确地完成带缩放系数的标量加法计算。若需对 Add 系列算子有更全面的了解可继续阅读双张量版本的 aclnnAdd / aclnnInplaceAdd 文档或查看底层 kernel 实现 math/add/op_kernel、tiling 配置 math/add/op_host/config 与单元测试 math/add/tests。【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-math创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号