ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Atlas 300V 24G部署YOLOv5指南:从ONNX到OM的昇腾推理

Atlas 300V 24G部署YOLOv5指南:从ONNX到OM的昇腾推理 最近在技术群里被问到最多的两个问题一个是“Atlas 300V 24G是运算加速卡吗”另一个是“网上说的atlas部署YOLO到底怎么搞”。这两个问题其实指向同一件事昇腾生态的Atlas系列AI推理设备越来越普及但大量开发者在第一步就被卡住了。这篇记录就以Atlas 300V 24G为例讲清楚这块卡到底是什么、能干什么再把YOLOv5模型从PyTorch一路搬到ONNX、转成昇腾的OM格式跑起来的完整流程拆开揉碎。适合刚拿到Atlas卡准备做边缘推理的算法工程师也适合正在做选型评估的架构师。1. Atlas到底是什么一张推理加速卡能干什么1.1 先回答那个高频问题300V 24G到底算不算“运算加速卡”直接说结论算而且它就是专门干这行的。Atlas 300V 24G是一张标准的AI推理加速卡基于昇腾310P3芯片板载24GB LPDDR4X统一内存半高单槽设计典型功耗在72W左右不需要外接供电插在服务器标准PCIe槽位上就能用。很多人一看到“24G”就以为它是显卡那一类的东西这个理解方向对了一半但它不是通用GPU而是面向深度学习推理场景定制的专用加速卡。如果你所说的“运算加速卡”是指CUDA那套通用并行计算卡那它确实不是。它跑不了CUDA也跟显卡的图形渲染没什么关系。但如果“运算加速”指的是给AI模型推理加速那它不仅是而且在目标检测、图像分类、OCR、语音识别这类场景里能效比往往比同功耗的GPU更突出。拿YOLO来说CPU上跑一个YOLOv5s可能要到一两百毫秒甚至更慢换到这块卡上推理耗时能压到十几到几十毫秒量级这就是它存在的意义。1.2 一张卡后面还藏着一整套软件栈很多第一次接触Atlas的人以为“插卡、装驱动、跑模型”三步走结果经常在第二步就卡住。原因很简单Atlas不是即插即用的设备它背后依赖一整套软件栈简单类比的话驱动像是给系统装上了“显卡驱动”但光有驱动还不够你还得装上对应版本的运行库和编译器那就是CANN昇腾AI处理器软件栈。CANN里面包含了算子库、图编译引擎、运行时环境以及AscendCL这套统一API。昇腾上的模型推理最终都要通过AscendCL或MindX这种上层封装跟硬件打交道。驱动、固件、CANN三者版本必须严格配套不配套的话轻则ATC转换报错重则npu-smi都看不到卡。这也是为什么网上搜Atlas部署YOLO会看到大量人问版本问题。如果你手头已经有一块卡建议先跑通官方文档里面列出的“驱动-固件-CANN版本配套表”再去折腾模型顺序别反了。2. 为什么大家都想用Atlas跑YOLO部署思路先理清2.1 YOLO这种目标检测模型和推理卡天生契合YOLO系列模型在网络结构上是典型的CNN检测模型输入一张图输出一堆框和类别概率。这类模型在训练阶段对算力要求很高但推理阶段的计算模式非常固定卷积、批归一化、激活、上采样、拼接这些算子都是推理卡早就优化好的“主菜”。昇腾的硬件架构本身就兼顾了高吞吐和低功耗在边缘端做视频流目标检测、工业缺陷检测、安防巡检YOLO配上Atlas几乎是标准组合。有人会问那我直接用GPU不就行了能用但要看场景。如果是机房训练服务器GPU肯定合适如果是在边缘侧部署几十路摄像头或者功耗、机箱空间都有限制的场景推理卡的能效比优势就体现出来了。Atlas 300V 24G这种半高单槽卡一台2U服务器能塞好几张24G统一内存对YOLO这种模型来说更是绰绰有余。所以“Atlas部署YOLO”成为热搜词不是没有原因的它就是这类场景下的主流选择。2.2 昇腾上跑YOLO的五条路选哪条更靠谱把YOLO模型弄到Atlas上跑实际有几种路径我列一个对比路径实现方式优点缺点适合场景ONNX转OMPyTorch导出ONNX用ATC转成OM流程通用和框架解耦算子兼容性需要处理绝大多数生产项目MindSpore模型直接在MindSpore训练并导出全栈昇腾友好需要迁移训练代码新项目、团队统一MindSporeMindX SDK用封装好的推理流水线SDK上手快含后处理插件定制性差黑盒较多标准视频分析流水线自研ACL推理直接写AscendCL代码性能上限最高开发量大调试难度高对性能有极致要求转成Caffe/TF模型老模型需要先转框架部分老框架资源多多一次转换风险历史模型迁移个人建议如果你手里的YOLOv5、YOLOv8是PyTorch训练出来的最通用的路线就是“PyTorch导出ONNX → ATC转OM → AscendCL推理”。这条路线社区案例最多踩坑资料也最全。MindX SDK我放在后期优化再看先保证模型能跑通再谈封装和流水线。3. 回归正题Atlas 300V 24G部署YOLOv5的完整实操3.1 环境准备软硬件版本怎么对齐以我手头这套环境为例Atlas 300V 24G服务器装的openEuler 22.03内核5.10驱动固件和CANN都选了官网配套的版本。安装顺序建议是先装NPU驱动再装固件最后装CANN工具包。每一步装完都执行一下npu-smi info确认设备能被系统正常识别。这一步看起来不起眼但非常重要很多后续报错其实在驱动阶段就已经埋下隐患了。驱动和CANN安装包解压后一般是一堆run文件。执行安装时注意用root权限安装完成后记得source环境变量source /usr/local/Ascend/ascend-toolkit/set_env.sh这个环境变量不source后面找atc命令、找libascendcl.so都会报错。建议写进~/.bashrc或系统的profile否则换一个终端就“失忆”。另外确认一下atc命令能正常执行atc --version如果输出正常说明CANN环境基本就绪。接下来可以先把官方的样例跑一遍比如resnet50模型转换与推理确认整条链路是通的再进入YOLO的部署。3.2 从PyTorch导出ONNX的正确姿势这一步是整条链路里最容易留坑的环节。YOLOv5官方仓库提供了export.py可以直接导出ONNX但有几个参数需要特别注意python export.py --weights yolov5s.pt --include onnx --opset 11 --batch-size 1这里有两个关键点第一opset版本不要用太高11或12足够。ONNX新版本里有些动态shape和高级算子ATC的算子支持列表不一定跟得上太高反而容易在转换时翻车。第二默认导出后的模型是动态shape后面用ATC转换时如果不指定固定shapeCANN编译优化会打折扣。如果要用固定shape可以在导出后修改ONNX或者在ATC转换时用--input_shape固定输入尺寸。还有很重要的一点不要把后处理(NMS)一起塞进ONNX。YOLOv5的export有个--nms参数很多人会顺手加上但昇腾CANN对NMS算子的支持不算好硬转经常报算子不支持。正确做法是模型只输出原始预测张量也就是shape为[1, 25200, 85]的那个输出把置信度过滤、坐标解码、NMS全部放在应用层做。这样一能避免算子兼容问题二来后期调阈值、做多目标跟踪也更灵活。导出后建议先用onnxsim把模型简化一下把一些冗余的shape节点去掉ATC转换时少一点意外的麻烦pip install onnxsim python -m onnxsim yolov5s.onnx yolov5s_sim.onnx3.3 ATC转换从ONNX到OM模型的关键一步环境OK、ONNX也准备好了接下来就是核心的模型转换。ATC是昇腾的图编译器能把ONNX、TensorFlow、MindSpore等格式的模型编译成昇腾硬件直接运行的OM模型。我用的转换命令长这样atc --modelyolov5s_sim.onnx \ --framework5 \ --outputyolov5s_bs1 \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --loginfo参数拆开说一下--model是输入ONNX文件路径--framework5表示ONNX格式--output是输出OM的路径和前缀--input_shape把输入固定成[1,3,640,640]这里要和导出ONNX时的输入名、形状完全一致--soc_version填的是芯片型号我这里是Ascend310P3如果你不确定用npu-smi info看板卡型号后去CANN文档里对照。如果你的ONNX输入名不是images怎么查用Python加载ONNX看一眼就行import onnx m onnx.load(yolov5s_sim.onnx) for inp in m.graph.input: print(inp.name, [d.dim_value for d in inp.type.tensor_type.shape.dim])转换成功后目录下会生成yolov5s_bs1.om。建议先用官方自带的msame工具做一次推理验证输入一个预处理好的bin文件确认输出形状和数值范围都正常再写业务代码。这一步能帮你把“模型转换问题”和“代码问题”分开排查。3.4 编写推理程序Python版最小示例拿到OM模型后我用的是AscendCL的Python接口。代码不复杂核心流程就四步初始化设备、加载模型、准备输入输出内存、执行推理。下面是一个最小可用的骨架后处理部分我留了注释按YOLOv5官方逻辑补就行import acl import cv2 import numpy as np # 初始化设备 acl.init() acl.rt.set_device(0) ctx, ret acl.rt.create_context(0) # 加载OM模型 model_path b./yolov5s_bs1.om model_id, ret acl.mdl.load_from_file(model_path) # 获取模型的输入输出尺寸 desc acl.mdl.create_desc() acl.mdl.get_desc(desc, model_id) input_size acl.mdl.get_input_size_by_index(desc, 0) output_size acl.mdl.get_output_size_by_index(desc, 0) # 申请设备侧内存 input_ptr, ret acl.rt.malloc(input_size, 2) output_ptr, ret acl.rt.malloc(output_size, 2) # 读取图片并预处理: letterbox RGB 归一化 def letterbox(img, new_shape(640, 640)): h, w img.shape[:2] r min(new_shape[0] / h, new_shape[1] / w) nh, nw int(round(h * r)), int(round(w * r)) img cv2.resize(img, (nw, nh), interpolationcv2.INTER_LINEAR) canvas np.full((new_shape[0], new_shape[1], 3), 114, dtypenp.uint8) canvas[(new_shape[0] - nh)//2: (new_shape[0] - nh)//2 nh, (new_shape[1] - nw)//2: (new_shape[1] - nw)//2 nw] img return canvas origin cv2.imread(test.jpg) img letterbox(origin, (640, 640)) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0 img np.ascontiguousarray(img.transpose(2, 0, 1)[None]) # 输入拷贝 Host - Device acl.rt.memcpy(input_ptr, input_size, img.tobytes(), input_size, 1) # 执行推理 acl.mdl.execute(model_id, [input_ptr], [input_size], [output_ptr], [output_size]) # 输出拷回 Device - Host out_buf np.zeros(output_size, dtypenp.uint8) acl.rt.memcpy(out_buf, output_size, output_ptr, output_size, 2) # 解析输出dtype以实际模型输出为准 pred np.frombuffer(out_buf.tobytes(), dtypenp.float32).reshape(1, 25200, 85) # 此时拿到的是解码前的预测后面的置信度过滤 NMS 用YOLOv5官方逻辑处理即可 # 释放资源真实工程务必补全 acl.rt.free(input_ptr) acl.rt.free(output_ptr) acl.mdl.unload(model_id) acl.rt.destroy_context(ctx) acl.finalize()这段代码我把错误检查都省略了实际工程里每一个API的返回值ret都要判断出错了尽早打日志退出不然很容易在某个不起眼的环节上出现“看起来没报错但结果不对”的诡异问题。4. 实测性能与调优经验别浪费了24G这块大显存4.1 不同配置下的性能观感先给一个量级概念YOLOv5s、输入640x640、Python侧预处理、后处理NMS放在Python里端到端单路推理大概在二三十毫秒量级。如果纯看模型在卡上的推理时间会更快一些瓶颈反而容易出现在图像读取、resize、数据拷贝这些“外围”环节。很多人拿卡跑完说“怎么没有想象的那么快”多半都是预处理拖了后腿。如果做多路视频流用多进程加多Stream并发把每路视频流分配到不同推理线程里Atlas 300V 24G跑6到8路1080p的实时检测是常见的配置。24G统一内存对单个YOLO模型来说根本用不满真正限制路数上限的往往是CPU预处理能力和后处理NMS的耗时而不是显存。4.2 真正能把卡压榨出性能的几个手段想提升吞吐我建议按优先级做下面几件事第一固定shape。ATC转换时给定固定的1,3,640,640比动态shape编译出来的模型性能好一截。动态shape每次推理都可能触发重编译或shape切换开销这在服务端在线的场景尤其明显。第二适当加大batch。如果能同时凑齐多路输入把batch从1提到4或8吞吐会有明显提升但会增加预处理侧的复杂度。第三用多Stream并发。AscendCL支持创建多个Stream把不同路视频的推理请求放到不同的Stream里硬件层面能并行起来。第四把预处理放到AIPP里。ATC转换时通过--insert_op_conf插入AIPP配置可以帮你在硬件里完成resize、色域转换、归一化。AIPP下沉之后主机侧CPU占用会下降很多对多路场景特别友好。我说的优先级是根据“投入产出比”排的不是每个项目都需要把AIPP调到最优。如果就是做几百路的离线分析先把固定shape和多进程搞起来收益最明显。4.3 24G显存的管理心得Atlas 300V 24G的内存统一管理不像GPU有显存和内存之分推理时数据都是在设备侧内存里分配的。单模型占用的内存其实不大YOLOv5s可能就几百MB到1GB左右24G预算很充足。但多路并发时要注意一点不要每路输入都单独acl.rt.malloc频繁分配释放会造成内存碎片也让性能波动变大。建议启动时一次性申请一块常驻内存池推理时从池子里取用完放回去。还有一个容易被忽略的地方一个进程加载一个OM模型模型的数据是常驻设备内存的。如果开了十几个进程每个进程都把同一份模型加载一遍24G也会被吃紧。能用同一个进程管理多路推理就尽量别拆太多进程或者合理规划各进程的模型实例数量。至于多进程和多线程怎么选我的经验是Python环境下多进程更稳妥能绕开GIL对预处理和后处理的限制多线程适合纯推理部分但如果预处理大量用OpenCV多线程不会带来太多提升。5. 常见问题与排查经验这一节能帮你省好几个通宵5.1 从装到跑最容易卡住的高频问题结合我自己的经历Atlas 300V 24G部署YOLO出问题最多的阶段反而在模型转换和环境配套上真正跑起来之后反而安静。先看驱动层npu-smi info如果看不到卡大概率是驱动安装失败或者固件没刷上其次是权限问题有些服务器上普通用户访问不了NPU设备需要加用户组或者用root。再看模型转换层ATC报E10002这类算子不支持的错误太常见了。遇到这种情况不要慌先把报错信息里的算子名记下来去ONNX里找到对应节点看能不能换一种算子表达或者直接转成opset 11再试一次。如果模型里带NMS优先考虑把NMS移出去。个人经验很多YOLO转换失败的案例最后都跟NMS算子有关。5.2 高频报错速查表报错现象常见原因解决方向npu-smi info显示无设备驱动或固件未正确安装重装配套版本确认固件版本匹配atc: command not found没source环境变量执行source /usr/local/Ascend/ascend-toolkit/set_env.shlibascendcl.so: cannot open...运行环境未配置source环境变量或配置LD_LIBRARY_PATHATC报E10002算子不支持模型里的算子CANN不认识简化模型、降低opset、移除NMS推理输出形状不对ONNX动态shape或输入名不一致用--input_shape显式指定检查ONNX输入名推理结果全为0或乱码预处理色域/归一化错误确认BGR/RGB通道顺序确认归一化系数输入尺寸不匹配letterbox与模型输入不一致统一使用640x640比例缩放加padding设备内存不足多进程重复加载模型或存在泄漏使用内存池、控制并发进程数量5.3 我养成的几个操作习惯这块算是我折腾久了之后沉淀下来的“肌肉记忆”。第一每拿到一块新卡我首先会对齐官方文档里驱动、固件、CANN的版本配套表然后先跑通一个resnet50样例再碰自己的模型。别一上来就转YOLO因为一旦报错你很难分辨是环境问题还是模型问题。第二ATC转换时加上--loginfo每一步日志都要看转换失败的详细原因基本都藏在日志里。第三第一次推理时先用一张已知结果的图片做对照输出张量的形状、数值范围、最大值位置这些都能快速判断链路上哪个环节出了问题。网上关于Atlas部署YOLO的教程不少但很多都是照着命令跑一遍没讲清楚为什么要这样配置。Euler系统和Ubuntu的依赖不完全一样CANN版本新旧也有差异直接照搬很容易失败。我自己的经验是把版本信息牢牢握在自己手里遇到问题先按“驱动 → 固件 → CANN → 模型 → 代码”的顺序自上而下排查而不是盲目搜索复制粘贴。最后再分享一个小技巧如果你发现ONNX转OM之后某个检测类别完全不输出先别怀疑硬件先检查是不是训练数据里这个类别的样本过少或者置信度阈值卡太死了。很多时候问题不在Atlas而在模型本身。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进