ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Atlas 300V 24G部署YOLOv5实战:环境搭建、模型转换与推理优化

Atlas 300V 24G部署YOLOv5实战:环境搭建、模型转换与推理优化 这阵子我一直在折腾一块华为Atlas 300V 24G目标是把手里的YOLOv5检测模型从GPU环境迁过来稳定跑出能上线的性能。查资料的时候发现很多人都在问同一个问题这块卡到底是不是运算加速卡怎么才能把YOLO这类常见模型部署上去所以干脆把整个实操过程整理成一篇笔记从硬件定位、环境搭建、模型转换到推理代码和踩坑记录尽量一次讲完整。如果你手头正好有一张Atlas 300V 24G或者你的项目正在考虑用昇腾设备做视频图像类的AI推理这篇笔记会很有参考价值。即便是第一次接触昇腾体系只要照着步骤一步步来也能避免很多我当初绕过的弯路。1. Atlas 300V 24G到底是不是运算加速卡1.1 先看规格这块卡的真实身份结论先说是的Atlas 300V 24G就是一块深度学习推理加速卡不是GPU但它在AI推理领域做的工作和GPU加速卡非常类似。严格来说它属于昇腾Ascend系列的推理加速产品核心是昇腾310P系列芯片板载24GB内存支持FP16和INT8混合精度的推理计算。普通PC上的显卡走的是CUDA生态而这块卡走的是昇腾自己的CANNCompute Architecture for Neural Networks计算框架。CANN的定位类似于NVIDIA CUDA下面跟着的是ACLAscend Computing Language运行时接口。你用惯了PyTorch的话可以暂时把它理解成一套“不能直接跑PyTorch模型但可以把模型转换成离线格式后高效执行”的异构计算环境。很多初学者拿到这块卡第一反应是“为什么不能直接用PyTorch的.pt文件跑”这个后面会细讲核心原因就是昇腾的设备有自己的指令集和内存管理方式必须通过工具链把模型转换成OMOffline Model格式推理时才能发挥硬件的性能。1.2 它不是GPU但也不是一个简单的外设Atlas 300V 24G从物理形态上看是一张PCIe加速卡插在服务器主板上就会多出一个推理设备。和普通显卡不一样的是它通常不输出显示画面也没有显示器接口。它的使命很纯粹接收图像输入完成神经网络推理计算输出结果。从开发角度讲你可以把这套环境分成四层来看底层是昇腾硬件设备负责实际的计算和存储上面一层是CANN运行时包含ACL、runtime等库文件负责管理设备、加载模型、执行推理再上面是模型转换工具ATC把ONNX、TensorFlow等格式的模型转换成OM格式最上层是业务代码可以用Python或C调用ACL接口把数据送进去并取回推理结果。知道了这四层你就能理解很多部署过程中的报错了要么是驱动层没装好要么是模型转换层出了问题要么是推理代码里面申请资源时类型不对。排查的路径也就清晰很多。1.3 这块卡适合什么场景24GB内存这个参数非常诱人它意味着你可以装得下一个比较大、batch稍大的检测模型或者同时跑多个小模型。在视频分析场景里比如工厂质检、园区安防、交通流量统计一个设备要同时处理多路视频流24GB容量能够支撑同时加载多个目标检测模型或分类模型这是它的现实优势。实际应用中用这块卡的人一般不会只跑单个模型而是会做一个“预处理→多个模型并发推理→后处理”的完整流水线。Atlas 300V的硬件编解码单元DVPP还能负责视频解码和图像缩放把CPU彻底解放出来整个链路吞吐量可以做得比较可观。2. 动手前的环境准备与硬件安装2.1 检查服务器硬件和系统版本先别急着插卡装软件。我遇到的第一个坑就是主板兼容性Atlas 300V 24G对主板BIOS设置和PCIe插槽有要求你需要确认服务器有空余的PCIe x16插槽并且供电足够。插卡后开机在BIOS里要打开项目确保系统能正确识别到新的PCIe设备。操作系统方面主流支持的是Ubuntu 18.04/20.04 or CentOS 7.6等版本。可以用下面命令查看当前内核uname -a cat /etc/os-releaseCANN版本对系统版本有对应关系安装前最好去昇腾社区对照一下你选的CANN版本驱动的兼容列表。我个人的建议是直接选Ubuntu 20.04 x86_64配最新的CANN 7.0.0或更高版本文档和问题样本都比较丰富。2.2 安装驱动、固件和CANN工具包在昇腾的体系里软件安装分两部分一部分是驱动和固件NPU driver和firmware一部分是CANN计算框架。一定要先装驱动和固件再装CANN。如果你是第一次安装下载驱动时会看到好几个软件包比如Ascend-cann-toolkit、Ascend-cann-nnal、Ascend-cann-kernels。我的建议是全部完整安装因为模型推理时会用到NPU上的算子实现如果只装了一部分很可能在运行某个自定义算子时报错。安装命令非常直接以driver为例./Ascend-hdk-310series-npu-driver_version_linux-x86_64.run --install ./Ascend-hdk-310series-npu-firmware_version_linux-x86_64.run --install装完后启动相关服务然后利用系统自带的工具检查设备是否正常npu-smi info如果能看到类似表格的信息显示芯片名称、温度、内存占用等恭喜硬件部分已经成功了。没有看到的话需要回到驱动安装和系统日志里面排查这部分放到最后一节来说。2.3 配置环境变量安装完CANN后CANN的目录结构通常会放在/usr/local/Ascend/ascend-toolkit/latest。运行ATC、调用Python库时都要用到其中的环境变量按照官方文档在~/.bashrc里加上下面几行source /usr/local/Ascend/ascend-toolkit/set_env.sh export LD_LIBRARY_PATH/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:$LD_LIBRARY_PATH export ASCEND_AICPU_PATH/usr/local/Ascend/ascend-toolkit/latest然后source ~/.bashrc在终端里运行atc --version能打印出版本信息说明环境基本就绪了。3. YOLO模型迁移从PyTorch到OM的完整链路3.1 为什么不能直接扛着.pt文件上卡很多人在这一步卡住原因很直接昇腾NPU不能直接执行PyTorch的.pt文件。PyTorch模型里面包含大量Python端逻辑和动态图结构而NPU更习惯执行那种静态的、算子和内存布局都已经确定好的计算图。所以标准路径是使用PyTorch权重导出ONNX图在ONNX上面做算子融合、裁剪等优化用ATC工具将ONNX图转换成OM格式推理时只用ACL加载OM模型不再依赖PyTorch。整个过程其实就是一个“把模型编译成硬件指令集”的过程。你可以类比成C代码要先编译成可执行文件才能运行而.pt文件像Python源码解释执行的效率自然没那么高。3.2 导出ONNX时最容易踩的坑YOLOv5的官方代码已经非常成熟直接提供exporter脚本。我们最常用的一条命令是python export.py --weights yolov5s.pt --include onnx --opset 11 --dynamic这里面的--dynamic参数值得单独提一下。如果你想要在推理时自由切换batch大小或者输入分辨率可以打开动态shape。但如果你跑的是多路固定分辨率的视频流我建议导出成固定shape的ONNX原因下面篇幅马上讲到。导出后使用onnxsim简化一下模型很多冗余reshape和transpose会被清理掉后面ATC转换的成功率也会提高pip install onnxsim python -m onnxsim yolov5s.onnx yolov5s_sim.onnx简化ONNX对ATC的算子识别影响很大尤其是在后处理里面用到的一些奇特切片方式简化后能减少转换报错的概率。3.3 使用ATC转换成OM离线模型有了ONNX之后执行ATC命令。这里以固定batch1、输入大小为640x640的YOLOv5s为例atc --modelyolov5s_sim.onnx \ --framework5 \ --outputyolov5s_bs1 \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --output_typeFP16几个参数的含义要记清--framework5表示输入模型是ONNX格式--input_shape严格对应模型输入节点的名称和shape如果和实际ONNX中的名字不一致后面会报输入节点找不到--soc_version要根据npu-smi里的芯片型号来填不同CANN版本支持的写法有细微差别具体可以用npu-smi info查到的芯片型号去文档里对应--output_typeFP16强制转换成半精度模型这对推理加速非常友好但要注意精度是否满足项目要求通常检测场景下影响很小。转换的过程会打印一波日志涉及算子映射和优化结果。我最常干的事情就是盯住是否出现“successfully”或者“ERROR”字样。如果成功会生成yolov5s_bs1.om文件。好的情况下整个转换过程从几十秒到几分钟不等。3.4 固定batch与动态shape怎么权衡关于动态shape我多说一句。动态shape最大的优势是灵活可以在不同分辨率输入之间切换但代价是ATC开启dynamic shape后生成OM模型的结果往往包含多份分支占用空间更大推理性能也会打一些折扣。对于绝大多数固定分辨率的摄像头画面直接用固定shape反而更高效。实际操作中你会看到很多人用--dynamic_batch_size 1,2,4或者--dynamic_image_size 640,640;1280,960这种做法在需要多分辨率场景时很实用但如果你只是单分辨率跑流水线别在这里过度设计。YOLOv5的部署通常就按640或者1280来推理固定shape最快稳。4. 推理代码编写与性能优化4.1 最小可用的ACL推理脚本CANN提供了Python的ACL接口可以使用pyacl或者acllite简化开发。但为了让你理解底层到底做了什么我建议至少掌握一段最基础的ACL代码。下面是一段最低限度的推理脚本负责把一张111形状的图像数据送进OM模型并取回输出张量import acl import numpy as np def init(): ret acl.init() assert ret 0 ret acl.rt.set_device(0) assert ret 0 context, ret acl.rt.create_context(0) assert ret 0 return context def load_model(model_path): model_id 0 ret acl.mdl.load_from_file(model_path, model_id) assert ret 0 return model_id def inference(model_id, input_data, input_size): desc acl.mdl.create_desc() acl.mdl.get_desc(desc, model_id) _, input_dims acl.mdl.get_input_dims(desc, 0) input_data np.ascontiguousarray(input_data, dtypenp.float32) data_len input_size data_ptr acl.util.numpy_to_ptr(input_data) output_size 8400 * 85 * 4 # YOLOv5s固定输出近似大小 output_data np.zeros((output_size,), dtypenp.float32) output_ptr acl.util.numpy_to_ptr(output_data) data_buf acl.rt.malloc(data_len, 2) output_buf acl.rt.malloc(output_size, 2) acl.rt.memcpy(data_buf, data_len, data_ptr, data_len, 1) acl.rt.memcpy(output_buf, output_size, output_ptr, output_size, 2) dims [1, 3, 640, 640] ret acl.mdl.execute_async(model_id, data_buf, output_buf, dims, 0) assert ret 0 acl.rt.synchronize(0) acl.rt.memcpy(output_ptr, output_size, output_buf, output_size, 1) output output_data.reshape([1, 84, 8400]) # 实际布局因转化选择而异 return output需要说明的是上面的代码只演示了核心逻辑没有做资源释放和异常处理而且不同CANN版本的接口名可能略有差异。参考的时候必须结合你安装的CANN版本对应API文档来调整函数名和参数类型。4.2 后处理从raw tensor到检测框ONNX转换后YOLOv5的输出通常是[1, 84, 8400]这样的维度8400就是640x640输入下所有特征图位置的候选框数量84是4个坐标信息加80个类别概率。需要在后处理里面完成候选框解码、NMS过滤才能得到最终检测框。在Atlas设备上很多做部署的人会把后处理逻辑从CUDA搬到CPU上跑用numpy实现就够了def decode_output(output, conf_thres0.25): output output[0].transpose(1, 0) # [8400, 84] boxes output[:, :4] # [cx, cy, w, h] scores output[:, 4:] class_ids scores.max(axis1) mask class_ids conf_thres boxes boxes[mask] class_ids class_ids[mask] # 再把中心点格式转换成xyxy或者xywh ...这里最关键的是搞清楚你的ONNX模型在后处理部分有没有被处理过。YOLOv5原始导出模型输出的是预测的原始值需要做sigmoid和anchor解码而有的自定义导出图会直接输出解码后的框坐标。你可以在导出OM前用ONNX Runtime先跑一遍同一张图确认输出含义再写后处理代码这个习惯能省下大量调试时间。4.3 用DVPP做预处理把CPU占用降下来在真实项目中摄像头或视频文件的解码、缩放、色域转换是不能省的成本。如果这些操作全放在CPU上做Atlas推理再快也顶不住。Atlas设备自带DVPP硬件单元专门处理JPEG解码和图像缩放这是20多年经验里最值得利用的部分。使用DVPP接口的方式在不同CANN版本里有一定变化但整体思路是调用aclvdec或aclvenc接口解出视频帧使用aclresize把图像缩放到模型输入尺寸再把RGB图像转成NHWC或NCHW数据拷贝到device内存。这样模型输入侧拿到的是直接在设备侧准备好的张量CPU几乎不参与图像格式转换吞吐量能明显提升。如果你的业务是实时视频流检测这一步一定要做否则推理卡的利用率会很低。4.4 让性能再往前挤一挤的几个技巧如果你的目标是多路视频同时检测有几个优化策略比较常用:开多stream: ACLE支持多stream并发执行不同stream可以同时推理不同帧合理设计stream数量和推理卡负载能明显提高吞吐量。通常可以先用2到4个预置stream测试观察NPU利用率和设备温度。固定batch进入推理: 如果你的设备内存足够可以合并多个帧组成一个batch同时推理减少不同step间的切换开销但前提是模型在ATC转换时选择了固定batch。不要为了batch而batch大batch会让单帧延迟略微增加所以它更适合注重吞吐量、不注重单帧延时的场景。用acl.mdl.execute_async异步执行: 让预处理、推理、后处理流水线化减少等待。推理期间CPU就可以继续准备下一帧这种并行使整体耗时显著下降。我还发现很多人在做性能统计时有个误区只看单纯的模型推理耗时不看整体流水线耗时。实际上NPU推理真正的时间可能只有几毫秒到十几毫秒而前处理和后处理往往占用大量时间。如果你追求端到端性能一定要用画质稳定、帧数固定的视频流来压测别拿几张静态图去估吞吐。5. 实际操作中遇到的常见问题与排查5.1 驱动装完设备不出现在npu-smi里这是最常见的一个问题。通常发生的情况是驱动安装没有报错但npu-smi info看不到设备信息。我的排查顺序是这样重新插拔卡确认PCIe槽位接触良好确认BIOS中4G以上解码、SR-IOV等选项打开有些服务器默认没开导致设备无法被系统识别观察dmesg | tail里面是否有“unknown device”或“failed to load”的信息确认驱动与固件版本匹配先升级固件再重装驱动往往能解决奇怪的识别故障。有一次我遇到的坑是系统里残留了旧版驱动的内核模块新驱动覆盖不干净导致NPU设备反复掉线。解决方法是彻底卸载旧驱动重启后再安装新版本。5.2 ATC转换报E10008算子不支持E10008错误一般翻译过来就是“某个算子不在ATC支持的范围内”。YOLOv5原版导出ONNX时会包含少量特殊操作譬如映射、滤波类算子这些算子不一定能在昇腾上直接映射。我的处理技巧是分两步走先检查ONNX版本和onnxsim是否运行正常再用to_net里的AutoBS选项或者--op_type_list手动搜索是哪个算子对应不上。如果确定是某个算子卡住了可以尝试修改导出代码把该算子对应的结构替换成另一种等价实现比如把hardswish替换为relu6加缩放或者直接用--insert_op_conf指定插入算子来绕过编译失败。5.3 推理结果全零或者检测框错位遇到这个问题的第一反应往往不是模型坏了而是预处理和后处理不一致。YOLOv5用的是0到1归一化有的代码习惯把像素除以255有的直接使用0到255如果预处理和推理时不一致结果自然就是错乱的。我建议调试时先在ONNX Runtime上跑一段单张图的推理结果确认输出range和shape再对比Atlas侧的输出这样能快速定位是模型转换问题还是数据流转问题。第二种常见情况是输入图像在送入前进行了BGR和RGB的转换但做反色或者通道交换的代码位置不对。新建一个纯色图片挨个通道排查代码是最快的办法。5.4 显存占用突然暴涨或者不释放Atlas 300V 24G的设备内存管得比较严格。如果推理代码里创建了很多acl.rt.malloc或临时tensor却没有及时acl.rt.free运行久一点就会出现设备内存不足的报错。这个进程还会导致下一次模型加载失败。我现在写代码的习惯是每条推理路径结束后统一回收data_buf、output_buf和dataset。严格要求自己别指望Python的垃圾回收机制能处理设备侧的内存。内存泄漏的排查也比较简单在循环里打印acl.rt.get_mem_info(0)观察内存变化情况如果一直增加肯定是哪里漏了。另外acl.mdl.execute_async异步执行的时候一定要记得调用acl.rt.synchronize否则后续内存释放可能提前于推理完成造成隐性bug。这类bug极难定位通常是随机性崩挂或数据损坏。5.5 使用多模型时的内存规划问题Atlas 300V 24G虽然内存大但如果你同时加载五六个模型还是要做一点规划。设备上的内存包括模型算子占用的固定内存和推理时的工作内存虽然模型不用时卸载但多个模型之间存在碎片化问题。建议在启动业务的时候提前规划模型清单按需加载。实在需要在同一块卡上跑不同业务时可以做一层模型管理器按照路由策略动态加载和卸载模型复杂程度高但是不要让多个服务同时向同一设备乱扔推理请求否则很容易出现同设备竞争导致的排队延迟。最后分享一点个人心得用Atlas 300V 24G跑YOLO部署这件事情我最深的体会是昇腾整个工具链并不是不能干活而是它的思考方式跟CUDA惯性不太一样。初期需要花时间把ATC转换、ACL资源管理和数据布局理清楚之后就能稳定地跑视频检测类业务。如果你是从GPU迁移过来的不要在一开始就追求性能最大化先跑通一条最简单的静态batch链路把整个流程走顺了再开始调优这样踩坑的面积会非常小。另外做这类部署项目时一定要保留一份可复现的环境记录包括CANN版本、驱动版本、ONNX导出代码、ATC参数和推理脚本的git历史。我吃过好几次亏某个模型在一个环境里转得出来换了一台机器就报一堆算子错误后来一核对发现是CANN版本不一致。昇腾社区的工具链变化很快锁版本永远比追新版本更让人省心。
返回列表