ARTICLE DETAIL

资讯详情

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

Atlas 300V 24G上部署YOLO:从ONNX转OM到NPU推理调优全指南

Atlas 300V 24G上部署YOLO:从ONNX转OM到NPU推理调优全指南 手里有一张Atlas 300V 24G专门用来跑YOLO推理。说句实在话这两年AI推理卡的行情大家都懂GPU要么贵要么等货很多做安防、质检、边缘侧视觉项目的朋友都把目光盯上了昇腾这套方案。Atlas 300V算是我个人实测下来性价比比较合适的一张卡24G显存版本尤其适合多路视频流同时做目标检测。这篇文章不聊虚的就围绕两个核心问题展开Atlas 300V 24G到底是什么级别的加速卡、值不值得用以及怎么在Atlas 300V上把YOLO模型从PyTorch一路部署到NPU跑通推理并调优。内容来自我自己踩坑的记录涉及环境搭建、模型转换、推理代码、性能调优和问题排查给正在评估昇腾方案或已经在部署路上碰壁的朋友一个参考。1. Atlas 300V 24G到底是运算加速卡吗1.1 名字拆解Atlas、300V、24G各代表什么先回答热搜里那个问题Atlas 300V 24G确实是运算加速卡但它不是GPU那种通用并行计算卡而是一张专门为AI推理场景设计的NPU加速卡。很多人第一次接触这个名字时会被搞晕我把它拆开讲。Atlas是昇腾AI硬件的产品系列名对标的是整个AI计算产品线。300V本质上对应的是昇腾310系列芯片也就是专门面向边缘计算和推理场景的那颗处理器。最后的24G指的是板载内存容量我这里拿到的版本是24GB也有16GB版本存在。所以完整理解就是这是一张基于昇腾310芯片、具备24GB板载内存、插在服务器PCIe插槽上用的AI推理加速卡。它主要干的事情是把训练好的模型拿过来做前向计算也就是推理而不是用来训练模型。很多人问它是不是运算加速卡答案当然是只不过它的运算能力是定向为AI推理服务的。1.2 昇腾芯片的核心达芬奇架构不同于GPU真正决定Atlas 300V使用方式的是它底下的昇腾310芯片架构。昇腾芯片用的是达芬奇架构和NVIDIA GPU的CUDA核心思路完全不同。达芬奇架构里最基本的计算单元是AI Core每个AI Core内部又包含Cube单元、Vector单元和Scalar单元分别应对矩阵运算、向量运算和标量运算。用一个不太严谨但好懂的说法GPU是很多个简单的核心一起上适合各种并行计算昇腾的AI Core则更像是为矩阵乘法量身定做的流水线在卷积、全连接这类深度学习算子上有比较高的能效比。这也是为什么Atlas 300V在跑YOLO这类卷积神经网络时单卡能顶住多路视频流但你要拿它去做通用计算或者跑科学计算那就不太合适了它的设计目标里压根没有那些场景。所以搞清楚一个重要结论Atlas 300V 24G是运算加速卡但它加速的是AI推理不是通用计算。这决定了后面所有部署流程都和GPU路线不太一样。1.3 训练卡还是推理卡定位要分清在AI硬件里训练和推理是两个差别很大的场景。训练要算梯度、要反向传播、要大数据量反复迭代对算力和显存的压力都很大。推理只是把训练好的模型跑一遍前向计算对算力要求低很多但对延迟、功耗、成本更敏感。Atlas 300V明确是推理卡适合的是模型已经训练好、需要上线跑业务的阶段。比如摄像头拍到的画面要实时检测人和车工厂产线上的图片要实时判断有没有缺陷这些场景都是推理。另外还需要注意Atlas 300V是插在服务器上的PCIe卡形态不是那种小盒子边缘盒子但它也常被用在边缘服务器或一体机里。我自己有一个很直观的感受如果项目本身已经用GPU完成了模型训练和验证到上线阶段发现GPU卡不够用或成本太高这时候把推理部分转到Atlas 300V上是一个值得认真考虑的方案。训练继续留在GPU推理切到昇腾这个混合架构我在好几个项目里都验证过完全走得通。2. 部署前必须搞懂的几个概念2.1 ONNX、OM、CANN、ACL这些名词一锅端昇腾部署路线和GPU路线最大的不同在于模型格式和运行环境。在NVIDIA那边PyTorch模型可以直接转TensorRT或者直接跑工具链相对统一。到了昇腾这边你会听到一串新名词ONNX、OM、CANN、ACL、ATC。一开始确实容易搞混我一个个讲清楚。ONNX是一种开放的神经网络模型交换格式相当于模型的标准交换文件。你在PyTorch里训练好的模型先导出成ONNX这一步的目的就是让模型脱离PyTorch框架变成一个中立的中间表示。OM是昇腾的离线模型格式是模型在NPU上能够直接加载执行的格式后缀通常就是.om。从ONNX到OM的转换工具叫ATC全称Ascend Tensor Compiler。CANN是昇腾的计算架构相当于CUDA在NVIDIA体系里的位置它包含了运行时、驱动、算子库、图编译器等全套软件栈。ACL是AscendCL是CANN提供的编程接口你写推理代码时就是调用ACL的API来加载OM模型、准备输入数据、执行推理、获取输出。还有一个常见工具叫MindSpore Lite它是昇腾生态里偏向端侧和移动侧的推理框架也支持加载OM模型。我在实际项目中大多直接用ACL的Python接口因为更接近底层、依赖更少、调试更直接。2.2 为什么AI推理卡部署比GPU多一套模型转换很多从GPU转过来的人会问一个问题为什么PyTorch模型不能直接在NPU上跑答案是NPU硬件不认识PyTorch模型里的算子需要先经过图编译把网络中的每个算子映射到硬件上可执行的指令这个过程就是ATC转换。你可以把ONNX模型理解成一张乐高图纸图纸上画了每个积木块怎么搭。GPU的执行方式是让通用核心去读图纸、照着搭每个GPU核心都能灵活处理各种图纸。但昇腾NPU更像一条专用流水线它需要你先根据图纸把每个积木块预制成流水线上能处理的规格再打包成OM格式。这样一来运行时就不需要再去解释图纸内容直接按预设好的指令执行效率和确定性都更高。所以模型转换不是多此一举而是NPU架构的必然要求。这也带来了一个非常实用的经验很多在GPU上能跑的模型到了昇腾这边未必能转换成功因为ONNX里的某些算子ATC不一定支持这时候需要做算子替换或者模型结构调整。这个过程虽然有些麻烦但跑通一次之后后面再部署其他模型就顺了。2.3 硬软件版本匹配是第一步在昇腾这套体系里版本匹配的重要性怎么强调都不为过。硬件固件、驱动、CANN Toolkit、MindSpore或PyTorch适配层这几者之间是有严格的版本对应关系的。我在第一次部署时就吃过亏CANN版本和固件版本不匹配导致npu-smi能看到卡但一初始化就报错。从实际操作顺序上来说建议先确定CANN版本再根据CANN版本要求去匹配驱动和固件。昇腾官方的CANN安装文档里一般会有一个版本配套表列清楚了某个CANN版本对应哪一版驱动固件。下载固件和驱动时注意看版本号不要一味求新。越是生产环境越要用经过验证的稳定版本组合而不是追最新版。另外你所在的操作系统也需要提前确认。Atlas 300V对操作系统有支持列表常见的是CentOS、Ubuntu和openEuler。我自己用的是Ubuntu 20.04 x86_64算是支持得比较好的组合。如果你用的是比较偏门的Linux发行版后面配置起来会多很多折腾。3. 环境搭建与CANN安装3.1 检查物理环境与固件拿到Atlas 300V 24G之后第一步不是装软件而是先确认硬件能被系统正确识别。把卡插到服务器的PCIe x16插槽上开机进入系统后先用lspci命令看一下有没有昇腾设备。lspci | grep -i ascend正常能看到类似Huawei Technologies Co., Ltd. Ascend 310这样的输出。看不到的话优先检查PCIe插槽是否插紧、主板BIOS里PCIe是否正确启用以及供电是否足够。Atlas 300V的功耗不算高但服务器电源建议留足余量。硬件识别没问题后需要安装NPU固件和驱动。这里说的固件是跑在芯片上的底层固件驱动则是操作系统和固件之间的通道。官方提供的安装包通常是一个.run文件直接在root权限下执行即可。chmod x Ascend-hdk-310-npu-driver_版本_linux-aarch64.run ./Ascend-hdk-310-npu-driver_版本_linux-aarch64.run --full执行完之后可以用npu-smi命令验证这个工具相当于NVIDIA的nvidia-smi。npu-smi info能显示出卡的温度、显存、芯片使用率等信息就说明驱动和固件层没问题了。如果npu-smi报错或者显示不出来大概率是版本不对或者安装顺序出错这时候把驱动卸载重装是最快的排查方式。3.2 安装CANN Toolkit驱动没问题之后接着装CANN Toolkit。CANN是整个昇腾软件栈的核心安装包体积不小下载前先确认磁盘空间充足我建议至少预留5GB以上。CANN Toolkit安装方式同样很简单就是一个.run安装包按提示把安装路径设置好即可。我习惯安装在默认的/usr/local/Ascend目录下这样后续找工具和环境变量都比较方便。chmod x Ascend-cann-toolkit_版本_linux-x86_64.run ./Ascend-cann-toolkit_版本_linux-x86_64.run --full如果你是第一次从GPU转向昇腾装完CANN后别急着跑模型先花半小时把它的目录结构摸一遍。重点看这几个目录/usr/local/Ascend/ascend-toolkit/latest下的opp算子包、atc转换工具、acllibACL运行时。了解每个目录是干嘛的后面排错时能省很多时间。3.3 配置环境变量与验证安装CANN装完以后环境变量是必须手动配置的。我建议把下面这段写入/etc/profile或者~/.bashrc里具体路径根据你的实际安装目录调整。export ASCEND_HOME/usr/local/Ascend/ascend-toolkit/latest export PATH$ASCEND_HOME/bin:$ASCEND_HOME/atc/ccec_compiler/bin:$PATH export LD_LIBRARY_PATH$ASCEND_HOME/lib64:$ASCEND_HOME/atc/lib64:$LD_LIBRARY_PATH export ASCEND_AICPU_PATH$ASCEND_HOME export ASCEND_OPPER_PATH$ASCEND_HOME/opp配置完成后手动source一下然后敲一个最简单但有意义的命令来验证环境atc --version能正常显示ATC版本号基本说明CANN主程序安装成功。如果想要更进一步的验证可以找一个官方自带的示例模型做一次完整的ATC转换和离线推理。官方文档里有很多resnet50之类的例程跟着走一遍你会对整个流程建立非常直观的认知。这里必须提醒一句如果你打算在conda环境里使用昇腾的Python库检查一下当前环境的Python版本是否在CANN支持范围内。我之前碰到过一个很隐蔽的问题conda默认Python版本太高导致aclruntime的so库加载失败所有程序一启动就像什么都没发生一样卡住。4. YOLO模型转换与推理部署全流程4.1 准备YOLO权重并导出ONNX接下来进入正题把YOLO模型部署到Atlas 300V 24G上。我用的是YOLOv5作为例子这套流程对YOLOv8也类似只是导出脚本和参数名略有差异。第一步是在GPU环境或CPU环境准备权重的ONNX导出。以YOLOv5为例官方仓库的export.py可以直接完成转换。需要注意导出的ONNX必须确保输入输出的shape是固定的最好是batch为1的静态shape避免后续ATC转换时出现动态shape不支持的问题。python export.py --weights yolov5s.pt --include onnx --img-size 640 640 --batch-size 1 --opset 11之所以opset版本选11是因为昇腾ATC对ONNX算子的支持范围里opset 11是最稳妥的。部分新版本opset会引入ATC还不支持的算子导致转换失败。导出成功后可以用onnx.checker做一次校验确认模型结构没问题。这一步很多人会跳过但我建议不要省因为ONNX本身如果结构异常后面ATC转换的报错信息会非常让人迷惑排查成本反而更高。python -c import onnx; monnx.load(yolov5s.onnx); onnx.checker.check_model(m); print(ONNX OK)4.2 使用ATC完成ONNX到OM的转换ONNX文件准备好之后就要用ATC工具把它转换成昇腾的离线模型OM格式。ATC的核心思路是把ONNX的计算图读进来经过算子调度、格式转换、内存复用等优化后生成硬件可直接执行的模型文件。下面是我在实际项目中用得很频繁的一条转换命令atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_bs1 \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310 \ --insert_op_confaipp.cfg \ --output_typeFP32重点解释几个参数。--framework5表示输入模型是ONNX格式。--input_shape定义了模型的输入尺寸这里batch为13通道640x640。--soc_version指定芯片类型Atlas 300V对应的是Ascend310。--insert_op_conf是AI预处理配置可以在这里配置图像缩放、归一化等操作把这些计算下沉到硬件上完成。关于图像预处理需要多解释一句。YOLO训练时通常有归一化操作也就是把像素值除以255可能还有减均值除方差的操作。在GPU上推理时这些操作都在预处理代码里完成。在昇腾上你可以选择在Host端用OpenCV做预处理也可以把预处理配置到AIPP里让NPU在数据进入模型前自动完成。我推荐把归一化和resize放到AIPP里不仅能减少Host端的CPU占用整个pipeline也更简洁。aipp.cfg文件示例如下aipp_op { aipp_mode: static input_format: RGB888_U8 mean_value: 0.0 0.0 0.0 min_value: 0.0 0.0 0.0 max_value: 255.0 255.0 255.0 }转换完成后检查一下是否生成了yolov5s_bs1.om文件以及文件大小是否合理。一个YOLOv5s的OM文件大概在几十MB到一百多MB之间如果生成的OM文件异常小说明模型转换可能只做了一部分算子映射后续推理时会报算子不支持的错误。4.3 基于ACL的Python推理代码有了OM模型接下来就要写推理代码了。ACL的Python接口是对C接口的封装整体思路是初始化设备加载模型申请输入输出内存将数据拷贝到设备侧执行推理再把结果拷贝回Host端。我整理了一份可以直接跑的简化推理代码核心逻辑都写清楚注释了import numpy as np import cv2 import acl def init_resource(device_id0): ret acl.init() ret acl.rt.set_device(device_id) context, ret acl.rt.create_context(device_id) return context def load_model(model_path): model_id, ret acl.mdl.load_from_file(model_path) desc acl.mdl.create_desc() ret acl.mdl.get_desc(desc, model_id) input_size acl.mdl.get_input_size_by_index(desc, 0) output_size acl.mdl.get_output_size_by_index(desc, 0) return model_id, desc, input_size, output_size def inference(model_id, desc, input_data): input_data np.ascontiguousarray(input_data) input_ptr acl.util.np_to_ptr(input_data) output_np np.zeros((1, 25200, 85), dtypenp.float32) output_ptr acl.util.np_to_ptr(output_np) ret acl.mdl.execute(model_id, [input_ptr], [input_data.size], [output_ptr], [output_np.size]) acl.rt.synchronize() result np.array(output_np).reshape(1, 25200, 85) return result def main(): context init_resource() model_id, desc, in_size, out_size load_model(yolov5s_bs1.om) img cv2.imread(test.jpg) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (640, 640)) img img.astype(np.float32) img img / 255.0 input_data np.transpose(img, (2, 0, 1)).copy() input_data np.expand_dims(input_data, axis0) result inference(model_id, desc, input_data) print(inference output shape:, result.shape) acl.mdl.unload(model_id) acl.rt.destroy_context(context) acl.finalize() if __name__ __main__: main()这里要特别说明一下输出shape为什么是1,25200,85。YOLOv5在640x640输入下会输出三个不同尺度的预测结果加起来是25200个候选框85表示4个坐标、1个置信度、80个类别概率。如果你的YOLO版本不同或者类别数不同这个shape要对应调整。ACL的Python接口里acl.util.np_to_ptr和acl.rt.memcpy这两组函数是数据搬运的关键。整个推理过程最大的原则就是尽量减少数据在Host和Device之间来回拷贝的次数。因为每次拷贝都有固定开销数据量一大这个开销会肉眼可见地拖慢推理速度。4.4 性能调优batch、多路流与模型瘦身离线单张图片跑通之后接下来就要考虑性能。Atlas 300V 24G这张卡真正发挥价值的地方是多路视频流并发推理而不是单张图片反复跑。第一个调优手段是batch推理。把多张图片拼成一个batch一次性喂给模型通过提高硬件利用率来提升吞吐。上面转换OM时用的batch为1如果需要支持batch为4甚至8转换命令里要把input_shape改掉atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_bs4 \ --input_shapeimages:4,3,640,640 \ --soc_versionAscend310这里有个关键经验模型转换时确定了batch运行时就必须严格按这个batch来准备数据不能像GPU上那样自由编排。所以实际项目中要评估一下业务高峰期到底需要多大的并发量然后选择一个固定的batch值。atlas 300V的显存有24G但实际使用中并不是说显存越大batch就能无限开大模型本身的算力上限在那里batch到一定程度之后延迟会增加吞吐提升趋缓需要自己实测找拐点。第二个调优手段是图像预处理优化。前面说的AIPP可以把resize和归一化下沉到硬件这在多路视频流场景下效果非常明显。如果没有AIPP每一路视频的图像缩放都要占用CPU和内存带宽CPU很快会成为瓶颈。第三个手段是模型本身的瘦身。YOLOv5s跑在NPU上已经很流畅但如果你的检测对象只有十几个类别可以考虑剪枝或蒸馏出一个更小的模型比如把检测头简化。每次转换出来的OM模型越小推理延迟越低。但注意不要为了追求性能把精度牺牲得太多最终验收指标是精度和速度的平衡。关于多路视频流的工程实现我建议用多线程配合设备侧队列每个线程各自往模型里喂数据然后用信号量或者消息队列来做结果汇总。帧率不需要开满很多安防场景15到25帧就够用了关键是要稳不能出现每隔一段时间就卡一下的情况。5. 常见问题与排查实录5.1 ATC报错ATE或框架版本问题我在部署过程中遇到的第一类比较典型的问题是ATC转换时报ATE错误或者算子不支持错误。ATE是ATC里做图编译的组件当ONNX里出现不支持的算子时报错信息通常会指出具体是哪个算子。面对这类报错我常用的排查手段是先用ATC工具自带的算子查询能力检查模型里哪些算子超出了支持列表。如果只是个别算子不支持最简单的办法是修改原始模型在导出ONNX前把这些算子替换成等价的基本算子组合。例如某些用户自定义的激活函数可以尝试替换成标准的ReLU或SiLU组合。另外如果你是用高版本PyTorch导出的ONNX里面可能带有一些新算子ATC不一定认识。此时建议在导出ONNX时把opset版本固定到11同时尽量不要打开某些高级优化选项让导出的模型结构尽可能朴素。这一步能规避掉大量ATC转换问题。5.2 推理结果全是错框或空白模型在GPU上推理正常转到Atlas 300V后推理结果全乱这个问题我也踩过。绝大多数情况下问题出在图像预处理不一致。YOLO在PyTorch里的预处理通常是resize到640x640像素值除以255做归一化然后按RGB通道顺序排列。到了昇腾侧如果你在AIPP里配置了归一化又在代码里也做了一遍归一化等于数据被归一化两次反之如果两边都没做对输入数据的分布就和训练时不一致结果自然全乱。我给出的排查步骤是先关掉所有预处理优化把输入数据完全按训练时的格式处理好确认推理结果正常再逐步把resize和归一化下沉到AIPP。这样每一步都有明确的验证点出了问题能快速定位。另外注意YOLOv5的前处理还有一个细节就是图像resize时的填充方式很多情况下原图比例不是1:1需要等比缩放后用灰色填充这个细节在GPU上不容易出错但在NPU上如果预处理写得不严谨会出现大量误检。5.3 性能上不去瓶颈排查顺序如果你发现Atlas 300V的推理速度远低于预期不要急着怀疑硬件。按照我习惯的排查顺序来先看Host端的CPU占用率再看数据拷贝次数最后看模型本身的算力瓶颈。Host端CPU占用率过高往往说明预处理太费CPU了比如在用OpenCV逐帧做大量resize和格式转换此时应该把AIPP用起来或者把预处理放到专门的线程池里。数据拷贝次数过多则是代码结构的问题比如每帧推理时都重复申请和释放Device内存这会带来不必要的开销正确做法是启动时一次性申请好运行期间复用。模型本身的问题比较简单直接跑官方benchmark或者用一个已知性能指标相同的模型对比测试。我用Atlas 300V实测YOLOv5s单卡batch为1时延迟大约在十几毫秒量级batch提到4到8时整体的吞吐有明显提升。如果你得到的数值差几个数量级一定是在以上三个环节里有明显浪费。5.4 显存与内存释放问题Atlas 300V虽然有24G显存但长期运行的服务如果显存管理不当一样会撑爆。最典型的错误场景是每次推理都通过acl.rt.malloc申请Device内存推理结束后又通过acl.rt.free释放使用频率很高时频繁地分配释放会带来性能损耗和内存碎片。我的建议是在服务启动阶段做一次统一的内存池初始化把需要用到的输入输出Buffer都提前申请好运行过程中不断复用。只有当batch策略发生变化时才重新分配。项目停止或模型更新时再统一释放。另一个容易忽视的问题是ACL的Python接口在做显式内存管理时对象生命周期如果没有处理好会出现Wechat式的未释放资源。Python的垃圾回收在这里帮不上忙因为ACL底层是C对象不会自动消失。所以代码里每创建一个ACL对象都要思考它的释放时机这是昇腾Python开发里很重要的一个习惯。5.5 一张速查表我的排查整理为了方便以后遇到同样的问题我把常见的错误现象和解决方向整理成一个速查表希望对你也有用。现象可能原因检查顺序npu-smi看不到卡驱动未装好/固件版本不符先看lspci再重装驱动atc命令找不到环境变量未配置检查CANN安装路径和PATHATC转换时算子不支持ONNX算子超范围/opset过高降低opset替换算子推理结果错乱图像预处理不一致检查resize、归一化是否和训练一致推理速度慢CPU预处理瓶颈/内存频繁拷贝用AIPP做内存复用内存持续增长ACL对象未释放排查每个ACL对象的生命周期程序启动即崩溃C版本Python太新/so库冲突换支持范围内的Python版本这张表不能替代完整的日志分析但它能帮你快速圈定问题的大致范围。昇腾的问题排查有一点和GPU生态很不一样它的报错信息有时不够直观甚至可能只是掩码错误码。所以排查时要多一点耐心学会用npu-smi看实时状态用tail看/var/log下的昇腾日志用ATC和ACL的调试选项逐步缩小范围。最后再分享一点我的个人体会。Atlas 300V 24G这款卡在推理性价比上还是很能打的尤其是多路视频流场景24G大显存带来的余量非常可观。但它的学习曲线确实比GPU路线陡一些主要成本就在模型转换和环境适配这一步。我的建议是从官方示例出发先用最简单的模型把整条链路跑通再一步步替换成自己的YOLO模型最后再做多路并发和性能优化。这套路虽然看着慢实际是少走弯路最快的方式。
返回列表