最近后台好多人问我同一个问题:atlas 300v 24g 是运算加速卡吗?以及 atlas 能不能部署 yolo?这两个问题放在一起看,其实非常典型——很多人把昇腾Atlas当成普通显卡拿到手,装了驱动后还想沿用GPU那套思路,结果被算子不支持、数据搬运报错、AIPP配置搞到怀疑人生。而真正常年在Atlas上部署YOLO类检测模型的人,又会给出另一个答案:只要把流程理顺,一张24G显存、72W功耗的推理卡,在边缘视频检测场景里其实很能打。
这篇文章算是我个人在Atlas 300V(24G)上完整部署YOLOv5的一次复盘。我会先把这张卡说清楚,然后带着你走完整个链路:环境搭建、PyTorch模型导出、ATC离线转换、AscendCL推理、性能调优以及各种坑。适合刚拿到昇腾推理卡、准备把检测模型从前端到后端全部迁到NPU上的读者,也适合正在做硬件选型、想知道这张卡到底值不值得买的朋友。内容比较长,但每一步都是实际跑过的,照着做能省不少时间。
1. Atlas 300V 24G到底算什么卡
1.1 名字里的数字都是什么意思
先回答那个被反复问烂的问题:Atlas 300V 24G是一张AI推理加速卡,属于华为昇腾Atlas产品线。它不是传统意义上的显卡,不能接显示器,不能跑OpenGL,更不能拿去玩3D游戏。它擅长的领域非常聚焦:卷积、矩阵乘、向量运算这些AI模型里的核心算子。换句话说,它是一张“专用运算加速卡”,面向推理场景、视觉分析场景,而“300V”里的V其实也在暗示这一点——V系列的典型落地场景就是视频分析、视频结构化这一类视觉任务。
名字里的“24G”指的是板载24GB显存。Atlas 300V家族里常见的有12G和24G两个版本,24G在高分辨率输入、多路视频流、大batch推理这些场景下会明显更从容。24GB这个容量放在推理卡里已经相当大了,很多老一点的训练卡也就这个水平。有人说推一个YOLOv5s用不了这么大显存,确实用不了,但如果你要跑YOLOv8m、YOLOv8l,或者同时接入多路视频流,24G的好处就体现出来了。另外要注意,Atlas 300V目前常见芯片是昇腾310P3,型号不同对应的soc_version也不同,后面模型转换的时候必须填对,否则大概率转换失败。
1.2 一张72W的卡凭什么跑AI模型
很多人第一次看到Atlas 300V 24G的功耗会愣一下:72W,就这么点功耗能跑AI?我一开始也有这个疑问。后来看了架构才明白,昇腾310P是典型的“专芯专用”设计,芯片里密集排布了AI Core阵列,这些AI Core主要由Cube单元、Vector单元和对应的Buffer组成,做矩阵运算时效率非常高。你可以把它理解成一条只做“固定几道工序”的流水线,虽然不能什么活儿都接,但只要接到自己擅长的卷积、全连接、注意力机制,单位功耗里的产出比通用GPU还要可观。
这张卡的官方标称算力是INT8 256 TOPS、FP16 128 TFLOPS左右(不同批次和型号会有差异)。这个标称值理论上很好看,但别太迷信,因为实际能发挥多少取决于模型结构、算子是否被支持、数据搬运有没有成为瓶颈。我实测下来,跑YOLOv5s这样的常规模型,单卡性能足够覆盖多路实时分析的需求。我常用的一个比喻是:GPU像一个全能型选手,什么都能干但功耗也高;NPU更像一个专项运动员,只在自己的项目上发力,但在这个项目上效率惊人。Atlas 300V就是后者。
1.3 拿它跟游戏显卡对比会怎样
我在不同场合都被问过类似问题:这卡和RTX 3060比怎么样?说实话,这不是一个公平的比较,但可以帮助建立直觉。下面这张表是我自己整理的对比,重点是让人知道Atlas的强项和短板在哪里。
| 对比项 | Atlas 300V 24G | 常见游戏GPU |
|---|---|---|
| 核心定位 | AI推理加速 | 图形渲染+通用计算 |
| 显存 | 24GB LPDDR4X | 8GB~12GB GDDR6 |
| 典型功耗 | 72W | 150W~200W+ |
| 软件生态 | CANN/AscendCL | CUDA |
| 图形输出 | 无 | 有 |
| 推理能效比 | 非常高 | 一般 |
| 上手成本 | 偏复杂 | 相对成熟 |
如果你想在Atlas上跑通用计算程序、做渲染、跑物理仿真,那它确实不合适。但如果你关心的是“在72W功耗下能跑几路YOLO检测”,那它会给你惊喜。我在一个边缘盒子里同时塞了两张Atlas 300V 24G,整机功耗控制得很好,散热压力也小,这在机房和边缘现场都是实打实的优势。
2. 决定用Atlas部署YOLO之前,我做了哪些准备
2.1 为什么选YOLO而不是别的检测算法
YOLO家族做目标检测在工业界用得最广,YOLOv5和YOLOv8的资料最多,遇到问题基本都能搜到解决方案。另一个重要原因是YOLO的算子结构相对规整,大部分算子昇腾的CANN工具链都已经支持,模型迁移成功率高。相比之下,有些最新的Transformer检测器或带特殊算子的开源模型,导出到ONNX后可能碰到不支持的算子,处理起来非常麻烦。从我个人的经验看,第一次接触昇腾NPU时,最好不要选太冷门的模型,先用YOLO把流程跑通、把工具链用熟,再逐步迁移更复杂的模型,这是最稳的路线。
当然,YOLO本身也有版本差异。YOLOv5s、YOLOv8s这类小模型适合先上手,算力要求低、转换快、调试时出错也好定位。如果业务需求是更高精度的检测,等流程稳定后再考虑YOLOv8m甚至更大模型。还有一点提醒:训练和部署要分开看。Atlas 300V是推理卡,用它做模型训练并不合适,训练阶段建议还是在GPU或者带昇腾训练卡的机器上完成,训练好之后再把权重拿到Atlas 300V上做推理部署。
2.2 部署方案路线对比:AscendCL、MindX SDK还是MindIE
在昇腾上部署YOLO,主要有三条路。第一条是用AscendCL(简称ACL)手写推理程序,这是最底层的推理接口,灵活性最高,能精确控制内存、输入输出、device分配,也最容易理解整个推理流程。第二条是用MindX SDK,它提供了一些封装好的推理流水线组件,适合快速搭视频流应用,缺点是黑盒成分多,出了问题排查起来比较费劲。第三条是用MindIE,它是昇腾较新的推理引擎,主要面向大规模、高性能场景,做YOLO这类模型有点杀鸡用牛刀。
我这次选择的是AscendCL + Python(pyACL)。原因很简单:可控、直观、方便调参。虽然代码会比用MindX SDK多一些,但每一步都能看到数据是怎么走的,遇到性能问题也知道在哪里下手。如果你以后要对接复杂的视频分析业务,再考虑迁移到MindX SDK也不迟。对新手来说,先把AscendCL摸清楚,很多概念会一通百通。
2.3 软硬件版本清单:照着配就行
昇腾生态非常吃版本匹配。驱动版本和CANN版本不匹配,轻则报错,重则NPU直接不工作。我这次使用的环境如下,你可以作为参考:
- 服务器:x86_64架构,Ubuntu 20.04,内核5.4
- 推理卡:Atlas 300V 24G,芯片昇腾310P3
- 驱动固件:Ascend HDK 310P系列,23.0.3
- CANN工具包:6.3.RC2
- Python:3.9
- 模型:YOLOv5s 6.1版
还需要在导出模型时用到PyTorch、onnx、onnxsim,在推理时用到opencv-python、numpy、pyACL。特别强调一点:下载驱动和CANN时,一定要去昇腾社区或企业支持页面找配套版本说明,不要随便拿最新版。我有一次图省事装了CANN 7.0,结果和手头驱动版本不匹配,光排查环境问题就花了一个下午,后来换成配套版本才正常。
3. 环境搭建实录:从裸机到npu-smi能看到卡
3.1 驱动固件怎么装才不会翻车
昇腾卡的驱动和固件是分开安装的,顺序是先固件后驱动。安装包通常是.run文件,需要用root权限执行。下面是我这次安装时用的命令:
uname -a cat /etc/os-release ./Ascend-hdk-310P-npu-firmware_23.0.3_linux.run --full ./Ascend-hdk-310P-npu-driver_23.0.3_linux.run --full reboot安装前建议先确认系统内核版本,因为驱动安装过程会编译内核模块,通常需要linux-headers和gcc。如果缺少这些依赖,安装过程中会报dkms编译错误。解决的办法是先把依赖装齐:
sudo apt-get install gcc make linux-headers-$(uname -r)装完驱动固件后重启,用npu-smi验证。这个工具类似GPU里的nvidia-smi,能看到卡的状态、温度、功耗和显存占用。如果能正常列出卡,说明驱动层没问题。
npu-smi info如果执行npu-smi后看不到卡,先别慌,优先检查固件是否安装成功、驱动模块有没有被加载,可以用dmesg查一下有没有npu相关报错。最常见的原因是安装顺序反了,或者内核版本和驱动不兼容。这一步别图快,尽量一次做对,否则后面CANN装好了也会因为底层不通而全线崩溃。
3.2 CANN工具链安装与版本对齐
驱动和固件就绪后,接下来装CANN。CANN是昇腾的计算架构,相当于GPU生态里的CUDA。推理侧最核心的是toolkit包,装好它,atc转换工具、AscendCL的Python接口就都有了。
chmod +x Ascend-cann-toolkit_6.3.RC2_linux-x86_64.run ./Ascend-cann-toolkit_6.3.RC2_linux-x86_64.run --install source /usr/local/Ascend/ascend-toolkit/set_env.sh注意,每次打开新的终端都需要source一下,否则找不到atc、找不到libascendcl相关库。如果不想每次手动source,可以把这行加到.bashrc里。安装完成后,可以在/usr/local/Ascend/ascend-toolkit/latest下看到工具链。验证是否装好,最简单的方式是执行atc --help,如果能正常输出帮助信息,说明ATC转换工具已经可用。
还有一个容易忽视的地方:如果CANN的toolkit安装成功了,但调用pyACL时提示找不到_acl库,很可能是少了kernels包,或者环境变量没有生效。CANN有些版本要求单独安装Ascend-cann-kernels和Ascend-cann-nnal这些组件,建议对照官方文档把组件补齐。
3.3 点亮NPU:用官方样例跑通第一个推理
环境搭好之后,我强烈建议先跑一个官方样例再上手自己的模型。这不光是“走了个流程”,它能一次性验证驱动、固件、CANN、环境变量是不是真的都OK。昇腾工具包自带了resnet50等模型的样例,可以找一下对应的sample目录,把resnet50的om模型或onnx模型做好转换后跑一次推理。
如果你不想编译C++项目,可以用一个最简Python脚本验证底层连通性:
import acl acl.init() ret, dev_count = acl.rt.get_device_count() print("device count:", dev_count) acl.rt.set_device(0)这段代码只做了初始化,但如果能正常打印出device count,说明pyACL已经能找到NPU设备。跑通官方样例之后,再进入自己的YOLO部署,心态会完全不一样。我见过不少朋友跳过这步,直接拿自己的模型上来,结果报错之后分不清是环境问题还是模型问题,排查成本反而更贵。
4. YOLOv5模型迁移:从PyTorch权重到OM离线模型
4.1 导出ONNX时先想清楚要不要输出层
Atlas 300V 24G部署YOLO,模型格式最终是.om,而它通常不能直接吃PyTorch的.pt文件,一般流程是先导出成ONNX,再用ATC工具转成OM。导出这一步,很多人直接用官方export.py一把梭,结果转换时报错或者输出形状不符合预期。关键原因是YOLOv5的ONNX导出会包含不同的输出定义,有些版本会带上decode和NMS相关算子,有些则是裸的检测头输出。
我这次的做法是:导出不含复杂后处理的“干净”模型。也就是让ONNX只输出检测头那几层的feature map,解码和NMS全部留在板端CPU上做。这样模型结构简单,ATC转换成功率高,后续也方便调AIPP和性能。导出命令大致如下:
cd yolov5/ python export.py --weights yolov5s.pt --include onnx --opset 11 --simplify--simplify会用onnxsim对计算图做简化,很多时候能顺手消掉一些不受支持的算子。导出之后,用onnx库查看输入输出名称,这个信息在ATC阶段必须用到:
import onnx model_path = "yolov5s.onnx" m = onnx.load(model_path) for inp in m.graph.input: print("input:", inp.name) for out in m.graph.output: print("output:", out.name)YOLOv5s导出的输入名一般是images,输出名可能是三个feature map,也可能是拼接后的结果。记下这些名字,后面ATC里不需要全都用到,但心里要有数。
4.2 ATC转换命令逐行拆解
ATC是昇腾的模型转换工具,作用是把ONNX等格式的模型转换成OM离线模型。我这次用的命令如下:
atc --model=yolov5s.onnx \ --framework=5 \ --soc_version=Ascend310P3 \ --input_shape="images:1,3,640,640" \ --input_format=NCHW \ --insert_op_conf=aipp.cfg \ --output_type=FP32 \ --output=yolov5s_bs1 \ --log=error每个参数的意义都值得说清楚。--framework=5表示输入是ONNX格式。--soc_version填的是芯片型号,一定要和实际芯片一致,Atlas 300V 24G通常对应Ascend310P3,可以用npu-smi info确认。--input_shape这里固定为1,3,640,640,第一次跑通时建议用静态shape,不要搞动态shape,动态shape会引发额外的编译开销和内存申请问题,后期调优再说。--output_type=FP32是因为YOLO的输出要拿去做decode和NMS,FP32解析起来最简单;如果追求极致性能,再考虑FP16,但要做好精度下降的心理准备。
--insert_op_conf是AIPP配置文件,也就是把一部分预处理放到NPU上去做。转换完成后会生成yolov5s_bs1.om,这就是最终用于推理的模型文件。如果转换过程报错,先把--log=error改成--log=debug再看详细日志,通常日志里会明确指出哪个算子不支持或哪个参数非法。
4.3 AIPP预处理:预处理搬到NPU上的正确姿势
AIPP可以说是昇腾部署里最容易被低估的环节。很多人在GPU上习惯把resize、归一化全部写在PyTorch或OpenCV里,但到了NPU上,这些操作如果在CPU侧做,会白白消耗很多时间,尤其多路视频流场景下CPU很容易成为瓶颈。昇腾的AIPP可以代替CPU执行一部分图像预处理工作,让数据在进入模型前就被处理成模型期望的格式。
我的AIPP配置如下:
aipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_w: 640 src_image_size_h: 640 csc_switch: true rbuv_swap_switch: true min_chn_0: 0 max_chn_0: 255 min_chn_1: 0 max_chn_1: 255 min_chn_2: 0 max_chn_2: 255 mean_chn_0: 0 mean_chn_1: 0 mean_chn_2: 0 }这个配置里提得比较关键的一点是:YOLOv5训练时的预处理是letterbox resize加除以255归一化。如果直接把一张16:9的原图喂给AIPP做固定尺寸resize,会导致长宽比失真,模型精度明显下降。我的习惯是:CPU侧先用OpenCV做好letterbox,把原图缩放并padding到640x640,然后把这张640x640的图交给AIPP做归一化和格式转换。AIPP里的min_chn和max_chn的设置就可以实现“除以255”的效果,mean为0就相当于不再减均值。如果你训练时用了自己的mean和std,就按训练时的实际值填。
5. 用AscendCL写推理程序:代码级流程
5.1 初始化、加载模型、创建入参
模型转换好之后,推理程序的核心是AscendCL。下面是一个简化但完全可以跑通的骨架:
import acl import numpy as np acl.init() acl.rt.set_device(0) context, ret = acl.rt.create_context(0) model_id, ret = acl.mdl.load_from_file(b"yolov5s_bs1.om") input_desc = acl.mdl.get_input_desc(model_id) output_desc = acl.mdl.get_output_desc(model_id) input_size = acl.mdl.get_input_size_by_index(model_id, 0) output_size = acl.mdl.get_output_size_by_index(model_id, 0) input_data, ret = acl.rt.malloc(input_size, acl.const.MEM_MALLOC_NORMAL_ONLY) output_data, ret = acl.rt.malloc(output_size, acl.const.MEM_MALLOC_NORMAL_ONLY) input_dataset = acl.mdl.create_dataset() output_dataset = acl.mdl.create_dataset() input_buffer = acl.mdl.create_data_buffer(input_data, input_size) output_buffer = acl.mdl.create_data_buffer(output_data, output_size) acl.mdl.add_dataset_buffer(input_dataset, input_buffer) acl.mdl.add_dataset_buffer(output_dataset, output_buffer)这段代码做了几件事:初始化设备、加载OM模型、获取输入输出尺寸、申请device侧内存、创建数据集。一个容易踩的坑是输入输出的内存大小不要自己根据shape推算,最好用get_input_size_by_index和get_output_size_by_index动态获取,因为OM模型里可能因为对齐策略使实际size比理论值大。按接口拿到的size一定是准确的。
5.2 数据搬运:Host与Device之间不能想当然
NPU计算的数据要放到device侧内存里,CPU侧预处理好的图像数据在host侧内存里,两者之间不能直接访问。这一步决定了推理的输入是否是“模型认可”的数据,也是很多人栽跟头的地方。我这次的预处理结果是一个1x3x640x640的float32数组,在喂给模型之前必须先拷贝到device内存:
img = preprocess(frame) # 做letterbox,返回float32数组,形状1x3x640x640 host_buf = img.tobytes() ret = acl.rt.memcpy(input_data, input_size, host_buf, len(host_buf), acl.rt.MEMCPY_HOST_TO_DEVICE) ret = acl.mdl.execute(model_id, input_dataset, output_dataset) out_np = np.zeros(output_size, dtype=np.uint8) ret = acl.rt.memcpy(out_np, output_size, output_data, output_size, acl.rt.MEMCPY_DEVICE_TO_HOST)这里有几个细节值得注意。第一,copy方向不能搞反,从CPU到NPU是HOST_TO_DEVICE,推理完从NPU拿回结果是DEVICE_TO_HOST。第二,numpy数组先tobytes再memcpy,在拷贝大尺寸图像时效率可以接受,但如果追求极致性能,建议用acl.rt.memcpy_async或者直接申请host锁页内存来减少拷贝开销。第三,output_size要作为目标缓冲区大小传入,防止越界。整体来看,AscendCL的数据搬运比CUDA多一步,但理解了Host和Device的内存界线之后,其实并不复杂。
5.3 输出解析与NMS:模型只做了一半工作
OM模型跑出来的输出通常是检测头那几层feature map,不是最终的框坐标和类别。YOLOv5的输出需要经过decode、按置信度过滤、NMS几个步骤才能变成可以直接画框的结果。如果你导出的ONNX没有带decode,那输出大概率和anchor、stride相关。
以YOLOv5s为例,它有三个检测头,stride分别是8、16、32,特征图尺寸是80x80、40x40、20x20,每个位置有3个anchor,输出shape就是(1, 255, 80, 80)这种形式。后处理要做的就是把这个255维拆成(85*3),也就是每个anchor有4个坐标、1个objectness和80个类别分数,然后再根据anchor和stride把相对偏移还原成原图坐标。这一部分如果有PyTorch的参考实现在CPU侧用Numpy复刻一遍也不难:
def postprocess(outputs, conf_thres=0.25, iou_thres=0.45): # outputs: 模型输出的多个feature_map # 1. 遍历每个stride,把预测值reshape成 [batch, anchor*3, 5+classes, h, w] # 2. 转换坐标到原图尺寸 # 3. 按置信度过滤 # 4. 执行NMS boxes, scores, class_ids = [], [], [] # ... 具体解码逻辑需要按anchor参数展开 return boxes, scores, class_ids如果你不想自己写decode,可以在导出ONNX时加入decode层,让模型的输出直接是1x25200x85的检测结果。这样做后处理更简单,但会增加模型内的计算量,转换时也可能遇到新算子不支持的风险。我的经验是:第一次做,老老实实写后处理,遇到问题好定位;等整套流程成熟了,再考虑用模型内decode来优化效率。
6. 性能实测:300V 24G跑YOLOv5能到什么水平
6.1 延迟、吞吐、内存占用数据
环境稳定后,我在同一台机器上做了几组测试。模型是YOLOv5s,输入尺寸640x640,CANN版本6.3.RC2。数据有批次差异,但大致可以作为参考:
| 测试项 | 延迟 | 等效吞吐 | 备注 |
|---|---|---|---|
| batch=1 纯推理 | 7~10ms | 约100 FPS | 不含预处理和后处理 |
| batch=1 完整流程 | 10~13ms | 约80 FPS | 包含letterbox和NMS |
| batch=4 完整流程 | 22~28ms | 等效140 FPS | 平均到4张图更快 |
显存占用方面,模型本身占用不到几百MB,推理时临时缓冲加起来大概1.5GB左右,24G显存余量非常大。这也意味着这张卡不是用来单跑一个轻量模型的,它更适合多路并发或者更大模型场景。比如跑YOLOv8l之类的大模型,显存充裕的优势才会真正体现出来。
这里插一句:算力标称归标称,实测延迟和驱动、CANN、模型结构、是否动态shape都有关系。如果你跑出来的数据和我的不同,不用觉得奇怪,重点看相对趋势。比如batch增大时单张平均耗时是否会下降,如果下降明显,说明NPU之前没有被喂饱。
6.2 调优三板斧:静态shape、AIPP、多流并发
性能不达标时,我的调优思路通常从三个方向入手。第一是静态shape,模型转换时固定batch和分辨率,不要用动态shape,动态shape虽然灵活,但运行时会有额外的shape推导和内存申请开销,在边缘推理场景下不值得。第二是AIPP,把归一化、色域转换这类操作从CPU搬到NPU,我在一条32路视频流场景里做过对比,CPU侧预处理时间一下子降了四成,整体吞吐提升立竿见影。第三是多流并发,Atlas 300V支持多路请求并行执行,实际部署时可以用多线程或者多进程分别创建context、加载同一个模型,然后并发execute。
还有一种更朴素的思路:如果预处理确实没办法优化,就直接增大batch。我在CPU性能较弱的机器上试过,batch=1时CPU把数据准备好NPU只能等着,改成batch=4之后CPU和NPU的配合明显好很多,整体吞吐反而上去了。所以在调优时不要只看NPU算力峰值,要看整条链路的瓶颈在哪里。
6.3 一次掉帧问题的排查实录
有次做多路视频分析,场景要求32路1080p视频流每路至少15FPS。一开始我在配置较低的x86服务器上跑,结果只能勉强跑到18路,再往上就开始掉帧。当时npu-smi显示NPU利用率只有60%左右,明显不是NPU算力不够。我先后检查了CPU占用,发现预处理进程已经把多个CPU核顶满了,瓶颈出在让OpenCV做resize和归一化上。
排查过程很典型:先用top定位CPU占用率,再用npu-smi看NPU状态,发现两边不对称。然后我做了一个很直接的优化:把图片缩放到640x640后,数据直接用numpy向量化操作做像素格式调整,同时把归一化部分交给AIPP,减少CPU侧的浮点运算。另一个改动是让多路视频帧拼成batch=4后统一送卡,减少进程切换和显存申请次数。优化之后,32路慢慢能稳定在26路左右,虽然没有完全达到30路,但比初始的18路已经好很多,后续再通过调整NMS阈值的并行度,最终满足了业务需要。
7. 常见问题速查表:从环境到运行的避坑手册
7.1 环境与驱动类问题
昇腾环境的坑,多半出在版本和依赖上。下面几个问题是我和周围朋友踩过频率最高的。
| 现象 | 常见原因 | 解决办法 |
|---|---|---|
| 安装驱动时dkms编译失败 | 缺linux-headers或gcc | 先装系统内核头文件和编译工具再重试 |
| npu-smi info 看不到卡 | 固件未装或驱动未加载 | 重启后看dmesg,确认npu相关模块是否加载 |
| 找不到atc命令 | 环境变量未生效 | source set_env.sh,或重新登录终端 |
| Python import acl 报错 | pyACL没装或不匹配 | 检查CANN组件是否齐全,确认Python版本匹配 |
我个人还有一个习惯:每次部署前把npu-smi、atc、python三个工具链的版本都打出来确认一遍,避免改了环境之后又踩“上个项目明明可以”的坑。
7.2 模型转换类问题
模型转换出问题,大部分集中在算子不支持、输入输出不对、动态shape没有处理好这三类。我在迁移过程中遇到过“Unsupported op xxx”的报错,当时用的CANN版本较老,后来换了更新的CANN版本,算子终于被支持。如果遇到不支持的算子,先看能不能用onnx-simplifier化简掉,再看有没有等价替代算子,最后才考虑升级CANN。
还有一个很容易踩的坑:输入输出名和ATC里--input_shape不匹配。导出的ONNX输入如果不是images,或者你改了模型结构,一定要用onnx库先查一下输入名,别想当然。转换成功后也别急着删掉onnx,后面调精度、排查输出时还要对着看。
7.3 推理与精度类问题
推理程序跑起来之后,常见的症状是输出全为0、输出框位置不对、精度下降严重这几类。输出全为0,先检查输入数据有没有成功拷贝到device侧,再看归一化是否正确。输出框位置不对,多半是预处理没有做letterbox,或者decode时anchor和stride对应关系搞错。精度明显变差,优先怀疑FP16的问题:如果模型转换时指定了FP16,很多场景精度会受到影响,建议把output_type设回FP32,或者至少在关键检测任务上对比一下两种模式的mAP差距。
另外要提一句内存管理。AscendCL里dataset和buffer用完要记得销毁,长期运行的服务如果每帧都新建dataset却不释放,最后一定会吃光显存导致推理失败。我在项目里习惯复用同一组dataset和buffer,只在输入变化时更新数据,稳定性和性能都更好。
最后说点个人感受。Atlas这套体系刚接触时,最难受的是思维切换。GPU生态太成熟,很多时候我们其实是“被惯坏了”。切到CANN之后,以前被屏蔽的细节全都冒出来:输入格式、内存归属、算子支持、模型转换、AIPP参数……但换个角度想,这也是理解AI推理底层的好机会。如果你也打算用Atlas 300V 24G跑YOLO,我的建议是:先别急着上自己的模型,把官方sample跑通,把npu-smi、ATC、AscendCL这三个工具用熟,再上自己的模型,踩坑成本会低很多。