Ascend C 高阶 API 实战:Sum 算子样例逐行解析与编译运行指南 人工智能深度学习算子库CANNAscend【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址https://gitcode.com/cann/asc-devkit点击查看免费下载导读本文以asc-devkit仓库中 Sum 样例 为主线讲解 Ascend CSum高阶 API 如何对输入数据按最后一个维度内轴求和一维向量对全部元素求和矩阵则逐行求和。通过本文读者将掌握Sum/Mean高阶 API 的调用方式、SumParams参数结构、GetSumMaxMinTmpSize临时空间计算方法以及一套可复制的单核固定 shape 算子工程骨架tiling 生成 → 数据搬运 → 向量归约 → 精度校验与编译运行流程。样例功能概述本样例演示Sum高阶 API 的基本用法。以固定 shape 为例输入src[3, 32]float、ND 格式输出dst[8, 1]float、ND 格式。计算时对输入矩阵的每一行元素求和即沿最后一个维度做归约输出中前 3 位为有效数据对应 3 行各自的求和结果最后 5 位为 padding 填充数据。接口提示除Sum外Ascend C 还提供语义完全一致的Mean接口用于求平均值。切换方式非常简单将sum.asc中的AscendC::Sum替换为AscendC::Mean同时把GetSumMaxMinTmpSize替换为GetMeanMaxMinTmpSize即可。支持的产品及 CANN 软件版本产品CANN软件版本Ascend 950PR950DT系列产品 CANN 9.1.0Atlas A3系列产品 CANN 9.0.0Atlas A2系列产品 CANN 9.0.0目录结构与工程骨架├── sum │ ├── scripts │ │ └── gen_data.py // 生成数据和真值数据的生成脚本 │ ├── CMakeLists.txt // 编译工程文件 │ ├── data_utils.h // 数据读写工具函数 │ ├── sum.asc // Ascend C样例实例 主程序 │ └── README.md // 样例说明文档工程骨架由四部分构成sum.asc算子核函数 主机侧main程序、data_utils.hReadFile/WriteFile二进制读写工具、scripts/gen_data.py随机输入与 golden 真值生成、CMakeLists.txtASC 语言编译工程配置。这是一个典型的单文件单核样例结构适合作为学习高阶 API 的起点。编译工程配置要点CMakeLists.txt 展示了 ASC 语言工程的构建方式find_package(ASC REQUIRED) project(kernel_samples LANGUAGES ASC CXX) add_executable(demo sum.asc) set(CMAKE_ASC_ARCHITECTURES dav-2201 CACHE STRING CMAKE_ASC_ARCHITECTURES, e.g. dav-2201, dav-3510) target_link_libraries(demo PRIVATE tiling_api register platform m dl) target_compile_options(demo PRIVATE $$COMPILE_LANGUAGE:ASC:--npu-arch${CMAKE_ASC_ARCHITECTURES})通过find_package(ASC REQUIRED)引入asc-devkit提供的 ASC 语言编译工具链生成的宿主可执行程序名为demo编译对象为sum.asc链接tiling_apitiling 计算接口、register、platform等库--npu-arch将CMAKE_ASC_ARCHITECTURES传递给 ASC 编译器决定目标 NPU 架构。样例规格项值样例类型 (OpType)sum样例输入srcshape[3, 32]floatND样例输出dstshape[8, 1]floatND核函数名sum_custom本样例为固定 shape 实现输入x[3, 32]输出y[8, 1]。y中的有效值数量为 3即 3 行各自的求和结果最后 5 位为 padding 填充数据。输出 shape 之所以是[8, 1]是因为输出侧同样需要满足 32 字节对齐的约束见下文outInner的计算。实现思路Kernel 实现将输入数据搬运到片上存储UB调用Sum高阶 API 完成求和再将结果搬出到 Global Memory。Tiling 实现使用GetSumMaxMinTmpSize接口计算所需最大/最小临时空间大小选用最小临时空间再根据输入长度确定inner、outter、n等 tiling 参数。核心实现逐行解析1. Tiling 数据结构与对齐工具sum.asc 首先定义 tiling 结构体用于把 shape 与临时空间信息从主机侧传递到设备侧核函数struct SumCustomTilingData { uint32_t inner; // 输入数据的内轴长度需满足32字节对齐 uint32_t outter; // 输入数据的外轴长度行数 uint32_t n; // 输入数据内轴的实际长度 uint32_t tmpBufSize; // 临时空间大小 uint32_t outInner; // 输出数据的内轴长度 };其中PaddingAlign把n1 * typeSize按 32 字节向上对齐constexpr uint32_t PADDING_BYTE 32U; uint32_t PaddingAlign(const uint32_t n1, const uint32_t typeSize) { if (typeSize 0) { return 0; } return (n1 * typeSize PADDING_BYTE - 1U) / PADDING_BYTE * PADDING_BYTE / typeSize; }对于本样例float4 字节inner PaddingAlign(32, 4) 32outInner PaddingAlign(3, 4) 8——这正是输出[8, 1]的由来3 个有效值被 padding 到 8 个元素以满足 32 字节对齐。2. Tiling 生成GetSumMaxMinTmpSize 源码级原理void GenerateTilingData(uint8_t* tilingBuf, const uint32_t m, const uint32_t n) { uint32_t minValue 0; uint32_t maxValue 0; // n: 输入数据的内轴长度归约维度 // sizeof(uint32_t): 数据类型大小 // false: 是否使用大临时空间false表示使用最小临时空间 // maxValue: 输出参数返回所需最大临时空间大小 // minValue: 输出参数返回所需最小临时空间大小 AscendC::GetSumMaxMinTmpSize(n, sizeof(uint32_t), false, maxValue, minValue); SumCustomTilingData* tiling reinterpret_castSumCustomTilingData*(tilingBuf); tiling-outter m; tiling-inner PaddingAlign(n, sizeof(uint32_t)); tiling-n n; tiling-tmpBufSize minValue; // 选用最小临时空间 tiling-outInner PaddingAlign(m, sizeof(uint32_t)); }GetSumMaxMinTmpSize的实现在 impl/adv_api/tiling/reduce/sum_tiling.cpp其临时空间估算逻辑与硬件向量归约的执行粒度强相关void GetSumMaxMinTmpSize( const uint32_t n, const uint32_t typeSize, const bool isReuseSource, uint32_t maxSize, uint32_t minSize) { if (isReuseSource) { TILING_LOG_WARNING([Sum][GetSumMaxMinTmpSize] The parameter isReuseSource is true, which is not effective!); } ASCENDC_HOST_ASSERT(typeSize 0, return, ...expected is 2 or 4!, typeSize); ASCENDC_HOST_ASSERT(n 0, return, ...expected is greater than 0!, n); constexpr uint32_t sumOneBlkSize 32; constexpr uint32_t sumOneRepeatByteSize 256; uint32_t elementNumPerBlk sumOneBlkSize / typeSize; // half16 float8 uint32_t elementNumPerRep sumOneRepeatByteSize / typeSize; uint32_t repeatTimes (n elementNumPerRep - 1) / elementNumPerRep; uint32_t finalWorkSize (repeatTimes elementNumPerBlk - 1) / elementNumPerBlk * elementNumPerBlk * typeSize; maxSize minSize finalWorkSize; }关键结论从源码可确认参数typeSize期望值为 2half或 4float对应接口文档中声明支持的两种数据类型isReuseSource目前不生效传入true只会触发告警日志归约的基本粒度是 32 字节/块sumOneBlkSize与 256 字节/单次 repeatsumOneRepeatByteSize对长度n的内轴先按单次 repeat 可处理元素数向上取整得到repeatTimes再按块对齐得到最终临时空间大小对本样例typeSize4时elementNumPerRep64n32→repeatTimes1finalWorkSize 32字节max 与 min 相等。3. Kernel 实现KernelMeanSum设备侧核函数封装在MyCustomKernel::KernelMeanSumT类中模板参数使接口可同时服务 Sum/Mean 两种算子。核心流程为CopyIn → Compute → CopyOutInit初始化队列与缓冲区pipe-InitBuffer(inQueue, 1, inner * outter * sizeof(T)); // 输入队列 pipe-InitBuffer(outQueue, 1, outInner * sizeof(T)); // 输出队列 pipe-InitBuffer(tmpBuf, tmpBufSize); // 临时空间来自tilinginQueueVECIN、outQueueVECOUT为 1 级深度的队列tmpBufVECCALC承接归约中间结果。CopyInGM → UBAscendC::LocalTensorT srcLocal inQueue.AllocTensorT(); AscendC::DataCopy(srcLocal, srcGlobal, inner * outter); // 整块搬入 inQueue.EnQue(srcLocal);ComputeDuplicate 清零 Sum 归约T scalar(0); AscendC::DuplicateT(dstLocal, scalar, outInner); // 初始化输出为0padding区为0 AscendC::LocalTensoruint8_t sharedTmpBuffer tmpBuf.Getuint8_t(); AscendC::Sum(dstLocal, srcLocal, sharedTmpBuffer, params); // params: Sum参数结构体 tmpBuf.FreeTensor(sharedTmpBuffer);CopyOutUB → GMAscendC::DataCopy(dstGlobal, dstLocal, outInner);4. SumParams 与 Sum 高阶 API 接口SumParams定义于 include/adv_api/reduce/sum_utils.hstruct SumParams { uint32_t outter 1; uint32_t inner; // inner 32-byte alignment of n, inner (n *sizeof(T) 32 - 1) / 32 * 32 / sizeof(T) uint32_t n; // actual length of the tensor };outter外轴行数默认值为 1inner内轴对齐后的长度即PaddingAlign(n, sizeof(T))n内轴实际参与计算的元素个数1 ≤ n ≤ inner。Sum接口声明于 include/adv_api/reduce/sum.h模板签名为template typename T, int32_t reduceDim -1, bool isReuseSource false, bool isBasicBlock false __aicore__ inline void Sum( const LocalTensorT dstTensor, const LocalTensorT srcTensor, const LocalTensoruint8_t sharedTmpBuffer, const SumParams sumParams)从源码可以确认的接口特性支持的数据类型为half与floatsum_3510_impl.h中的SumCheckParams以static_assert(SupportTypeT, half, float(), ...)强制校验接口带有#pragma begin_pipe(V)管线标注运行在向量Vector计算单元提供不带sharedTmpBuffer的重载版本在__NPU_ARCH__为 2201/2002/3510/9201/3003/3113/5102/5162 的平台上会通过PopStackBuffer自动从栈上申请临时缓冲区简化调用头文件顶部明确禁止与--enable-simt纯 SIMT 编译混用。5. 设备侧归约的底层实现两套架构实现sum.h依据目标架构选择不同实现头文件通用架构实现impl/adv_api/detail/reduce/sum/sum_common_impl.hdav-2201 等借助RepeatReduceSum指令 SetVectorMask向量掩码对每行执行先单次 repeat 归约、再对中间结果迭代归约的流程最终结果写回dstTensor[row]3510 系列实现impl/adv_api/detail/reduce/sum/sum_3510_impl.h3510/9201/5102/5162/3003/3113改用Reg::LoadAlign/Reg::ReduceSum/Reg::StoreUnAlign寄存器级指令同样遵循若一次 repeat 放得下则直接归约否则先在共享临时缓冲区逐段归约、再逐层收敛的策略。两种实现都体现了迭代二分归约的思想归约长度不足一个 repeat 时一次完成否则在临时缓冲区反复对上一轮的中间结果做归约直到收敛为一个元素。这也解释了为什么GetSumMaxMinTmpSize需要按elementNumPerRep与块粒度估算空间。同时SumCheckParams对输入做了运行时校验源码可确认1 n innerinner * sizeof(T)必须是 32 的整数倍。因此在自定义 shape 时务必保证inner按 32 字节对齐否则会触发断言失败。6. 主机侧 main 与精度校验sum.asc的main函数演示了基于 ACLAscendCL的完整调用链aclInit(nullptr)初始化 ACL 环境aclrtSetDevice(0)设置设备分配 tiling 内存并调用GenerateTilingDataaclrtMallocHost/aclrtMalloc分配主机与设备侧输入输出缓冲区ReadFile读入./input/input_x.binaclrtMemcpy将输入从 Host 拷贝到 Device以sum_custom1, 0, stream(...)启动核函数1 个核USED_CORE_NUM 1aclrtSynchronizeStream等待执行完成将结果拷回 Host 并写./output/output.binCompareResult读取./output/golden.bin按绝对误差与相对误差双重阈值EPS 1e-4逐元素对比任何一项超差即判定失败清理资源打印test pass!或test failed!。注意main中的TILINGDATA_SIZE 5与SumCustomTilingData的 5 个uint32_t字段一一对应手动新增字段时需同步修改。7. 真值数据生成gen_data.py 模拟硬件归约scripts/gen_data.py 负责生成输入与 golden输入x np.random.randint(-100, 100, [3, 32]).astype(np.float32)即 3 行 32 列、取值 [-100, 100) 的随机整数转 float32goldencalculateSum采用递归二分求和逐对相加刻意模拟硬件向量归约的求和顺序避免与朴素顺序求和产生浮点误差累积差异输出对齐按(outer * 4 31) // 32 * 32 // 4计算 float32 对齐后的输出长度本样例为 8未填充位置保持 0产物input/input_x.bin与output/golden.bin。编译与运行配置环境变量根据当前环境上 CANN 开发套件包的安装方式配置环境变量source ${install_path}/cann/set_env.sh${install_path}为 CANN 包安装目录未指定安装目录时默认安装至/usr/local/Ascend下。样例执行在样例根目录examples/01_simd_cpp_api/04_advanced_api/04_reduce/sum下执行mkdir -p build cd build; # 创建并进入build目录 cmake .. -DCMAKE_ASC_ARCHITECTURESdav-2201;make -j; # 编译工程 python3 ../scripts/gen_data.py # 生成测试输入数据 ./demo # 执行编译生成的可执行程序执行样例使用CPU 调试或NPU 仿真模式时添加-DCMAKE_ASC_RUN_MODEcpu或-DCMAKE_ASC_RUN_MODEsim参数即可cmake -DCMAKE_ASC_RUN_MODEcpu -DCMAKE_ASC_ARCHITECTURESdav-2201 ..;make -j; # cpu调试模式 cmake -DCMAKE_ASC_RUN_MODEsim -DCMAKE_ASC_ARCHITECTURESdav-2201 ..;make -j; # NPU仿真模式注意切换编译模式前需清理 cmake 缓存可在 build 目录下执行rm CMakeCache.txt后重新 cmake。编译选项说明选项可选值说明CMAKE_ASC_RUN_MODEnpu默认、cpu、sim运行模式NPU 运行、CPU调试、NPU仿真CMAKE_ASC_ARCHITECTURESdav-2201默认、dav-3510NPU 架构dav-2201 对应 Atlas A2系列产品和 Atlas A3系列产品dav-3510 对应 Ascend 950PR950DT系列产品执行结果如下说明精度对比成功test pass!从 Sum 切换到 Mean一行替换README 明确给出Mean的切换方法将sum.asc中AscendC::Sum替换为AscendC::MeanGetSumMaxMinTmpSize替换为GetMeanMaxMinTmpSize。结合源码可以给出更精确的提示GetMeanMaxMinTmpSize的签名是(n, srcTypeSize, accTypeSize, isReuseSource, maxSize, minSize)比GetSumMaxMinTmpSize多一个accTypeSize累加器类型字节数参数声明位于 include/adv_api/reduce/mean_tiling.h同时它还提供GetMeanTmpBufferFactorSize用于获取最大临时空间相对输入空间的倍数因子与额外缓冲区大小。因为KernelMeanSum类本身是模板化、参数化的通用实现替换接口名后其余代码无需改动即可从求和无缝切换为求均值。源码佐证与测试验证接口定义include/adv_api/reduce/sum.h、include/adv_api/reduce/sum_utils.hTiling 估算impl/adv_api/tiling/reduce/sum_tiling.cpp设备侧实现impl/adv_api/detail/reduce/sum/sum_common_impl.h、impl/adv_api/detail/reduce/sum/sum_3510_impl.h单元测试tests/api/adv_api/reduce/sum/test_operator_sum.cpp。该测试用例直接构造SumParams{8, 160, 152}8 行、inner160、实际有效元素 n152验证实际长度小于对齐长度的典型场景并按elementNumPerBlk/elementNumPerRep手工计算工作区大小后调用Sum(dstLocal, srcLocal1, workLocal, params)以half与float两种类型参数化运行——这与样例中n与inner分离的设计思路完全一致可作为扩展 shape 时的参考模板。综上本样例提供了一条从接口声明 → tiling 估算 → 内核实现 → 主机侧编排 → 真值校验的完整链路开发者可直接以此为模板将其中的Sum换成Mean或按SumParams的约定调整outter/inner/n快速迁移到自己的归约类算子中。赞分享人工智能深度学习算子库CANNAscend【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址https://gitcode.com/cann/asc-devkit点击查看免费下载相关推荐Ascend C Swish/Silu 激活算子样例全解析从高阶 API 调用到编译运行验证asc-devkit 实战Ascend C Swish/Silu 激活算子样例全解析从高阶 API 调用到编译运行验证asc devkit 实战 导读 本篇文章以 CANN asc人工智能深度学习算子库CANNAscend用 Gelu 高阶 API 实现 GELU 激活计算Ascend C 样例从算子内核到编译运行的源码级解读用 Gelu 高阶 API 实现 GELU 激活计算Ascend C 样例从算子内核到编译运行的源码级解读 本文基于 asc devkit 仓库中的 Gelu人工智能深度学习算子库CANNAscend昇腾 Ascend C 归约算子实战基于 ReduceMax 与 Sum 高阶 API 的端到端样例深度解析昇腾 Ascend C 归约算子实战基于 ReduceMax 与 Sum 高阶 API 的端到端样例深度解析 本文以 CANN asc devkit 开源仓库人工智能深度学习算子库CANNAscend上一篇SRS 生态中的 Oryx一体化直播与 WebRTC 平台的架构、部署与运维实践下一篇Readest 仓库 Git worktree 变基后子模块指针漂移submodule drift的根因、诊断与修复指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考