ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CANN ops-cv 算子 API 样例编译与运行实战:以 GridSample(aclnnGridSampler2D)为例

CANN ops-cv 算子 API 样例编译与运行实战:以 GridSample(aclnnGridSampler2D)为例 CANN ops-cv 算子 API 样例编译与运行实战以 GridSampleaclnnGridSampler2D为例【免费下载链接】ops-cv本项目是CANN提供的图像处理、目标检测相关的算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-cv本文是 CANN ops-cv 图像算子库中算子 API 样例的完整编译与运行指南。文章以GridSample 算子aclnnGridSampler2D为主线系统讲解从环境准备、示例代码与 CMake 脚本编写到环境变量配置、编译、运行及结果验证的全过程同时结合 op_api/aclnn_grid_sampler2d.cpp 等仓库源码说明两段式接口的调用原理与参数校验逻辑帮助开发者在本地复现算子 API 的调用流程并快速排查运行期错误。1. 前提说明编译运行算子 API 所需的基础环境在编译和执行算子 API 之前请确保基础环境已搭建完成主要包括驱动与固件AI 处理器对应的驱动和固件已正确安装并生效CANN 软件包包含 Runtime、算子库等核心组件安装后可提供set_env.sh环境脚本ops 包算子二进制包包含算子编译后的二进制 kernel 库缺少该包时 API 内部会报“未加载到算子的二进制 kernel 库”类错误对应返回码ACLNN_ERR_INNER_OPP_KERNEL_PKG_NOT_FOUND见 docs/zh/context/aclnn_return_code.md编译工具链g支持 C11、cmake最低版本 3.14、make。说明算子 API 的调用流程和编译运行操作的完整官方说明可参见《应用开发CC》中“单算子调用 单算子API执行 调用aclnn接口示例代码”章节。本文的实战步骤与仓库内 image/grid_sample 模块的实际代码一一对应。2. 编译前准备以 GridSample 算子为例本文以开发和运行环境合设场景为例即带 AI 处理器的机器既作为开发环境又作为运行环境代码开发和代码运行在同一台机器上。以 GridSample 算子为例其他算子的调用逻辑、流程、编译脚本与 GridSample 算子大致一样请根据实际情况自行修改 API 调用脚本*.cpp和编译脚本CMakeLists。2.1 准备示例代码GridSample 算子的功能是提供一个输入 tensor 以及一个对应的 grid 网格然后根据 grid 中每个位置提供的坐标信息将 input 中对应位置的像素值填充到网格指定的位置得到最终的输出。示例代码可从 image/grid_sample/docs/aclnnGridSampler2D.md 的“调用示例”一节获取将代码文件命名为test_grid_sampler2_d.cpp。仓库中已存在可直接使用的完整样例 image/grid_sample/examples/test_aclnn_grid_sample2_d.cpp代码整体分为 7 个步骤int main() { // 1. 固定写法device/stream初始化参考acl API手册 int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); // 2. 构造输入与输出需要根据API的接口自定义构造 int64_t interpolationMode 0; // 0: bilinear int64_t paddingMode 0; // 0: zeros bool alignCorners false; std::vectorint64_t inputShape {1, 1, 5, 8}; std::vectorint64_t gridShape {1, 3, 3, 2}; std::vectorint64_t outShape {1, 1, 3, 3}; // 3. 调用CANN算子库API需要修改为具体的Api名称 uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnGridSampler2D第一段接口 ret aclnnGridSampler2DGetWorkspaceSize(input, grid, interpolationMode, paddingMode, alignCorners, out, workspaceSize, executor); // 根据第一段接口计算出的workspaceSize申请device内存 void* workspaceAddr nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); } // 调用aclnnGridSampler2D第二段接口 ret aclnnGridSampler2D(workspaceAddr, workspaceSize, executor, stream); // 4. 固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); // 5. 获取输出的值将device侧内存上的结果复制至host侧 // 6. 释放aclTensor // 7. 释放Device资源 return 0; }代码中几个要点与仓库源码相互印证两段式接口调用aclnnGridSampler2DGetWorkspaceSize是第一段接口负责完成参数校验、构图并计算出计算所需 workspace 大小aclnnGridSampler2D是第二段接口真正在指定 stream 上执行计算。这与仓库文档 docs/zh/context/two_phase_api.md 描述的“两段式”机制一致第一段接口形如aclxxXxxGetWorkspaceSize(const aclTensor *src, ..., uint64_t *workspaceSize, aclOpExecutor **executor)第二段接口形如aclxxXxx(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)。注意第二段接口不能重复调用否则会出现异常。workspace 的概念workspace 是指除输入/输出外算子在 NPU 上完成计算所需要的临时内存workspaceSize 表示临时内存的大小。只有第一段接口计算出的workspaceSize 0时才需要调用aclrtMalloc申请 Device 侧内存。参数校验在第一段完成从 op_api/aclnn_grid_sampler2d.cpp 源码可见aclnnGridSampler2DGetWorkspaceSize内部依次执行空指针检查CheckNotNull、数据类型检查CheckDtypeValid、属性取值检查CheckAttrValid其中interpolationMode与paddingMode的取值范围均为 02、shape 匹配关系检查CheckShape全部通过后才进入构图流程而第二段接口 aclnn_grid_sampler2d.cpp 仅通过CommonOpExecutorRun完成计算下发。2.2 编写 CMakeLists 文件CMake 文件示例如下与示例代码放在同一目录请根据实际情况修改# Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. # CMake lowest version requirement cmake_minimum_required(VERSION 3.14) # 设置工程名 project(ACLNN_EXAMPLE) # Compile options add_compile_options(-stdc11) # 设置编译选项 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ./bin) set(CMAKE_CXX_FLAGS_DEBUG -fPIC -O0 -g -Wall) set(CMAKE_CXX_FLAGS_RELEASE -fPIC -O2 -Wall) # 设置可执行文件名如opapi_test并指定待运行算子文件*.cpp所在目录 add_executable(opapi_test test_grid_sampler2_d.cpp) # 设置ASCEND_PATHCANN软件包目录请根据实际路径修改和INCLUDE_BASE_DIR头文件目录 if(NOT $ENV{ASCEND_CUSTOM_PATH} STREQUAL ) set(ASCEND_PATH $ENV{ASCEND_CUSTOM_PATH}) else() set(ASCEND_PATH /usr/local/Ascend/cann) endif() set(INCLUDE_BASE_DIR ${ASCEND_PATH}/include) include_directories( ${INCLUDE_BASE_DIR} ${INCLUDE_BASE_DIR}/aclnn ) # 设置链接的库文件路径 target_link_libraries(opapi_test PRIVATE ${ASCEND_PATH}/lib64/libacl_rt.so ${ASCEND_PATH}/lib64/libnnopbase.so ${ASCEND_PATH}/lib64/libopapi_math.so ${ASCEND_PATH}/lib64/libopapi_cv.so) # 可执行文件在CMakeLists文件所在目录的bin目录下 install(TARGETS opapi_test DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})对上述脚本的逐项说明配置项说明cmake_minimum_required(VERSION 3.14)最低 CMake 版本要求低于 3.14 的版本可能无法正确解析脚本project(ACLNN_EXAMPLE)工程名可自定义add_compile_options(-stdc11)算子 API 示例代码使用 C11 标准与仓库示例代码的语法一致CMAKE_RUNTIME_OUTPUT_DIRECTORY ./bin编译产物输出到当前目录的 bin 子目录ASCEND_PATHCANN 软件包安装目录。优先读取环境变量ASCEND_CUSTOM_PATH未设置时默认/usr/local/Ascend/cann请按实际安装路径修改include_directories引入${ASCEND_PATH}/include与${ASCEND_PATH}/include/aclnn用于找到acl/acl.h、aclnnop/aclnn_grid_sampler2d.h等头文件libacl_rt.soACL Runtime 库提供aclInit、aclrtMalloc、aclrtMemcpy、aclrtCreateStream等运行时接口libnnopbase.so算子基础库OPBASElibopapi_math.so/libopapi_cv.so算子 API 库其中libopapi_cv.so承载图像处理类算子 APIGridSample 的aclnnGridSampler2D即位于该库中提示若算子 API 的调用代码使用了aclGetRecentErrMsg错误信息获取接口该接口由libacl_rt.so提供无需额外链接其他库。2.3 MC2 算子的特殊编译要求对于集合通信和 MatMul 计算融合、并行的算子统称为通算融合算子简称 MC2 算子包括AllGatherMatmul、AlltoAllAllGatherBatchMatMul、BatchMatMulReduceScatterAlltoAll、MatmulAllReduce、MatmulAllReduceAddRmsNorm、MatmulReduceScatter等。调用该类算子 API 时一般会涉及多线程和 HCCLHuawei Collective Communication Library集合通信库因此 CMake 文件需要额外导入如下内容否则无法成功编译# 设置链接的库文件路径 find_package(Threads REQUIRED) target_link_libraries(opapi_test PRIVATE ${ASCEND_PATH}/lib64/libacl_rt.so ${ASCEND_PATH}/lib64/libnnopbase.so ${ASCEND_PATH}/lib64/libopapi_math.so ${ASCEND_PATH}/lib64/libopapi_cv.so ${ASCEND_PATH}/lib64/libhccl.so # 集合通信库文件 ${CMAKE_THREAD_LIBS_INIT}) # 多线程依赖的库文件其中find_package(Threads REQUIRED)是 CMake 用于查找线程库的命令可自动链接线程库依赖的头文件或间接依赖的库文件。${CMAKE_THREAD_LIBS_INIT}为查找到的线程库Linux 下通常为-lpthread。3. 编译与运行3.1 步骤一准备代码与编译脚本提前准备好算子的调用代码*.cpp和编译脚本CMakeLists.txt两者位于同一目录。3.2 步骤二配置环境变量安装 CANN 软件后使用 CANN 运行用户登录环境执行如下命令生效环境变量source ${INSTALL_DIR}/set_env.sh其中${INSTALL_DIR}为 CANN 软件安装后文件存储路径请根据实际情况替换例如/usr/local/Ascend/cann。环境变量生效后ASCEND_CUSTOM_PATH等变量即被设置CMake 脚本中if(NOT $ENV{ASCEND_CUSTOM_PATH} STREQUAL )分支会命中自动使用该路径作为ASCEND_PATH。3.3 步骤三编译进入 CMakeLists.txt 所在目录执行如下命令新建 build 目录存放生成的编译文件mkdir -p build进入 build 目录执行 cmake 命令编译再执行 make 命令生成可执行文件cd build cmake ../ -DCMAKE_CXX_COMPILERg -DCMAKE_SKIP_RPATHTRUE make参数说明-DCMAKE_CXX_COMPILERg显式指定 C 编译器为 g-DCMAKE_SKIP_RPATHTRUE跳过 RPATH 设置避免在可执行文件中写入绝对路径确保运行时依赖按系统动态库搜索路径LD_LIBRARY_PATH解析。编译成功后会在 build 目录的 bin 文件夹下生成opapi_test可执行文件。3.4 步骤四运行并查看结果进入 bin 目录运行可执行文件 opapi_testcd bin ./opapi_test以 GridSample 算子的运行结果为例运行后的结果示例如下resultData[0] is: 0.250000 resultData[1] is: 2.250000 resultData[2] is: 2.000000 resultData[3] is: 8.500000 resultData[4] is: 20.500000 resultData[5] is: 12.000000 resultData[6] is: 8.250000 resultData[7] is: 18.250000 resultData[8] is: 10.000000说明样例输入inputShape{1,1,5,8}共 40 个元素、gridShape{1,3,3,2}、outShape{1,1,3,3}输出共 9 个元素与上述打印一一对应。该组输入/输出数据同样出现在仓库单元测试 image/grid_sample/tests/ut/op_host/op_api/test_aclnn_grid_sampler2d.cpp 的case_1中输入值 0~39、grid 为 3×3 的 9 个采样点、alignCornersfalse、bilinear zeros可用于交叉验证算子计算结果的正确性。4. 运行报错排查使用 aclGetRecentErrMsg 获取错误信息若执行结果报错未出现预期结果可以使用aclGetRecentErrMsg接口获取报错具体信息。以调用aclnnGridSampler2DGetWorkspaceSize报错input 为空指针为例示例代码如下// input is nullptr ret aclnnGridSampler2DGetWorkspaceSize( input, grid, interpolationMode, paddingMode, alignCorners, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnGridSampler2DGetWorkspaceSize failed. ERROR: %d.\n[ERROR msg]%s, ret, aclGetRecentErrMsg()); return ret);上述构造空指针问题获取到的报错信息示例如下aclnnGridSampler2DGetWorkspaceSize failed. ERROR: 161001 [ERROR msg][PID:xxxx] xxx(timestamp) AclNN_Parameter_Error(EZ1001): Expected a proper Tensor but got null for argument input.对错误码的解读错误码161001对应返回码ACLNN_ERR_PARAM_NULLPTR含义为“参数校验错误参数中存在非法的 nullptr”错误信息中的AclNN_Parameter_Error(EZ1001)与Expected a proper Tensor but got null for argument input明确指出了出问题的参数是input。这一行为与第一段接口源码中的参数校验顺序完全对应在 op_api/aclnn_grid_sampler2d.cpp 中CheckParams首先执行CheckNotNull(input, grid, out)任一参数为空即返回ACLNN_ERR_PARAM_NULLPTR错误码 161001。常见返回码速查详见 docs/zh/context/aclnn_return_code.md状态码名称状态码值状态码说明ACLNN_SUCCESS0成功ACLNN_ERR_PARAM_NULLPTR161001参数校验错误参数中存在非法的 nullptrACLNN_ERR_PARAM_INVALID161002参数校验错误如输入的两个数据类型不满足输入类型推导关系ACLNN_ERR_RUNTIME_ERROR361001API 内部调用 npu runtime 的接口异常ACLNN_ERR_INNER_XXX561xxxAPI 内部发生异常如 561003 表示未找到 kernel可能因算子二进制包未安装针对 aclnnGridSampler2D第一段接口入参校验阶段常见的错误码还包括同样定义在 image/grid_sample/docs/aclnnGridSampler2D.md 的返回值一节返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 input、grid 或 out 是空指针ACLNN_ERR_PARAM_INVALID161002input、grid、out 的数据类型不在支持范围之内或数据类型不一致interpolationMode 或 paddingMode 的值不在支持范围内interpolationMode 为 bicubic 时数据类型不是 FLOAT32 或 FLOAT16input、grid、out 的维度关系不匹配input 最后两维为空5. 算子 API 背后从 aclnn 接口到 NPU 计算为便于理解样例代码的行为这里结合仓库源码简要梳理 aclnnGridSampler2D 的调用链路第一段接口aclnnGridSampler2DGetWorkspaceSizeop_api/aclnn_grid_sampler2d.cpp创建OpExecutorCREATE_EXECUTOR()依次执行空指针、数据类型、属性取值、shape 关系校验见上文空 tensor 场景直接返回workspaceSize 0通过l0op::Contiguous将 input、grid 转为连续 tensor根据硬件平台选择执行路径AI Core 上优先使用l0op::GridSample必要时做 NCHW→NHWC 转置与 FP16/FP32 的 CastAI CPU 路径使用l0op::GridSampler2D均不满足时报ACLNN_ERR_PARAM_INVALID通过l0op::ViewCopy将计算结果拷贝到输出 out最后调用uniqueExecutor-GetWorkspaceSize()取得 workspace 大小并返回。第二段接口aclnnGridSampler2Dop_api/aclnn_grid_sampler2d.cpp接收 workspace、executor 与 stream直接调用CommonOpExecutorRun完成计算下发与执行。算子定义层op_host/grid_sample_def.cpp 中通过OP_ADD(GridSample)注册算子定义了 x、grid 输入与 y 输出FLOAT16/FLOAT32/BFLOAT16ND 格式以及interpolation_mode默认 bilinear、padding_mode默认 zeros、align_corners默认 false、channel_last默认 false、scheduler_mode默认 1等属性并为不同芯片ascend910b、ascend910_93、ascend950、ascend310p、ascend310b、kirinx90、kirin9030配置了不同的计算核心配置。通过aclnnGridSampler2DGetWorkspaceSize返回的executor会携带完整的算子计算流程因此样例代码中无需自行组织 kernel 启动细节只需按两段式模式申请 workspace 后调用第二段接口即可完成 NPU 上的计算这也是单算子 API 调用方式相比图模式通过算子 IR 构图见 image/grid_sample/op_graph/grid_sample_proto.h更轻量、更直接的体现。6. 常见问题与注意事项未配置环境变量导致编译失败执行source ${INSTALL_DIR}/set_env.sh后CMake 才能通过ASCEND_CUSTOM_PATH找到 CANN 软件包路径否则会回退到默认路径/usr/local/Ascend/cann请确保该路径真实存在。链接库缺失示例代码用到的aclnnGridSampler2D在libopapi_cv.so中aclrtMalloc、aclrtMemcpy等在libacl_rt.so中缺少任一库都会导致链接失败MC2 算子还需额外链接libhccl.so与线程库。运行时报 kernel 未找到错误码561003ACLNN_ERR_INNER_FIND_KERNEL_ERROR通常表示算子二进制包ops 包未安装请检查基础环境中的 ops 包是否就绪。两段式接口使用约束第二段接口aclnnGridSampler2D(...)不能重复调用每次执行需重新走一遍两段式流程参见 docs/zh/context/two_phase_api.md。换用其他算子时的改动点替换test_grid_sampler2_d.cpp中的 API 名称、输入/输出 shape 与 host 数据同时把 CMakeLists 中add_executable的源文件换成对应的 *.cpp若新算子的 API 位于其他库如libopapi_math.so保持现有链接项即可覆盖绝大多数图像与数学算子。【免费下载链接】ops-cv本项目是CANN提供的图像处理、目标检测相关的算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-cv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表