从 0 到 1:10 分钟跑通第一个 Ascend ACL 推理程序
第一次在昇腾 NPU 上跑推理很多人卡在第一步环境装好了ATC 模型转换也成功了一跑推理程序就报aclInit failed或者load model failed。我当年第一次跑 ACL 推理环境装了 3 遍模型转了 5 遍推理程序编译通过但运行就 core dump。最后发现是环境变量没配全——LD_LIBRARY_PATH少了/usr/local/Ascend/nnrt/latest/acllib/lib64导致运行时找不到libascendcl.so。这篇文章把我踩过的坑全部列出来你照着做10 分钟内必能跑通。第一步CANN 环境安装1.1 确认硬件和环境先确认你有昇腾 NPU910/910B/310 都行且系统是 Ubuntu 18.04/20.04 或 CentOS 7.x。# 看有没有 NPU 设备 ls /dev/davinci* # 有输出比如 /dev/davinci0说明驱动装好了没输出先装驱动。去昇腾社区下载对应版本的驱动[https://www.hiascend.com/hardware/firmware-drivers]按文档装完重启。1.2 安装 CANN Toolkit 和 NNRtCANN 有两个包Toolkit开发用含编译工具链和NNRt运行时含 ACL 库。# 下载 CANN 8.0.RC1 版本示例具体版本看你 NPU 驱动版本 # 去 https://www.hiascend.com/software/cann/community-history 下载 # 安装 Toolkit开发机装 ./Ascend-cann-toolkit_8.0.RC1_linux-x86_64.run --full # 安装 NNRt运行机装如果开发运行同一台机器两个都装 ./Ascend-cann-nnrt_8.0.RC1_linux-x86_64.run --full90% 新手都会踩的坑 No.1装完不配环境变量。 装完 CANN 一定要配环境变量否则编译时找不到头文件运行时找不到库。第二步环境变量配置这是最容易出问题的地方。很多人以为/etc/profile里配一次就完事了其实每次开新终端都要 source。创建环境变量配置文件~/.cannrc# ~/.cannrc export ASCEND_HOME/usr/local/Ascend export CANN_HOME$ASCEND_HOME/nnrt/latest export PATH$ASCEND_HOME/toolkit/latest/bin:$PATH export LD_LIBRARY_PATH$CANN_HOME/acllib/lib64:$ASCEND_HOME/driver/lib64:$LD_LIBRARY_PATH export ASCEND_OPP_PATH$ASCEND_HOME/nnrt/latest/opp每次开新终端都要 sourcesource ~/.cannrc或者写进~/.bashrc一劳永逸echo source ~/.cannrc ~/.bashrc验证环境变量是否配好# 看能不能找到 ATC 工具 which atc # 输出应该是 /usr/local/Ascend/toolkit/latest/bin/atc # 看能不能找到 ACL 库 ldconfig -p | grep ascendcl # 输出应该有一行 libascendcl.so90% 新手都会踩的坑 No.2LD_LIBRARY_PATH配了但没生效。 用ldconfig -p | grep ascendcl验证。如果没输出说明库路径没配进去。检查~/.cannrc里的路径是否真实存在比如nnrt/latest是不是软链接有时候装完叫nnrt/8.0.RC1。第三步模型转换ATCACL 推理需要 OM 格式的模型离线模型。你手里的 ONNX/PyTorch/TensorFlow 模型需要先转成 OM。3.1 准备 ONNX 模型如果手头没有 ONNX 模型用 PyTorch 导出一个 ResNet-50# export_resnet50.py import torch import torchvision model torchvision.models.resnet50(pretrainedFalse) model.eval() dummy_input torch.randn(1, 3, 224, 224) torch.onnx.export(model, dummy_input, resnet50.onnx, input_names[input], output_names[output])3.2 用 ATC 转 OMatc --modelresnet50.onnx \ --framework5 \ --outputresnet50 \ --input_formatNCHW \ --input_shapeinput:1,3,224,224 \ --loginfo参数解释解释 WHY 而非 WHAT--framework5ONNX 的格式编号是 51Caffe, 3TensorFlow, 5ONNX, 6PyTorch--input_formatNCHWNPU 要求输入是 NCHW 格式跟 PyTorch 一致--outputresnet50输出的 OM 模型叫resnet50.om自动加.om后缀转换成功会看到ATC run success生成resnet50.om文件。90% 新手都会踩的坑 No.3模型转换成功但推理时报load model failed。 原因ATC 转换时用的 CANN 版本跟推理程序编译时链接的 CANN 版本不一致。解决保证转换和运行用同一个 CANN 版本比如都是 8.0.RC1。第四步写 ACL 推理代码C这是核心。ACL 推理分 5 步初始化 → 加载模型 → 准备输入 → 执行推理 → 解析输出。4.1 目录结构acl_inference/ ├── CMakeLists.txt # 编译配置 ├── main.cpp # 主程序 ├── resnet50.om # 模型文件ATC 转换生成 └── test_image.bin # 输入数据二进制文件4.2 完整 C 代码// main.cpp #include acl/acl.h #include acl/ops/acl_dvpp.h #include iostream #include fstream #include vector // 检查 ACL 返回值的宏不写 try-catch直接判错 #define CHECK_RET(ret, msg) \ if ((ret) ! ACL_SUCCESS) { \ std::cerr msg , ret ret std::endl; \ return -1; \ } int main() { // 第 1 步初始化 ACL aclError ret aclInit(nullptr); CHECK_RET(ret, aclInit failed); // 指定要用的 NPU 设备0 号设备 ret aclrtSetDevice(0); CHECK_RET(ret, aclrtSetDevice failed); // 第 2 步加载 OM 模型 uint32_t model_id 0; ret aclmdlLoadFromFile(resnet50.om, model_id); CHECK_RET(ret, aclmdlLoadFromFile failed); // 获取模型描述信息输入/输出的 shape、数据类型 aclmdlDesc *model_desc aclmdlCreateDesc(model_id); ret aclmdlGetDesc(model_desc, model_id); CHECK_RET(ret, aclmdlGetDesc failed); // 第 3 步准备输入数据 // 读二进制输入文件假设已经把图片预处理成了 1×3×224×224 的 float32 数组 std::ifstream infile(test_image.bin, std::ios::binary); std::vectorfloat input_data(1 * 3 * 224 * 224); infile.read(reinterpret_castchar*(input_data.data()), input_data.size() * sizeof(float)); infile.close(); // 申请 NPU 显存输入数据要从 Host 拷到 NPU size_t input_size aclmdlGetInputSizeByIndex(model_desc, 0); void *input_dev nullptr; ret aclrtMalloc(input_dev, input_size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret, aclrtMalloc failed); // 把 Host 数据拷到 NPU ret aclrtMemcpy(input_dev, input_size, input_data.data(), input_size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret, aclrtMemcpy failed); // 创建输入 datasetACL 要求用 dataset 封装输入输出 aclmdlDataset *input_dataset aclmdlCreateDataset(); aclDataBuffer *input_buffer aclCreateDataBuffer(input_dev, input_size); ret aclmdlAddDatasetBuffer(input_dataset, input_buffer); CHECK_RET(ret, aclmdlAddDatasetBuffer failed); // 第 4 步执行推理 // 创建输出 dataset aclmdlDataset *output_dataset aclmdlCreateDataset(); for (size_t i 0; i aclmdlGetNumOutputs(model_desc); i) { size_t output_size aclmdlGetOutputSizeByIndex(model_desc, i); void *output_dev nullptr; ret aclrtMalloc(output_dev, output_size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret, aclrtMalloc output failed); aclDataBuffer *output_buffer aclCreateDataBuffer(output_dev, output_size); ret aclmdlAddDatasetBuffer(output_dataset, output_buffer); CHECK_RET(ret, aclmdlAddDatasetBuffer output failed); } // 执行模型推理 ret aclmdlExecute(model_id, input_dataset, output_dataset); CHECK_RET(ret, aclmdlExecute failed); // 第 5 步解析输出 // 把输出从 NPU 拷回 Host for (size_t i 0; i aclmdlGetNumOutputs(model_desc); i) { aclDataBuffer *output_buffer aclmdlGetDatasetBuffer(output_dataset, i); void *output_dev aclGetDataBufferAddr(output_buffer); size_t output_size aclGetDataBufferSize(output_buffer); std::vectorfloat output_data(output_size / sizeof(float)); ret aclrtMemcpy(output_data.data(), output_size, output_dev, output_size, ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret, aclrtMemcpy output failed); // 打印前 10 个输出值真实场景要接后处理比如 argmax 取分类结果 std::cout Output i (first 10 values): ; for (int j 0; j 10 j output_data.size(); j) { std::cout output_data[j] ; } std::cout std::endl; } // 清理资源 ret aclmdlUnload(model_id); CHECK_RET(ret, aclmdlUnload failed); ret aclrtResetDevice(0); CHECK_RET(ret, aclrtResetDevice failed); ret aclFinalize(); CHECK_RET(ret, aclFinalize failed); std::cout Inference success! std::endl; return 0; }4.3 代码关键解释为什么用aclmdlDataset封装输入输出ACL 的接口设计是面向 Dataset的——一个模型可能有多个输入比如 GPT 的input_ids和attention_mask用 Dataset 封装可以一次性传多个输入。为什么输入数据要从 Host 拷到 NPUNPU 只能直接访问自己的显存HBM。Host 内存的数据必须显式拷贝用aclrtMemcpy。为什么aclrtMalloc要用ACL_MEM_MALLOC_HUGE_FIRSTNPU 的 HBM 支持大页内存Huge Page用这个标志申请内存会优先用大页性能好 10-15%。第五步编译写CMakeLists.txtcmake_minimum_required(VERSION 3.10) project(acl_inference) set(CMAKE_CXX_STANDARD 14) # 找 CANN 包装在 /usr/local/Ascend find_package(Ascend REQUIRED) # 包含 ACL 头文件路径 include_directories(${ASCEND_INCLUDE_DIRS}) # 编可执行文件 add_executable(acl_inference main.cpp) # 链 ACL 库 target_link_libraries(acl_inference ${ASCEND_LIBRARIES})编译mkdir build cd build cmake .. make -j90% 新手都会踩的坑 No.4编译通过但运行时报error while loading shared libraries: libascendcl.so。 原因LD_LIBRARY_PATH没配全。运行时的库路径要在~/.cannrc里配好见第二步。第六步运行# 确保环境变量已 source source ~/.cannrc # 把 resnet50.om 拷到运行目录 cp ../resnet50.om . # 运行需要有 NPU 权限加 sudo 或把用户加入 HwAiUser 组 ./acl_inference成功输出Output 0 (first 10 values): 0.0023 -0.0156 0.0089 ... Inference success!为什么模型能转换成功但运行失败这是新手问的最多的问题。我总结了 4 个原因原因 1CANN 版本不匹配ATC 转换时用的 CANN 版本跟推理程序编译/运行时用的 CANN 版本不一致。OM 模型格式可能变了导致aclmdlLoadFromFile失败。排查# 看 ATC 版本 atc --version # 看推理程序链接的 ACL 库版本 ldd acl_inference | grep ascendcl解决统一版本重新转换模型、重新编译程序。原因 2NPU 驱动版本跟 CANN 不匹配CANN 8.0 要求驱动版本 24.1.0。如果驱动太老ACL 初始化就失败aclInit failed。排查# 看驱动版本 npu-smi info解决升级驱动到 CANN 要求的版本。原因 3输入 Shape 跟模型要求的不一致ATC 转换时指定了input_shapeinput:1,3,224,224但推理时输入数据的 shape 不对比如你传了1,3,256,256的数据导致aclmdlExecute失败。排查打印输入数据的尺寸跟 ATC 转换时指定的 shape 对比。解决推理前把输入数据 resize/crop 到模型要求的 shape。原因 4权限问题运行推理程序需要访问/dev/davinci0设备文件普通用户没权限。排查ls -l /dev/davinci0 # 如果 owner 是 root你需要 sudo 或加入 HwAiUser 组解决sudo usermod -aG HwAiUser $USER # 注销重新登录就有权限了90% 新手都会踩的坑完整版坑编号问题描述原因解决方法1装完 CANN 找不到头文件/库环境变量没配写~/.cannrc每次开终端 source2编译通过运行时libascendcl.so找不到LD_LIBRARY_PATH没配全ldconfig -p3模型转换成功推理时load model failedCANN 版本不匹配统一转换和运行用的 CANN 版本4aclInit failed驱动版本太老升级驱动到 CANN 要求的版本5推理输出全是 0 或 NaN输入数据没归一化图片预处理要跟训练时一致比如 ImageNet 的 mean/std排错方法总结遇到问题按这个顺序排查看返回值所有 ACL 接口都返回aclError用CHECK_RET宏检查看环境变量echo $LD_LIBRARY_PATH确认库路径看设备状态npu-smi info确认 NPU 在线看模型信息atc --modedisplay_model_info --omresnet50.om确认模型输入/输出 shape简化复现先跑 CANN 自带的样例比如/usr/local/Ascend/nnrt/latest/samples/inference/modelInference/工程经验第一次跑不通别慌。ACL 的错误码很详细比如ACL_ERROR_INVALID_RESOURCE 107002去昇腾社区搜错误码90% 的问题都有现成答案。https://atomgit.com/cann/runtime https://atomgit.com/cann/asc-devkit https://atomgit.com/cann/cann-samples
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2633291.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!