ARTICLE DETAIL

资讯详情

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

Atlas 300V 24G推理卡实战:从零部署YOLOv5全流程

Atlas 300V 24G推理卡实战:从零部署YOLOv5全流程 如果你最近在调研AI推理卡大概率会刷到Atlas 300V 24G这个名字。上周还有朋友直接问我这卡到底算不算运算加速卡买回来能不能跑YOLO我没有直接给结论而是把工位上这块Atlas 300V Pro 24G从零到一部署YOLOv5的全过程重新捋了一遍——驱动、固件、CANN、ONNX转OM、pyACL推理、性能调优该踩的坑一个没漏。这篇文章就是完整复盘目标是让手里有这块卡、或者正在考虑入手的人照着做就能把YOLO跑起来顺便搞清楚它和GPU到底有什么不一样。1. 认清这块卡Atlas 300V 24G到底是做什么用的1.1 它是运算加速卡但和GPU不是一个物种很多人被运算加速卡这几个字带偏以为Atlas 300V 24G就是一块低配GPU。实际上它是昇腾系列里的AI推理卡核心芯片是昇腾310P。关键词是推理它擅长把已经训练好的模型跑出结果而不是从零开始训练大模型。这和NVIDIA那边A100、L40S这种训练卡或者至少兼顾训练和推理的通用GPU从骨子里就不是同一种东西。这张卡的物理形态是标准PCIe卡尺寸不大单槽或双槽带主动散热风扇整卡功耗在70W上下。插在普通x86服务器或者ARM服务器的PCIe插槽里就能用不需要外接供电这一点在边缘机房特别友好。而24G这个数字指的是板载内存容量但你别拿它和GPU的显存划等号。它的作用是给推理过程中的输入图像、中间特征图、输出结果做缓冲容量越大能同时在卡上驻留的模型越大、能并发的视频路数越多。所以回到热搜里那个问题Atlas 300V 24G是运算加速卡吗答案是它是运算加速卡但准确定位是AI推理加速卡。想拿它去训练大模型、跑Stable Diffusion微调趁早打消念头想拿它做线上推理、视频流目标检测、图像分类这类任务这个定位非常对口。1.2 为什么这类推理卡越来越受欢迎先说一个很多人忽略的点GPU计算卡如果真的部署到生产环境麻烦事比跑Demo的时候多得多。单卡动辄三四百瓦需要专门的供电线、高功率电源、暴力散热机房里多插几块就得考虑空调和电费而Atlas 300V这种推理卡几十瓦的功耗标准服务器机箱直接插供电和散热都省心。24G大内存也不是为了炫技。以YOLOv5s这种体量的模型为例权重文件也就几十MB配合图像输入输出缓冲单路占用其实很小。大内存的意义在于可以同时跑几十路视频流图像进来之后在卡上排队推理不用频繁搬运模型内存充裕了吞吐量自然就上去了。这种场景在安防、智慧园区、工业质检、车路协同里非常典型需要的就是长时间、多路数、低功耗地跑同一个模型而不是反复实验不同模型。这也是我在实际选型时愿意把它放进对比清单的真正原因。2. YOLO落到Atlas前必须想清楚的三个问题2.1 你的YOLO到底能不能转换成功很多人拿到卡的第一反应就是我直接把YOLOv8跑起来。但昇腾不认PyTorch的权重格式它认的是OM离线模型中间必须经过ONNX这个中转站。能不能中转换成功取决于你的模型里用到的算子昇腾是否支持。像YOLOv5、YOLOv6、YOLOv7、YOLOv8、YOLOX这类主流目标检测模型主干和检测头的结构在昇腾上基本都能找到对应算子转换成功率很高。真正容易出问题的是在导出ONNX时顺手把NMS非极大值抑制也包进去了或者用了一些特别冷门的自定义算子。我的建议是导出ONNX时只保留网络前向计算部分把NMS和所有后处理逻辑留在模型外面用Python或C来解决。原因有二一是ONNX里的NMS算子在不同opset版本下行为差异很大转换时经常报算子不支持二是把后处理放在CPU侧可视化调试、调整置信度阈值非常方便不用每次改完都重新转一遍OM模型。2.2 单路低延迟还是多路高吞吐这个选择决定了你的软件架构怎么设计。如果业务是实时交互比如机器人抓取、工业流水线上要逐帧判断那么你关心的是单帧延迟也就是一张图从进卡到出结果要多少毫秒。此时应该用单stream调度把AIPP预处理、模型推理、后处理挤在一起抠时间。如果业务是安防监控、视频巡逻摄像头有几十上百路每一路每秒也就一两帧需要分析那么你关心的是吞吐量也就是整卡每秒能处理多少张图。这时就不要追求单路极致延迟而是开多个stream并发让卡始终处于满载状态。Atlas 300V的24G内存这时候就发挥作用了它可以同时驻留多个推理流图像数据在设备内存里排队处理效率比一个stream硬扛高得多。2.3 图像预处理放哪边YOLO这类模型输入前要做resize、归一化、RGB通道调整。这些操作既可以在CPU上用OpenCV做也可以交给卡上的AIPP模块做。如果放在CPU侧代码简单、调试容易但每一帧图像都要在CPU和卡之间来回拷贝这个开销在高帧率场景下会吃掉不少算力如果交给AIPP它会在数据进入AI Core之前自动完成resize和归一化省掉一次甚至两次内存拷贝对吞吐量的提升非常明显。我在实际项目中是这么做的先在没有AIPP的情况下把整个流程跑通确认模型精度正确然后再在ATC转换时配置AIPP逐项把resize和归一化挪进卡里。这样每一步的问题都能隔离不会出现图像黑屏、框全丢的时候分不清是预处理问题还是模型转换问题。3. 环境准备驱动、固件、CANN版本之间的连锁反应3.1 安装顺序错一步后面全白搭这次踩坑让我印象很深。Atlas 300V的环境依赖不是装一个软件就完事而是三个组件相互配合NPU驱动、固件、CANN Toolkit。安装顺序我建议固定为驱动 - 固件 - CANN Toolkit。驱动和固件负责让操作系统正确识别卡npu-smi命令才能看到卡的型号和实时功耗CANN Toolkit则是昇腾完整的软件栈里面有ATC转换工具、pyACL运行库等我们的Python代码最终调用的是这一层。安装本身不算复杂以常见的ARM服务器为例# 驱动 ./Ascend-hdk-310p-npu-driver_23.0.rc2_linux-aarch64.run --full # 固件 ./Ascend-hdk-310p-npu-firmware_23.0.rc2_linux-aarch64.run --full # CANN Toolkit ./Ascend-cann-toolkit_7.0.RC1_linux-aarch64.run --install这里有个很现实的问题这三个组件的版本必须在一个兼容列表里不是随便拿最新版就能一起用。我在第一次搭环境时驱动装了23.0.rc2固件却刷了另一个RC版本结果npu-smi能识别到卡但加载模型时一直报设备不可用最后反查官方版本配套矩阵才发现固件和驱动需要严格配套。所以装之前先打开官方文档查好软件配套表把驱动、固件、CANN的版本一行一行对好再下载。3.2 环境变量和基础验证装完之后最直接的验证方式是执行npu-smi info能看到卡的芯片型号、内存总量、当前温度、功耗这一步能通过说明驱动和固件已经正常工作了。接下来还需要把CANN Toolkit的相关路径写进环境变量。官方给了现成的脚本source /usr/local/Ascend/ascend-toolkit/set_env.sh我建议写进~/.bashrc里因为每次开新的终端都要用手动source很容易漏。注意安装目录可能因为CANN版本差异而不同有人装在/usr/local/Ascend有人装在/opt/Ascend最好在安装日志里确认一下。这一步不做好后面运行atc或者import acl都会报找不到文件。顺带提一个容易忽略的操作CANN安装时会要求设置Python环境如果你的服务器上有多个Python版本建议用conda单独建一个环境来跑推理代码避免和系统Python里的包冲突。昇腾官方对Python版本有明确要求3.7到3.11之间视CANN版本而定用conda管理可以随时切换比在系统环境里折腾省心得多。4. 模型改造从PyTorch导出ONNX再到ATC转OM4.1 导出ONNX时不处理NMS后面会省很多事先说导出模型这一步。以YOLOv5为例仓库自带的export.py可以一键导出ONNX但出于前面说的原因我强烈建议不用默认带NMS的那个分支而是直接把model的forward输出拿下来让模型只输出原始预测张量一个包含边界框坐标、置信度和类别概率的特征图。这样导出的ONNX图结构最干净后面处理起来最顺手。导出时还需要注意opsert版本。我测试下来opset设置在12到17之间比较安全。太低的话某些算子比如ScatterND无法表达太高的话昇腾的转换器也不一定完全同步支持。另外输入尺寸建议直接固定成640x640dims固定后面ATC转换参数写起来简单性能也更稳定。你当然可以导出动态shape的模型但代价是转换时多配很多参数推理时多走一些动态内存判断没必要在业务初期给自己找麻烦。实际导出命令类似这样python export.py --weights yolov5s.pt --include onnx --opset 13 --img-size 640导出完成后用Netron打开ONNX图看一眼输入节点名字和shape这个信息后面ATC命令里要用到。多数情况下输入名是images但如果你从别处拿到的模型可能叫input.1之类的不检查清楚的话ATC转换时会卡在输入节点名字不匹配。4.2 ATC转换与AIPP配置ONNX转OM使用的是ATC工具一条命令完成。我这里给出一个在我环境里真实跑通的示例atc --modelyolov5s.onnx --framework5 --outputyolov5s_om \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --insert_op_confaipp.cfg \ --loginfo逐个说参数--model指定ONNX文件--framework5表示PyTorch导出的ONNX--output是输出的OM文件名--input_shape必须和导出的输入尺寸一致--soc_version填卡对应的芯片版本Atlas 300V系列一般是Ascend310P3但具体以你手头卡的实际型号为准不确定的话用npu-smi info看芯片型号再去配套文档里对照--insert_op_conf就是刚才提到的AIPP预处理配置文件--loginfo可以让你看到完整的转换日志失败时方便定位。AIPP配置文件是个文本文件我常用的最小配置长这样aipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_w: 640 src_image_size_h: 640 csc_switch: false rbuv_swap_switch: false min_chn_0: 0 min_chn_1: 0 min_chn_2: 0 var_reci_chn_0: 0.00392157 var_reci_chn_1: 0.00392157 var_reci_chn_2: 0.00392157 }这段配置的意思是把输入图像按RGB888格式读入不启用色彩空间转换然后每个通道减去均值0再乘以0.00392157也就是1/255。注意这里的通道顺序和YOLO训练时保持一致如果你的训练代码里是BGR顺序这里要做swpr调整否则检测框位置正确但分类全错这是我调过的真实问题。4.3 转换失败的常见报错ATC转换失败很常见不用慌。我碰到最多的是两类一类是算子不支持日志里会直接打出某个op名字比如Unsupported op XXX。这时候先确认opset版本是否偏高再查官方算子清单看是不是用了CANN不支持的稀有算子。如果模型里有自定义算子那就只能改写Detect头或者用CPU算子替代这个工作量就要单独评估了。另一类是输入shape不匹配。日志里会列出ONNX图的输入信息和你命令里的input_shape二者不一致就会中断。解决方法是严格对齐shape包括batch size、通道数、高和宽。另外还有个冷门坑ONNX里有些Squeeze、Concat算子会产生动态的shape信息ATC转换时误判导致失败这种情况下可以在导出ONNX时固定所有dims或者在ATC命令后面手动加上--input_fp16_nodes之类的参数把部分节点强制到指定精度。5. pyACL推理代码从跑通到跑稳5.1 核心链路代码模型转换完成之后推理代码用的是pyACL也就是Python版的Ascend Computing Language。整个流程可以分成五步初始化、加载模型、准备输入输出内存、执行推理、取回结果。下面这段是我习惯用的核心链路骨架注释里写清楚了每一步的作用import acl import numpy as np # 1. 初始化 ret acl.init() ret acl.rt.set_device(0) context acl.rt.create_context(0) # 2. 加载OM模型得到模型ID和描述句柄 model_id acl.mdl.load_from_file(yolov5s_om.om) model_desc acl.mdl.create_desc() acl.mdl.get_desc(model_desc, model_id) # 3. 查询输入输出的字节数 input_size acl.mdl.get_input_size_by_index(model_desc, 0) output_size acl.mdl.get_output_size_by_index(model_desc, 0) # 4. 在设备侧申请内存 ret, input_ptr acl.rt.malloc(input_size, 2) ret, output_ptr acl.rt.malloc(output_size, 2) # 5. 把预处理后的图像数据拷到设备侧 acl.rt.memcpy(input_ptr, input_size, image_data_ptr, input_size, acl.ACL_MEMCPY_HOST_TO_DEVICE) # 6. 推理 ret acl.mdl.execute(model_id, input_ptr, output_ptr) # 7. 把结果从设备侧拷回主机侧 output_host np.zeros(output_size, dtypenp.uint8) acl.rt.memcpy(output_host.ctypes.data, output_size, output_ptr, output_size, acl.ACL_MEMCPY_DEVICE_TO_HOST) # 8. 释放句柄和内存 acl.rt.free(input_ptr) acl.rt.free(output_ptr) acl.mdl.unload(model_id)这里要多说一句pyACL不同CANN版本的接口签名可能有细微差异尤其像memcpy的参数顺序、malloc的返回值形式我代码里是按我当前使用的CANN 7.0惯例写的。真到自己代码里先打开官方接口文档对着过一遍避免因为版本差异踩坑。这段骨架虽然能跑通但离稳定上线还有距离。实际项目中我把这套逻辑封装成了一个类加载模型时记录模型描述、输入输出size推理时外部传入一个numpy数组内部完成去设备侧拷贝、执行、取回这样业务代码不用直接碰ACL接口出问题也方便排查。5.2 图像前处理偷懒方案和性能差异如果你不是一个追求极致性能的人图像预处理可以直接在主机侧用OpenCV完成读图、resize、归一化、转成RGB然后把最终的数据拷贝进设备内存。优点是代码直观、好调试OpenCV的resize算法效果稳定怎么改参数都不用动模型。缺点是CPU耗时和内存拷贝耗时叠加在单路低延迟场景下还能接受多路并发时CPU会被额外占用挤占后处理时间。如果想让性能更极致就把resize和归一化全部交给AIPP。这种情况下主机侧只需要把原始图像数据按像素格式排好甚至可以直接把JPEG解码后的BGR数据原样传上去AIPP在数据进AI Core前统一处理。实测下来AIPP方案在多路并发时的整体吞吐提升非常明显因为图像的缩放归一化不再占用CPU时间服务器CPU可以专心做检测框解码和业务逻辑。代价就是前面说的AIPP一次的配置参数必须和训练时一致一旦错一个像素格式检测结果全乱排查起来比调OpenCV代码麻烦得多。我的建议是先跑通OpenCV方案验证模型精度OK再逐步把处理挪进AIPP。如果你时间充裕且项目上线周期紧我甚至建议用OpenCV方案先顶住第一轮后续性能瓶颈明确了再优化。6. 实际性能、踩坑记录与调优建议6.1 我实测的一组数据以YOLOv5s、输入640x640为例CANN 7.0环境下单stream推理一帧耗时大概在6毫秒左右连续跑两千帧耗时曲线非常平稳。开了四个stream并发之后整卡吞吐量上了一个台阶每秒能处理的帧数可以稳定到200帧以上这个数据是在CPU不参与图像缩放的AIPP方案下测出来的。如果换成OpenCV预处理单帧CPU耗时多了几毫秒多路并发时CPU成为瓶颈吞吐反而上不去。这个数据告诉我们Atlas 300V 24G单卡应对几十路720P或1080P视频流的分析任务在合理控制每路帧率的情况下是够用的。当然具体数值受模型大小、输入分辨率、CANN版本、服务器CPU性能影响很大我这组数据只作为参考别当硬指标。6.2 三个让我折腾最久的坑第一个坑是模型加载偶尔失败日志里报设备内存不足。排查了很久才发现是同一进程里反复加载和卸载模型后设备内存碎片化加上之前没有正常释放context导致内存泄漏。解决方法是进程中只加载一次模型长驻内存每次推理复用同一块输入输出内存不要频繁malloc和free。第二个坑是输出结果解码后的坐标全错。代码逻辑看起来没问题后来发现是模型输出的数据排布是NHWC格式而我按NCHW去解析导致每个通道的数据错位。YOLO输出一般以候选框维度的格式给出但不同导出方式差异很大最稳妥的办法是先在ONNX阶段弄清楚输出张量的shape和含义再按对应顺序在Python里做解码。第三个坑是推理出现了周期性卡顿每跑几百帧突然掉一拍。后来定位到是CPU侧的图像解码和后处理没有做好线程隔离解码线程占用过高导致推理线程等待。解决办法是单独开一个线程池处理图像采集成和后处理把推理线程的优先级单独设置。这类问题不是昇腾特有的但只有在长时间压力测试时才会暴露。6.3 还能怎么继续压榨性能如果业务量还在涨可以从三个方向继续优化。第一使用异步推理接口execute_async配合多个stream并行让图像搬运和计算重叠执行吞吐量能继续往上提。第二如果模型本身还能压缩可以尝试量化到INT8再转OM昇腾的INT8算力比FP16高不少但量化后精度需要重新评估目标检测模型通常能承受一定程度的量化损失但要在业务数据上做一轮完整验证。第三如果有多张卡按卡数开多个独立context每张卡跑一路业务进程扩展起来也很方便。我个人在实际操作中的体会是Atlas 300V 24G这套东西性能上限不低但对环境细节要求苛刻。它的每一个环节从驱动版本到ATC参数到pyACL接口写法都老老实实按官方配套表来跑起来基本不会太折腾一旦你自己发挥想当然地用某个新版本或者随意改接口参数问题就会接踵而至。所以如果你准备用这块卡跑YOLO最简单的路径就是先固定版本再跑通流程最后谈优化。希望这篇复盘能让你少走几个我这几个月走过的弯路。
返回列表