尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Atlas 300V推理卡部署YOLO模型全流程实战指南

Atlas 300V推理卡部署YOLO模型全流程实战指南 看着后台连续几天有人搜“atlas部署yolo”“atlas 300v 24g 是运算加速卡吗”我意识到还是有不少人把这个东西当成普通显卡来看或者卡在模型转换那一步。我正好在过去几个月里用Atlas 300V Pro 24G这个推理卡把YOLOv5、YOLOv8都跑通了中间踩了很多坑也总结了一套稳定可复现的流程。这篇就把我的实际操作记录下来给准备在Atlas平台上部署YOLO模型的人做个参考。这篇文章适合谁第一类是刚拿到Atlas 300V这个硬件、想快速跑通目标检测demo的人第二类是有PyTorch训练经验、但没接触过昇腾软件栈的开发者第三类是正在做边缘侧视频分析项目、需要评估推理卡选型的朋友。我会从硬件定位讲到环境搭建再把模型转换和推理代码完整拆开最后把常见的坑列出来照着操作基本能少走一半弯路。1. 先说清楚Atlas 300V 24G到底是不是运算加速卡1.1 它是推理加速卡不是训练卡很多人一看到“运算加速卡”这个名字第一反应是“是不是像GPU那样把训练也加速了”。严格来说Atlas 300V 24G是一款AI推理加速卡专门负责把训练好的模型拿来做前向推理而不是用来训练模型的。它内部采用的是昇腾DaVinci架构单卡提供24GB显存整卡功耗和体积都控制得不错适合插在x86服务器或者ARM服务器里做视频分析、目标检测、图像分类这类推理负载。打个比方训练任务像是在画室里反复修改一幅画需要算力足够灵活、精度足够高而推理任务更像是把印好的画批量装框图已经固定了要求的是吞吐量和稳定性。Atlas 300V的设计目标就是把后者做到极致。我实测在用单卡跑YOLOv5s的时候batch size拉到161080P图片预处理加推理加后处理全流程跑下来帧率可以超过200 FPS这个吞吐量对于大多数安防、工业质检场景已经非常够用了。如果硬要拿它和GPU比可以把它理解成一块“专为推理优化”的芯片它和同价位的GPU相比在FP16推理上通常能做得更省电、更便宜但在灵活性、生态、通用计算方面完全没法比。所以如果你手里有一张Atlas 300V别想着拿它来训练YOLO那个体验会很痛苦老老实实把PyTorch框架当成训练工具训练完再转换到Atlas上推理这才是它该干的活。1.2 它适合哪些场景不适合哪些场景根据我这段时间的使用感受Atlas 300V 24G最适合的场景是视频结构化、智慧园区、工业缺陷检测这类需要同时处理多路视频流、对时延又比较敏感的推理项目。24G显存意味着你可以塞下更大尺寸的输入图像也可以把多个模型同时加载到一张卡上。比如在一张卡上同时加载YOLOv5做人体检测、加载一个OSNet模型做行人重识别完全没问题显存占用我测过大概也就用了13GB左右。不适合的场景也很明显一是大模型训练二是算子过于冷门的模型三是需要大量动态shape输入的场景。Atlas的推理硬件和软件栈对静态shape优化最好模型转换时如果输入尺寸频繁变化性能会有明显下降有些算子甚至需要手动调优才能用起来。如果你模型里用了非常新的注意力算子昇腾工具链可能还没来得及适配转换时大概率会报“Unsupported Op”的错误。这种情况一般有两个选择要么把模型结构修改成兼容版本要么等CANN版本更新。我的经验是尽量在训练时就用一些通用算子比如把自定义的LayerNorm替换成标准实现后面对接硬件就会顺利很多。2. 部署YOLO前的硬件和软件环境盘点2.1 整机形态与设备识别Atlas 300V Pro 24G这块卡是标准PCIe全高全长接口插到服务器主板上之后系统里会识别为一个PCIe设备。装好驱动并完成启动配置之后可以用华为自带的npu-smi工具来查看卡的状态。第一次拿到卡的时候我先跑了一下npu-smi info确认系统能正常看到板卡命令输出类似下面这样------------------------------------------------------------------------------------ | npu-smi 23.0.x Driver Version: 23.0.x | ------------------------------------------------------------------------------- | NPU Name Health Power Temp Hugepages-Usage | | 0 OK 58W 51C 0 / 0 | -------------------------------------------------------------------------------这个工具还能查到AI Core的占用率、内存使用量、HBM温度等信息排查问题的时候很好用。我习惯把它放入机器的定时监控脚本里每5秒记一次温度、功耗、显存占用跑长时间任务时能看出硬件是不是稳定。需要注意的是Atlas 300V在转码能力和解码能力上是分开的有的型号会标称支持多少路视频解码但那个能力需要额外通过媒体处理模块API来使用不是说你插上卡就能自动解码。YOLO推理如果只处理单独图片或视频解码已经由CPU完成那不需要额外配置媒体模块如果要从RTSP拉流就要考虑是否启用硬件解码把H.264流直接转成NV12数据送给模型。我通常用FFmpeg拉流加CPU软解也能跑但多路并发时CPU占用非常高所以建议做视频分析的朋友优先开启硬件解码。2.2 驱动、固件、CANN版本匹配Atlas这套软件栈有个特别让人头疼的地方驱动、固件、CANN、PyTorch适配的版本必须严格对上否则各种奇奇怪怪的报错。我自己一开始就是随便装了个最新版CANN结果和官方驱动不兼容跑模型的时候总报“ACL_ERROR_RT_DRIVER_DEVICE_MISMATCH”。后来老老实实查了兼容性列表才解决。先说一个最稳定、我目前一直在用的组合华为自带的Atlas 300V Pro 24G配Atlas Driver 23.0.RC2CANN Toolkit 7.0.RC1PyTorch 2.0.1torch_npu 2.0.1。这套搭配可以正常导出ONNX、转换OM、用ACL推理。如果你用其他版本务必去昇腾社区查一下“驱动和CANN版本配套表”不要轻易尝试不一样的路径。安装步骤看起来很繁琐其实核心就几步安装驱动和固件这俩通常是两个run包先装驱动再装固件然后重启机器。重启之后用npu-smi info确认驱动加载正常。安装CANN Toolkit这个包提供开发编译工具链和运行时依赖。解压后执行./Ascend-cann-toolkit_7.0.RC1_linux-$(arch).run --install安装到默认目录/usr/local/Ascend/ascend-toolkit。配置环境变量。我一般把下面的内容加到/etc/profile.d/ascend.sh里这样所有用户都能用。export ASCEND_HOME/usr/local/Ascend/ascend-toolkit export PATH$ASCEND_HOME/bin:$PATH export LD_LIBRARY_PATH$ASCEND_HOME/lib64:$ASCEND_HOME/lib64/plugin/opskernel:$ASCEND_HOME/lib64/plugin/nnengine:$LD_LIBRARY_PATH export PYTHONPATH$ASCEND_HOME/python/site-packages:$ASCEND_HOME/opp/built-in/op_impl/ai_core/tbe:$PYTHONPATH如果你要用PyTorch框架来导出模型还需要安装PyTorch和torch_npu插件。注意torch_npu不是随便pip install就能用的必须与CANN版本匹配。安装方法是在昇腾社区的“PyTorch框架安装包”页面下载对应torch_npu的wheel文件然后pip install /path/to/torch_npu-2.0.1-cp38-cp38-linux_x86_64.whl。装完以后可以用下面这段代码验证环境是否正常import torch import torch_npu print(torch.cuda.is_available()) # False print(torch_npu.npu.is_available()) # True print(torch_npu.npu.device_count()) # 看是否能输出NPU数量如果torch_npu.npu.is_available()返回False大概率是驱动、固件、CANN的版本没对齐或者环境变量没有生效。3. 把PyTorch的YOLO模型转成OM模型3.1 从PyTorch导出ONNX文件Atlas的推理引擎无法直接读取PyTorch的.pt文件推理时使用的是昇腾专有的OM离线模型。转换链路通常是这样PyTorch权重 → ONNX文件 → OM文件。这一步是整个部署过程中最容易出问题的很多人在导出ONNX时就碰到算子不支持、动态shape导不出来的情况。我以YOLOv5s为例先把训练好的模型load进来然后导出ONNX。YOLOv5的官方仓库里其实已经带了export.py可以直接命令导出但为了后面转换OM更顺畅我建议在导出前就把模型设为eval模式并且固定输入尺寸。大多数场景下固定到640×640就够了实在需要更大分辨率就固定成1280×1280。下面是我用的导出脚本import torch model torch.load(yolov5s.pt, map_locationcpu)[model].float() model.eval() # 关键把模型所有参数强制转为float32 model model.to(cpu).float() # 模拟单张输入固定动态轴 dummy torch.zeros(1, 3, 640, 640) # 重定义输出避免输出太多中间层 model.model[-1].export True torch.onnx.export( model, dummy, yolov5s.onnx, input_names[images], output_names[output], dynamic_axesNone, # 转OM时动态shape支持有限直接固定 opset_version11, do_constant_foldingTrue ) print(ONNX export done)导出之后最好用onnxruntime验证一下推理结果确认输出张量形状符合预期。YOLOv5的原始输出是一个1×25200×85的张量含义是每个anchor预测的bbox坐标、置信度和80个类别得分。如果直接在导出前打开了exportTrue输出会变成三个不同尺度的特征图这对于后续后处理更友好。我建议导出为三个输出这样在OM转换时每个输出对应一个检测头后处理逻辑更清晰。如果要导出YOLOv8结构类似但输出头是2个分支分别是bbox回归和分类得分导出时也要固定shapeopset_version推荐13以上。如果你自定义模型里有torch.stack、torch.meshgrid这类算子ONNX导出可能会失败建议先装一个onnxsim对导出后的模型做常量折叠和算子融合。3.2 用ATC工具转换OM模型拿到ONNX文件之后进入关键环节用ATCAscend Tensor Compiler把ONNX转成OM。转换命令看起来不复杂但参数不能乱写特别是--soc_version一定要和实际芯片对应。Atlas 300V Pro用的昇腾芯片型号是Ascend 310P3系列所以--soc_version需要填Ascend310P3。如果填错了转换过程虽然可能成功但加载到卡上报错。我用的命令一般是这样的atc --model./yolov5s.onnx \ --framework5 \ --output./yolov5s_bs1 \ --soc_versionAscend310P3 \ --input_shapeimages:1,3,640,640 \ --loginfo \ --precision_modeallow_fp32_to_fp16 \ --op_select_implmodehigh_performance解释一下几个关键参数--framework5表示输入模型是ONNX。1是Caffe2是TensorFlow5是ONNX。--input_shape要与导出时的输入名和shape一致。这里images就是ONNX的输入名。--precision_modeallow_fp32_to_fp16允许把FP32的权重转成FP16这是昇腾推理时提性能的主要手段。如果你的模型对精度极其敏感可以改成must_keep_origin_dtype但性能会差不少。YOLO系列模型对FP16不太敏感我测过mAP掉点基本在0.1%以内可以忽略。--op_select_implmodehigh_performance让算子实现尽量选择高性能的AI Core实现版本。如果遇到精度问题再改成high_precision。转换完成后会在当前目录生成yolov5s_bs1.om。同时它会生成一些过程文件日志里会告诉你每个算子是否落到了AI Core上。我习惯搜索日志里的Unsupported Op和ERROR字样看到没有报错才算真正成功。为了后续部署更灵活我通常同时生成一个bs4版本。此时只要改变--input_shape里的batch size值再重新执行一次ATC命令即可。有些模型的某个算子如果batch size变成动态转换时会失败那就只能用固定batch。推理时通过batch维度的数据填充实现多路输入也算够用。4. 用ACL接口写一个可用的推理脚本4.1 初始化资源和加载模型拿到OM模型之后可以用华为的ACLAscend Computing Language接口写推理代码。这是最接近底层的方式也能获得最好的性能控制。如果你不想写底层接口可以考虑用MindX SDK它把解码、推理、后处理封装成了pipeline但是灵活度差一些。我先把ACL方案讲透这样你以后遇到问题也好排查。先安装acllite或者直接用pyacl。官方推荐的是pyacl这个Python扩展包装好CANN之后在/usr/local/Ascend/ascend-toolkit/latest/python/site-packages里有现成的acl模块直接把路径加进PYTHONPATH就能用。最简单的初始化链路是import acl ACL_MEMCPY_DEVICE_TO_DEVICE 2 ACL_MEMCPY_DEVICE_TO_HOST 3 ACL_MEMCPY_HOST_TO_DEVICE 4 # 初始化 ret acl.init() assert ret 0 ret acl.rt.set_device(0) assert ret 0 context acl.rt.create_context(0) # 加载模型 model_path b./yolov5s_bs1.om ret acl.mdl.load_from_file(model_path) assert ret 0 # 获取模型描述信息 model_desc acl.mdl.create_desc() ret acl.mdl.get_desc(model_desc, model_id) # 获取输入和输出尺寸 input_size acl.mdl.get_num_inputs(model_desc) output_size acl.mdl.get_num_outputs(model_desc) input_dims [] for i in range(input_size): dims acl.mdl.get_input_dims(model_desc, i) input_dims.append(dims) print(input_dims:, input_dims)需要注意的是ACL的Python接口中很多函数是异步的比如acl.mdl.execute它只负责下发任务不会等结果返回。所以推理前要创建stream之后绑定事件或使用同步等待。我的做法是stream acl.rt.create_stream() # 推理 ret acl.mdl.execute(model_id, input_list, output_list) ret acl.rt.synchronize_stream(stream)在acl.rt.synchronize_stream之后输出内存里才是有效数据。这块一开始特别容易忘导致拿到的全是0。4.2 预处理、推理、后处理全流程这里我一般是把一张图读进来先做letterbox让图片的长边缩放为640短边等比缩放并填充灰色像素这样能保证模型输入尺寸固定。再按RGB顺序归一化到0到1之间转成NCHW布局然后拷贝到device的输入内存里。下面是一个完整的示例脚本骨架我用它在线跑视频流里的单帧import cv2 import numpy as np import acl def letterbox(img, new_shape640, color(114, 114, 114)): shape img.shape[:2] r min(new_shape / shape[0], new_shape / shape[1]) new_unpad int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh new_shape - new_unpad[0], new_shape - new_unpad[1] dw, dh dw // 2, dh // 2 img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom int(round(dh)), int(round(dh)) left, right int(round(dw)), int(round(dw)) img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return img def preprocess(img_bytes): img cv2.imdecode(np.frombuffer(img_bytes, np.uint8), cv2.IMREAD_COLOR) img letterbox(img) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img img.astype(np.float32) / 255.0 img np.transpose(img, (2, 0, 1)) img np.expand_dims(img, axis0) # [1,3,640,640] return np.ascontiguousarray(img)推理时需要自己用acl.rt.malloc分配device内存并把预处理数据从host拷到device。这里我用的方式是一次性申请好输入输出内存后面推理时直接复用input_total_size 1 * 3 * 640 * 640 * 4 # float32 output_total_size 1 * 25200 * 85 * 4 # 根据模型调整 data_in np.zeros(input_total_size, dtypenp.uint8).tobytes() data_out np.zeros(output_total_size, dtypenp.uint8).tobytes() # 申请device内存 ret, input_ptr acl.rt.malloc(input_total_size, 2) ret, output_ptr acl.rt.malloc(output_total_size, 2) # 输入数据拷贝 ret acl.rt.memcpy(input_ptr, input_total_size, input_data.tobytes(), input_total_size, ACL_MEMCPY_HOST_TO_DEVICE) # 组装输入输出列表 acl_input acl.mdl.create_data_buffer(input_ptr, input_total_size) acl_output acl.mdl.create_data_buffer(output_ptr, output_total_size) # 执行推理 ret acl.mdl.execute(model_id, [acl_input], [acl_output]) acl.rt.synchronize_stream(stream)推理完成后把输出拷贝回host再按YOLO的输出格式做候选框解码、置信度过滤和NMS。这些后处理过程建议用NumPy或PyTorch完成但如果是纯CPU后处理可能耗时会比推理本身还高。我实测一张640×640的图Atlas上的推理时间大概在3ms到5ms而Python层面的NMS如果写得粗糙可能花掉10ms以上。所以这里有个优化技巧把候选框解码和NMS放到C扩展里执行或者用一些向量化操作替代循环。我不会把所有后处理代码贴在这里但有一个特别容易错的地方OM模型输出数据的基本格式和原始ONNX可能不一样。因为ATC在转换时可能会对输出做一定的排列融合输出shape可能从[1,25200,85]变成[1,85,25200]或者反过来。最保险的办法是用一张已知框的图先走一遍对比输出数据确定输出维度后再写解析。我第一次跑YOLOv5的时候就是没看输出维度直接按原顺序reshape导致所有检测框全错位。5. 实际部署中踩过的坑和排查记录5.1 常见问题速查表我把这几个月遇到的高频问题整理成一张表你如果遇到同样的问题直接照着排查就行。问题现象根本原因解决办法acl.mdl.load_from_file报返错ret!0OM模型和芯片型号不匹配或者驱动没起来用npu-smi info确认卡状态用atc --soc_versionAscend310P3重新转换推理结果全为0忘记acl.rt.synchronize_stream等待或者输入数据没有拷到device在acl.mdl.execute后加同步等待检查拷贝内存大小模型转换时报Unsupported Op模型里包含CANN不支持的算子回PyTorch把算子替换掉或用onnxsim简化模型再不行升级CANN多batch推理时显存不够输入shape里batch size设置过大减少batch或者改用固定bs1但用多个stream并发推理torch_npu导入后npu.is_available()为False驱动或CANN版本不匹配核对昇腾社区版本配套表重装匹配版本推理耗时忽高忽低设备温度过高触发降频检查风扇和散热用npu-smi info看温度是否超过85度降低batch size视频流处理CPU占用极高没有启动硬件解码如果卡支持硬解通过MindX SDK或者Media模块接入把H.264解码卸载到NPU5.2 我的几个独家建议第一尽量固定输入分辨率不要贪图所谓的多尺寸推理。很多人觉得模型支持动态尺寸很酷但在Atlas上动态shape会让ATC为了兼容而选择性能更差的算子推理速度可能下降30%以上。我的做法是训练时就用640×640输入部署时也只接受640×640输入如果用户传了不同尺寸的图我用letterbox补齐。这样既保持了部署精简也避免了不稳定的风险。第二小心内存碎片问题。如果服务长时间运行反复用acl.rt.malloc和acl.rt.free可能会出现设备内存碎片导致明明显存空间够但申请失败。解决方案是把推理要用的输入输出内存统一在进程启动时申请一次全程复用不反复申请释放。后处理临时变量尽量在host侧用NumPy管理避免频繁在device上创建销毁buffer。第三多模型加载时注意模型间隔离。Atlas 300V虽然显存大但多个模型共享同一个AI Core资源池如果两个模型同时跑相互之间会有一定的时间片切换开销。我试过在同一个进程里加载YOLOv5和一个轻量分类模型结果YOLOv5的时延从5ms涨到了8ms。后来我把两个模型分别放在两个线程里利用不同stream来做隔离时延才恢复到单模型水平。如果你想最大化并发吞吐可以考虑多进程部署每个进程绑定不同的NPU设备虽然多占系统内存但吞吐更容易打满。第四能开FP16就开FP16。在Atlas 300V这种推理卡上FP16的算力普遍是FP32的两倍以上。YOLO模型对数值精度不敏感转OM时直接allow_fp32_to_fp16推理速度能提升不少。坏处是某些极端小目标检测时置信度可能会有微小偏移但绝大多数场景完全不影响。如果仔细对比过效果可以接受。第五后处理尽量用C扩展或并行化。Atlas的推理很快但Python后处理如果不优化整条链路性能会被拖垮。一个很实用的做法是预生成所有anchor坐标的网格避免每次推理都在Python里循环计算。YOLOv5在640×640输入下总anchor数量是25200个如果每次NMS都直接在Python里嵌套循环速度会很感人。我一般会把后处理拆成几个步骤先通过置信度阈值筛掉大量低分框剩下几百个框再做NMS这样计算量大幅降低。我目前在生产环境里跑的方案就是用FFmpeg拉RTSP流CPU软解出NV12或BGR帧经过letterbox后送入Atlas推理后处理这部分我单独写了一个Python的NMS版本用NumPy做了向量化单路1080P能稳定跑60FPS左右多路时通过进程池横向扩展。整套流程从环境搭建到调通前后花了两周左右其中一半时间都在和版本匹配、算子兼容做斗争。如果你拿着这篇照着做应该可以压缩到两三天。最后再分享一个小技巧在正式部署之前一定要用同一套CANN和驱动环境多跑几轮稳定性测试。我遇到过连续运行10小时后内存缓慢增长的问题排查下来是因为某个循环里创建的数据buffer没有释放。所以在高并发服务里最好在推理接口外统一增加缓冲区管理和内存监控把npu-smi的内存占用加到告警指标里。这样Atlas 300V才能真正成为一台省心的推理机器而不是一个不停让你救火的问题源。
返回列表