FEATURED · 精选文章

Atlas 300V 24G推理加速卡部署YOLOv5:从模型转换到推理实战

发布时间 / 2026/9/19 5:07:52
来源 / 创域科博编辑部
栏目 / 资讯中心
Atlas 300V 24G推理加速卡部署YOLOv5:从模型转换到推理实战 最近总有朋友拿着同一个问题来找我“Atlas 300V 24G 到底是不是运算加速卡”还有人把热词里“Atlas 部署 YOLO”直接甩给我让我给出能直接复现的完整流程。正好我手上有一张 Atlas 300V Pro 24G也刚在它上面跑通了 YOLOv5这篇就把卡的定位、环境准备、模型转换、推理代码、踩坑过程一次性讲清楚。文章不是给你讲 PPT是按我实际操作的顺序写的尽量做到你照着能走完。1. 先回答“300V 24G 是不是运算加速卡”1.1 它确实是加速卡但准确叫法是“AI 推理加速卡”答案是肯定的但这里有个很容易让人误会的点Atlas 300V Pro 24G 不是我们日常说的“显卡”形式上它是插在服务器 PCIe 槽位上的一块计算卡没有显示输出接口也不能直接接显示器。它内部用的是昇腾 310P 这个 AI 处理器板载 24GB 显存算力规模大致在百 TOPSINT8量级官方定位就是面向边缘侧和推理场景的 PCIe 推理加速卡。为什么会有人问这个问题我猜很多人是被“加速卡”这三个字搞混了。大家平时接触最多的是 NVIDIA 的 GPU跑 CUDA、跑 PyTorch、跑 TensorFlow感觉“卡就该这么用”。Atlas 这支产品线不一样它的软件栈以 CANN 为核心模型要先用 ATC 转成 OM 格式再通过 ACL/pyACL 或 MindX SDK 去调用和 CUDA 那套完全不是一回事。所以你问“是不是运算加速卡”我可以负责任地说是但它是昇腾体系的推理加速卡不是通用计算/训练卡。1.2 把它和常见 NVIDIA 推理卡放在一起看差距就清楚了下面这个对比表不是精确到小数点后多少的跑分而是选型时的参考维度维度Atlas 300V Pro 24GNVIDIA T4 这类推理卡A100 这类训练卡定位单卡多路视频分析、目标检测、OCR 推理数据中心推理训练、大规模并行计算接口PCIe Gen4PCIePCIe / SXM显存24GB16GB 左右40GB / 80GB编程入口CANN、pyACL、MindX SDKCUDA / TensorRTCUDA / cuDNN能否直接跑 PyTorch 的 .pt不能直接用需转 OMPyTorch 模型可转 TensorRT 或直接跑可直接跑功耗几十瓦级别通常无需外接供电70W 左右300W/400W 及以上所以从硬件形态来说它就是一块标准意义的“计算加速卡”从软件生态来说它和 NVIDIA 卡属于两个体系。你把它当推理卡它能在目标检测、视频结构化、OCR 这些场景里干很多活你把它当训练卡一上来就想 torch.load 一个 .pt 往里丢那基本会碰一鼻子灰。2. 在 Atlas 上部署 YOLO先要把“模型怎么跑”这件事想清楚2.1 昇腾这套工具链并不难难在入口多我第一次接触昇腾时也有点头大因为光名词就够绕的CANN、ATC、OM、pyACL、DVPP、AIPP、MindX SDK……每一个都像入口但又不是全都要用。实际部署 YOLO 时常规路径只有五步把 PyTorch 的模型导成 ONNX。用 ATC 工具把 ONNX 转成昇腾的 OM 模型。可选通过 AIPP 配置文件把图像预处理并入模型前处理。在宿主机上用 pyACL 或 MindX SDK 加载 OM传入数据拿到推理输出。在 CPU 侧做后处理坐标解码、置信度过滤、NMS。没错ATLAS 上的“模型转换”是比 NVIDIA 多出来的强制步骤。NVIDIA 那边你拿着 .pt 或者 .onnx 直接在 TensorRT 里 build engine 就行昇腾这边统一入口是 OM一切推理都从 OM 开始。这也是很多人第一次部署时最不适应的地方。2.2 需要记住的最小术语集CANN昇腾的软件栈总称类似 CUDA 生态。ATC模型转换工具把 ONNX/Caffe/TensorFlow 模型转成 OM。OM昇腾离线模型文件类似 TensorRT 的 .engine。pyACLPython 接口用于加载 OM 并执行推理。DVPP昇腾硬件上的图像/视频预处理单元包括缩放、抠图、编解码。AIPPLocal/AI 预处理配置可把归一化、通道转换、裁剪等前处理操作“烧进”模型转换过程中。对于部署 YOLO前面四个词会频繁出现后面两个主要是优化性能时用。记不住没关系后面都会碰到。2.3 部署前环境检查清单动手之前先确认这台服务器是干净的、驱动和 CANN 是匹配的。我的习惯是依次跑三条命令每条都不能报错# 1. 检查是否能看到 NPU 设备 npu-smi info # 2. 确认 CANN 环境变量是否已生效 source /usr/local/Ascend/ascend-toolkit/set_env.sh env | grep ASCEND # 3. 确认 ATC 转换器在不在 which atc atc --version这三条命令里最容易出问题的是第二条。很多人自带的 shell 环境没有 source 昇腾的 set_env.sh结果后面 atc 命令找不到或者 pyACL import 失败。我的建议是直接把它写进~/.bashrc或者在你跑部署脚本的虚拟环境里统一 source。3. 手把手从 YOLOv5 权重到 OM 离线模型3.1 在 GPU 侧导出 ONNX我建议先在你有 CUDA 显卡的机器上把 YOLOv5 权重导出成 ONNX再拷贝到 Atlas 机器上做转换。即使在 Atlas 机器上也装了 PyTorch导出这一步仍然建议在 GPU 机器上完成因为原版 YOLOv5 的 .pt 更熟悉 CUDA 的导出流程省得在国产卡上再折腾一遍算子兼容问题。以 YOLOv5 v6.0/v7.0 为例git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt python export.py \ --weights yolov5s.pt \ --include onnx \ --img-size 640 640 \ --batch-size 1导出后会得到yolov5s.onnx。这一步有两点要注意不要加--dynamic。ATC 对动态 shape 的支持虽然比早期好很多但第一次跑通尽量用固定 640×640否则后面 AIPP、输入数据结构都会多很多不确定因素。导出后我习惯用onnxsim再简化一次python -m onnxsim yolov5s.onnx yolov5s_sim.onnx简化之后有些冗余算子会被合并ATC 转起来更省事部分情况下还能降低 OM 的转换失败概率。3.2 ATC 转换先别急着上 AIPP网上很多教程都喜欢在第一步就让你配 AIPP但我实际跑下来的经验是第一次先不配 AIPP在主机侧用 Python/OpenCV 做预处理把模型先跑通再回来优化。主要原因很简单AIPP 的字段一旦配错比如 RGB/BGR 反了、归一化重复做了模型输出的坐标和置信度会变得很奇怪而且这种问题很难一眼看出是转换配置的问题还是模型本身的问题。于是第一次转换命令用最干净的形式atc \ --modelyolov5s_sim.onnx \ --framework5 \ --input_shapeimages:1,3,640,640 \ --input_formatNCHW \ --outputyolov5s_310p \ --soc_versionAscend310P3 \ --loginfo几个参数说明framework5表示输入是 ONNX。input_shape里的名字是imagesYOLOv5 导出的输入名就叫这个不要随手改。soc_versionAscend310P3是 Atlas 300V Pro 的芯片代号。不同版本、不同产品可能对应Ascend310P1、Ascend310P2、Ascend310P3最准的办法是用npu-smi info看一下芯片型号再对照 ATC 的帮助文档确认。转换成功后会生成yolov5s_310p.om。如果转换失败日志里常见的是算子不支持但很多时候并不是真的算子不支持而是soc_version填错导致 ATC 没找到对应的算子库。3.3 用 msame 快速验证 OM 是否正常在写 Python 代码之前先用昇腾官方样例工具msame做一次“空跑”能最快区分“模型没问题”和“我的代码有问题”。./msame \ --model yolov5s_310p.om \ --input ./input_nchw \ --output ./outputinput_nchw目录下放一张预处理过的 640×640 的 NCHW 浮点输入格式可以用二进制或者 JPEG具体看 msame 版本。如果 msame 正常输出两个推理结果文件说明模型转换没问题接下来写代码心里就有底了。3.4 认识 YOLOv5 的输出形状如果导出时用的是原始 YOLOv5 ONNX不带 NMS 的话OM 输出通常是两个 tensor一个形状是(1, 25200, 85)的稀疏特征对应 3 个尺度、每个尺度 3 个 anchor、80 个类别另一个是(1, 25200, 1)的候选框数量。这里很多人会卡住拿着 25200 这个数无从下手。其实它就是 640×640 输入下所有网格候选框的总数(80×80 40×40 20×20) × 3 25200每个候选框的 85 维向量是[cx, cy, w, h, objectness, 80 个类别得分]。后面的后处理就围绕这 85 个数值展开。4. 用 pyACL 写推理的最短可用代码4.1 初始化和加载模型的顺序不能乱pyACL 的名字看起来像普通 Python 库但用起来有几个固定动作先acl.init()再指定设备再创建上下文最后加载模型。顺序错了后面接口就会报“context is null”之类的错。一个最小可用的骨架大体是这样的import acl import numpy as np def check_ret(ret, msg): if ret ! 0: raise RuntimeError(f{msg}, ret{ret}) # 1. 初始化 check_ret(acl.init(), acl.init failed) check_ret(acl.rt.set_device(0), acl.rt.set_device failed) context, ret acl.rt.create_context(0) check_ret(ret, acl.rt.create_context failed) # 2. 加载 OM 模型 model_id, ret acl.mdl.load_from_file(yolov5s_310p.om) check_ret(ret, acl.mdl.load_from_file failed) model_desc acl.mdl.create_desc() check_ret(acl.mdl.get_desc(model_desc, model_id), acl.mdl.get_desc failed)这只是前半段。真正麻烦的是输入输出数据集的构造因为昇腾的模型输入往往是 Device 侧内存需要把你在主机侧预处理好的数据拷贝过去再绑定到 buffer 上。不同 CANN 版本里acl.util.numpy_to_ptr的可用性不一样所以网上抄的代码很经常出现“在我的环境能跑到你环境就报错”的情况。下面这段是示意代码重点看流程接口细节一定要以你机器上 CANN 版本带的样例为准# 3. 构造输入数据集 input_np np.random.randn(1, 3, 640, 640).astype(np.float32) input_ptr acl.util.numpy_to_ptr(input_np) input_buffer acl.mdl.create_data_buffer(input_ptr, input_np.nbytes) input_dataset acl.mdl.create_dataset() acl.mdl.add_dataset_buffer(input_dataset, input_buffer) # 4. 构造输出数据集 output_size acl.mdl.get_output_size_by_index(model_desc, 0) output_ptr, ret acl.rt.malloc(output_size, 2 * 1024 * 1024) output_buffer acl.mdl.create_data_buffer(output_ptr, output_size) output_dataset acl.mdl.create_dataset() acl.mdl.add_dataset_buffer(output_dataset, output_buffer) # 5. 执行推理 ret acl.mdl.execute(model_id, input_dataset, output_dataset) check_ret(ret, acl.mdl.execute failed) # 6. 把输出拷回主机侧 output_np np.zeros(output_size, dtypenp.uint8) acl.rt.memcpy( output_np.__array_interface__[data][0], output_size, output_ptr, output_size, acl.memcpy_kind.DEVICE_TO_HOST, )acl.mdl.execute返回之后output_dataset 里就是模型输出的原始数据形状和 3.4 节说的一致。4.2 YOLOv5 的后处理为什么得动手写NVIDIA 生态里有现成的 TensorRT 插件、有 DeepStreamYOLOv5 的后处理经常已经被封装好了但昇腾侧走 pyACL 时后处理基本都要你自己做。这也是很多教程到模型转换就结束不往下写的原因因为后面这段代码又长又容易踩坑。我提供一个干活够用的简化思路关键步骤就三个从 25200 个框里筛出置信度大于阈值比如 0.25的框按类别分别做 NMS同一个类别里只保留最好的框因为模型输入是 640×640如果原图是等比 letterbox 过的还要把坐标映射回原图。代码骨架不展开整段核心就是靠 NumPy 向量化代替循环def postprocess(raw_output, conf_thr0.25, iou_thr0.45): pred raw_output[0] # (25200, 85) scores pred[:, 4:] # 80 类分数 cls_ids scores.argmax(axis1) conf scores.max(axis1) mask conf conf_thr boxes pred[mask] classes cls_ids[mask] confs conf[mask] keep [] for c in np.unique(classes): idx np.where(classes c)[0] sub_boxes boxes[idx] sub_confs confs[idx] # 对 sub_boxes 做 NMS得到保留下标 keep_idx simple_nms(sub_boxes, sub_confs, iou_thr) keep.extend(idx[keep_idx]) return boxes[keep], classes[keep], confs[keep]NMS 本身不复杂就是反复找最高分框、删除与其 IoU 过大的框。真到了生产环境建议直接用 pyclipper、shapely 这类库去算 IoU或用 C 写版本性能会好很多。开发阶段用纯 NumPy 循环完全够用。5. 我实际踩过的四个坑含完整排查链路5.1 坑一驱动和 CANN 版本打架症状是最典型的npu-smi info能看到卡但跑 ATC 时莫名其妙提示某个插件加载失败或者 pyACL 一acl.init()就直接段错误。排查链路是这样的用npu-smi info确认卡正常用ascend-dmi -i或查看/usr/local/Ascend/driver/version.info查驱动版本用cat /usr/local/Ascend/ascend-toolkit/latest/version.cfg查 CANN 版本两个版本对照官方兼容性列表。我那次问题的根因是驱动更新到新版但 CANN 还是几个月前的旧版两者接口不匹配。解决办法不是乱降版本而是把 CANN 升到和驱动配套的版本再重新 source 环境变量。5.2 坑二soc_version 填错报错却像“算子不支持”这个坑比较坑因为 ATC 报出来的错误信息是“找不到 XX 算子”很多人第一反应是换 ONNX 简化策略、换算子折腾半天没用。我当时用 Atals300V Pro第一反应填了Ascend310P2结果转换失败。后来用npu-smi info查看芯片型号显示为 310P再查 CANN 文档发现这块卡应该用Ascend310P3。同样的模型换掉soc_version后一次通过。经验就是遇到算子不支持的错先怀疑soc_version别急着动模型。5.3 坑三RGB/BGR 和归一化位置搞反YOLOv5 训练时用的是 RGB、输入范围是 0~1。但 OpenCV 读图出来默认是 BGR、0~255。如果你在主机侧预处理时忘了做cv2.cvtColor(img, cv2.COLOR_BGR2RGB)模型就会把红蓝通道对调检测表现是猫狗的检测框错位、置信度普遍很低、同类物体漏检。还有一个更隐蔽的问题是归一化“叠了两层”。如果你先用 AIPP 做了 1/255 的缩放主机侧又一次除以 255输入就变成 0~0.0039 的范围模型基本全废。这个现象很难查我的排查方法是拿一张已知的测试图先把预处理完的输入 dump 出来用np.min/np.max看一眼数值范围到底在哪个量级。5.4 坑四试图在“卡”上直接跑 PyTorch 的 .pt很多刚接触昇腾的人会问“为什么不能直接在 Atlas 300V 上torch.load(yolov5s.pt)”。原因是Atlas 300V Pro 是推理卡驱动只提供推理相关的运行环境模型必须转成 OM通过 CANN 的推理接口来调用。官方虽然有 torch_npu 项目但它主要面向昇腾训练卡和部分推理场景并不是让你像使用 CUDA 显卡一样无缝跑任意 PyTorch 代码。常规推理场景最稳的路线永远是PyTorch 侧导出 ONNXATC 转 OMpyACL 执行推理。5.5 四个坑汇总现象根本原因解决动作ATC 插件加载失败或段错误驱动与 CANN 版本不匹配对照官方兼容列表升级 CANN转换报“算子不支持”soc_version 填错用 npu-smi 查真实芯片型号再填检测框错位、置信度低BGR/RGB 反了或归一化重复检查预处理链路并 dump 输入验证想直接跑 .pt不理解推理卡的工作边界走 ONNX - OM - pyACL 路线6. 性能和部署建议6.1 我实测的量级在我这边环境下CANN 6.3 系列版本YOLOv5s、640×640、batch1 的 OM 模型单帧推理时间大概是十几毫秒量级。这个数字不算惊艳但对于视频结构化、安防、工业质检这类场景24GB 大显存意味着你可以同时加载多个模型或者把不同分辨率的检测任务都塞进同一张卡利用率会比小显存卡好不少。要注意的是如果你在 Atlas 上跑 YOLOv5 还同时开一堆图像解码速度瓶颈很可能在 CPU 和预处理不在 NPU。这点和 NVIDIA 卡上跑推理很类似数据搬运常常比计算更耗时。6.2 想再快一点按这个顺序优化性能优化的优先级我建议是固定输入尺寸。YOLO 检测如果业务允许就固定 640×640动态 shape 在昇腾上会多出很多调度开销。合并前处理。把归一化和通道转换写进 AIPP 配置文件让预处理下沉到硬件侧减少主机到设备的内存拷贝。多 batch。视频流场景下把 4 路或 8 路帧拼成一个 batch比单路反复调用推理接口要划算得多。用 DVPP 做缩放。JPEG 解码、缩放交给 DVPP不要在 CPU 上先用 OpenCV 做一遍。AIPP 配置尤其值得花时间。网上很多 YOLO 教程设置的 AIPP 都是为了分类模型直接抄过来检测模型很容易犯归一化错误。我建议要用 AIPP 时先在主机侧用纯软件预处理跑通一版再把这部分逻辑迁移到 AIPP这样两头都好排查。6.3 部署形态容器化还是裸机如果是正式项目我建议用昇腾容器镜像。宿主机只需要装好驱动容器里放 CANN 和推理服务方便多环境隔离。启动容器时要把 NPU 设备映射进去常见做法是挂载/dev/davinci*和/dev/davinci_manager再把/usr/local/Ascend/driver相关目录挂进去。我踩过一个小坑容器内npu-smi info能看到卡但acl.init()报设备打开失败最后发现是没挂/dev/davinci_manager。这个设备文件别看它名字不起眼丢了它容器里的进程根本没有管理 NPU 的权限。如果团队还处于可行性验证阶段直接裸机跑即可少一层容器网络问题排查也更直接。等流程完全稳定了再容器化也不迟。最后说句实在话Atlas 300V 24G 这块卡能不能用很大程度上取决于你的心态。如果你只是抱着“用 NVIDIA 的方式去用昇腾”的想法那大概率会觉得很别扭但如果你愿意接受“ONNX - OM - pyACL”这套固定流程它其实是一块性价比很高、功耗控制也很好的推理加速卡。我个人的经验是第一次部署别追求性能极限先老老实实把最小链路跑通再逐渐叠加 AIPP、DVPP、多 batch 这些优化最终做到生产可用并没有想象中那么难。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻