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

资讯详情

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

Atlas 300V 24G上部署YOLO:从环境配置到推理优化全攻略

Atlas 300V 24G上部署YOLO:从环境配置到推理优化全攻略 有人拿着Atlas 300V 24G问我这卡到底是不是运算加速卡。是但更准确的说法是它是一张AI推理加速卡不是用来跑训练脚本的那类卡。它的本职工作是把已经训练好的模型高效地跑起来尤其适合视频流分析、目标检测、OCR这类推理任务。而围绕这张卡我被问到最多的事情就一件怎么把YOLO部署上去。这篇文章就围绕这个问题把从硬件确认、环境准备、模型转换到推理代码和性能调优的完整链路讲清楚全是实际操作层面的东西。1. 先搞清楚Atlas的定位300V 24G不是训练卡1.1 昇腾产品线里经常被搞混的几种形态Atlas这个名字下面其实是一整条产品线常见的有Atlas 200 DK开发套件、Atlas 300系列PCIe推理加速卡、Atlas 800/900系列推理/训练服务器还有昇腾910系列训练卡。很多人以为Atlas只有一种买回来发现软件栈装不对或者网上搜的教程对不上号其实就是卡没对上。Atlas 300系列里又细分出300I、300V、300I Pro、300V Pro等型号。后缀里的I和V代表不同的市场定位I一般偏视频分析V更偏通用视觉计算。Atlas 300V 24G这个型号出货量在安防、智慧园区这类场景里非常大原因很简单它是面向边缘推理的PCIe卡插在标准服务器上就能用不需要整机绑定。1.2 300V 24G的核心规格意味着什么300V 24G这个名字里的24G指的是24GB HBM显存这决定了它能不能在一个模型实例里放下比较大的模型或者较高的batch。它的处理器是昇腾310P系列官方标称INT8算力在两百多TOPS这个量级功耗却比训练卡低一大截。这组数字放在实际场景里的含义是跑YOLOv5s、YOLOv8s这类轻量模型单卡可以同时挂几十路视频流跑YOLOv5m、YOLOv8m这种中等规模的模型24G显存也能轻松放得下想做批量检测比如单次推理batch8或者16显存也不会成为瓶颈。所以如果你手头有这张卡主要能干的活就是目标检测、图像分类、语义分割、OCR识别这类推理服务。它不适合做训练训练请用昇腾910系列这是定位决定的不是能力不行。1.3 和GPU推理卡的本质差异软件栈完全不同用过NVIDIA显卡的人都知道GPU上跑PyTorch装上CUDA、cuDNN基本就完事了。Atlas不是这个玩法它走的是**CANNCompute Architecture for Neural Networks**这套软件栈模型要先转换成.om格式再通过ACLAscend Computing Language接口或MindSpore来调用。换句话说你现在的PyTorch权重不能直接被它加载中间必须过一道“翻译”的工序。这个差异是很多人卡住的根本原因。不是卡坏了也不是板子没插好而是部署链路本身就比GPU多一步。理解了这一点后面所有操作都能说得通。2. 环境准备驱动、固件、CANN的版本匹配是第一个大坑2.1 从官网下载三类软件包一个都不能少在Atlas上跑推理环境上需要三样东西驱动Driver、固件Firmware、CANN工具包。驱动和固件属于硬件底层的部分CANN是上层推理框架。具体下载时通常要拿这几个包Ascend-cann-toolkit_x.x.x_linux-x86_64.run或者aarch64版本Ascend-hdk_版本_linux-aarch64.run驱动和固件包具体命名按官网实际为准有些场景还有Ascend-cann-nnae之类的补丁包用于PyTorch适配但如果只做推理非必要。这里最容易踩的坑是版本之间不是任意搭配的。CANN版本和固件/驱动版本有对应关系表最好是官网上标注“配套”的一组一起拉下来。我有一次图省事装了新版CANN却保留旧固件结果ATC转换阶段一直报算子相关错误排查了很久才发现是版本不配套。2.2 安装顺序与验证流程安装顺序建议是先装驱动和固件再装CANN。命令行下没有太多交互但有两个细节容易被忽略安装驱动和固件时如果当前系统的内核版本和驱动包要求的不一致会提示失败这时候先升级内核或者换对应版本不要硬装。安装完成后需要source一下环境变量脚本source /usr/local/Ascend/ascend-toolkit/set_env.sh如果不想每次开终端都手动source可以写进~/.bashrc。这一点和CUDA的PATH配置是同一个道理。装完之后第一件事先看卡有没有被系统识别npu-smi info输出里能看到卡的温度、使用率、显存占用、固件版本、驱动版本这些信息。只要npu-smi info能正常列出设备说明硬件和驱动层面已经OK。2.3 用npu-smi确认当前软件版本版本检查是很多人会跳过的步骤但恰恰是最值得花十秒钟看的。建议执行一下npu-smi info -t board -i 0或者看版本文件cat /usr/local/Ascend/ascend-toolkit/latest/version.cfg记录下CANN版本和固件版本。后面一旦出现“版本过高”“算子不兼容”之类的报错回来对版本是最快的排查方式。3. YOLOv5到OM模型转换的全过程3.1 从PyTorch导出ONNX最容易忽略的细节YOLO的部署第一步是把PyTorch权重转成ONNX。这一步看起来简单但有几个点决定了后续ATC转换顺不顺利第一opset版本建议用11。太高或太低都会导致某些算子导出异常或者ATC不认。我遇到过用opset13导出时报一个自定义算子不支持的情况降到11就好了。在YOLOv5的仓库里导出命令是这样的python export.py --weights yolov5s.pt --include onnx --opset 11第二是否需要固定尺寸。YOLOv5的默认输入是640x640。如果你后续要跑不同分辨率的输入可以导出--dynamic但我会建议首次先把尺寸固定下来跑通整个链路之后再考虑动态shape。原因很实际固定shape的OM模型编译器可以做得更激进推理性能更好动态shape的灵活度是用额外开销换来的。第三输入输出的命名。导出后的ONNX里输入节点通常叫images输出节点会有好几个YOLOv5输出的是1x25200x85这种形状以v5s 640输入为例。后续ATC参数里要准确填对这个名字。3.2 ATC转换命令与参数解读拿到ONNX文件之后用CANN自带的ATC工具做转换。ATC全称Ascend Tensor Compiler作用就是把ONNX、MindSpore或者TensorFlow的模型编译成昇腾能直接执行的OM文件。我的转换命令长这样atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_om \ --soc_versionAscend310P3 \ --input_shapeimages:1,3,640,640 \ --insert_op_confaipp.cfg \ --loginfo逐个解释一下--framework5表示输入是ONNX--soc_version是芯片型号300V 24G对应的是Ascend310P3这个值不能写错写错会直接报soc_version not support--input_shape要跟ONNX里的输入名和维度完全对上名字不对也会报错--insert_op_conf用于插入AIPP预处理配置这个下面说。转换成功后会生成一个.om文件。转换过程会打印很多信息建议把--log设成info至少看一遍有没有warning。有些warning可以忽略但跟“op not support”相关的warning要警惕。3.3 AIPP预处理把图像处理也丢给NPUAIPP是Atlas的Image Pre-Processing模块。它的作用是在模型推理前在NPU侧完成一部分图像预处理这样CPU就能少干活吞吐量能上来不少。我用的aipp.cfg是这样写的aipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_h: 640 src_image_size_w: 640 crop: false csc_switch: true rbuv_swap_switch: true mean_chn_0: 0 mean_chn_1: 0 mean_chn_2: 0 min_chn_0: 0 min_chn_1: 0 min_chn_2: 0 }这里面两个最容易搞混的开关是csc_switch和rbuv_swap_switch。csc_switch表示做色域转换比如YUV到RGBrbuv_swap_switch表示交换R和B通道。因为YOLO训练时用OpenCV读图OpenCV默认是BGR顺序而很多在线推理的输入帧是RGB所以这里要根据你喂给模型的数据格式来设置否则出来的检测结果会偏色或者完全错乱。还有一个实际问题如果开了AIPP的static模式那么输入图片会被强制缩放到src_image_size_h/w指定的尺寸。也就是说CPU端只需要负责解码和resize到640x640归一化、通道交换这些都可以省掉。这一点对计算资源的节省非常明显。4. 用pyACL实现推理代码框架与内存管理4.1 初始化流程少一步都不行模型转好后就到了写推理代码的环节。CANN对Python提供的是pyACL接口核心流程是固定的初始化 → 设置设备 → 加载模型 → 准备输入输出 → 执行推理 → 释放资源。下面这段代码框架我每次都会复用只改模型路径和数据import acl import numpy as np # 初始化 acl.init() ret acl.rt.set_device(0) context, ret acl.rt.create_context(0) # 加载模型 model_id, ret acl.mdl.load_model_from_file(./yolov5s_om.om) model_desc acl.mdl.create_desc() ret acl.mdl.get_desc(model_desc, model_id) # 获取输入输出尺寸 input_size acl.mdl.get_input_size_by_index(model_desc, 0) output_size acl.mdl.get_output_size_by_index(model_desc, 0) # 申请设备内存 input_data, ret acl.rt.malloc(input_size, 2) output_data, ret acl.rt.malloc(output_size, 2) # 准备一个numpy数组作为输入先放在CPU内存 img_cpu np.random.randn(1, 3, 640, 640).astype(np.float32) # 拷贝到设备内存 ret acl.rt.memcpy(input_data, input_size, img_cpu.tobytes(), input_size, acl.ACL_MEMCPY_HOST_TO_DEVICE) # 执行推理 ret acl.mdl.execute(model_id, [input_data], [input_size], [output_data], [output_size]) # 把结果拷回CPU output_np, ret acl.rt.memcpy_to_host(output_data, output_size) # 释放资源 acl.rt.free(input_data) acl.rt.free(output_data) acl.mdl.unload_model(model_id) acl.rt.destroy_context(context) acl.rt.reset_device(0) acl.finalize()这段代码有个很关键的细节acl.rt.malloc的第二个参数官方叫mem_type正常写2表示申请大页内存这对性能是有利的。如果你申请设备内存时类型设置不对后面memcpy会报错。4.2 数据预处理放CPU还是NPU取决于你的输入源上一步AIPP如果已经配置好了那么CPU端只做两件事把图像读进来resize到640x640。这里有个容易绕晕的点AIPP的static模式会做居中裁剪或缩放如果你的业务图片长宽比和640x640差很多建议在CPU端先做letterbox处理也就是保持宽高比填充黑边否则目标会被拉伸变形检测精度明显下降。我自己测试下来的体感是如果把letterbox也放到CPU端做single-stream延迟里预处理占个3到5毫秒是正常的如果输入源是视频流解码那部分同样会吃掉不少CPU。这也是为什么很多生产环境会倾向用硬件解码比如Atlas的DVPP模块把解码、缩放都丢给硬件做。4.3 NMS放在哪里做是后处理性能的关键YOLO的OM输出是原始的检测框张量NMS非极大值抑制在昇腾上没有一个现成算子能直接用所以通常放在CPU后处理里。这意味着整条链路的瓶颈往往不在推理本身而在后处理。我见过有人直接把ONNX输出里的1x25200x85整个遍历一遍做阈值过滤Python跑下来单张要十几毫秒直接把推理提速省下来的时间全吃回去。规整的做法是先用置信度阈值过滤比如score 0.25的直接过滤掉这时候保留的框通常已经很少再做NMS用OpenCV的cv2.dnn.NMSBoxes就行没必要自己写如果对延迟极度敏感考虑把后处理换成C模块通过pybind11暴露给Python调用。这一步当业务方的检测类别从80类减到几个类别时后处理耗时会有明显下降。5. 性能调优从单张到高并发5.1 一组基于实测的参考数据我拿Atlas 300V 24G实际跑过YOLOv5s输入640x640AIPP静态预处理C部署单batch的情况下模型推理本身大概在5到8毫秒如果走Python pyACL的链路加上预处理和后处理单帧端到端延迟在10毫秒上下是可以做到的。这个数据受驱动版本、CANN版本、CPU性能、板卡散热都有影响不是一个绝对基准但可以给你一个判断标准如果单张640x640的YOLOv5s推理延迟超过15毫秒通常不是卡不够强而是链路里有东西没调好最常见的就是预处理或后处理在CPU上拖了后腿。5.2 固定batch和动态batch的取舍如果业务是批量离线处理图片或视频抽帧建议把OM模型固定成batch8甚至batch16来转换然后用一个batch的数据凑满再做推理。这样做的好处是NPU的算力利用率更高尤其是昇腾这种推理芯片小batch的话显存带宽和算力都喂不饱。但固定batch带来一个问题业务请求不是规整的8的倍数。这时候要自己在业务层做排队和凑批的逻辑比如用一个积攒队列攒够8帧再触发一次推理。如果业务延迟要求很高比如单帧必须10毫秒内出结果那就用batch1的模型配合多线程并发来吃满卡。我实际测试过300V 24G跑YOLOv5sbatch1时延迟低但卡利用率上不去batch8时吞吐能明显提升但延迟会相应变长。没有绝对最优只有适合当前业务的选择。5.3 多路视频流的并发设计很多场景是几十路摄像头同时进来每一路都是独立的检测任务。这种情况下我推荐的做法有几个多线程或多进程同时调用ACL接口。pyACL在Python多线程下要注意GIL问题如果发现并发上不去要么改用多进程要么干脆C做线程池Python只做上层调度。每个线程持有自己的context或stream避免共享带来的锁争用。ACL的设计里模型是可以在多个线程里并发执行的但设备上下文最好各管各的。batch可以按路数来分。比如四路视频流每路出4帧凑成16帧一个batch这样既有了batch的吞吐优势又保证了各路视频流的响应公平性。我见过一个生产项目用300V 24G跑16路1080p视频流每路抽帧做YOLOv5s检测端到端延迟控制在15毫秒以内卡的使用率大概到70%左右。对推理卡来说这个负载已经算比较健康了。6. 部署过程中最常遇到的几个报错和解决思路6.1 报错信息与处理对照这里把我在踩坑过程里遇到的高频问题整理成一个表方便直接对着查。报错或现象可能原因处理方式soc_version not supportsoc型号填错确认卡的实际型号300V 24G填Ascend310P3ATC转换时提示算子不支持ONNX导出的opset过高或过低重新导出--opset 11检查是否用了自定义算子acl.rt.set_device失败驱动没装好或设备被占用执行npu-smi info确认设备存在检查当前用户是否有权限推理结果全为0或乱码输入数据格式与AIPP配置不一致确认喂给ACL的数据是RGB还是BGRrbuv_swap_switch是否正确内存拷贝报错设备内存申请类型不对或容量不足确认acl.rt.malloc的第二个参数为2检查输入输出尺寸是否匹配推理延迟突然变高设备温度过高或降频npu-smi info看温度检查服务器散热风道这里重点说一下权限问题。Atlas设备默认/dev/davinci*的设备节点可能需要root权限才能访问有时候程序跑着跑着报设备打开失败其实不是代码问题是用户没有权限。临时解决可以chmod 666 /dev/davinci*正式环境建议按官方要求配好udev规则。6.2 我自己最常用的排查命令部署遇到问题我的排查顺序基本固定# 1. 先确认硬件和驱动 npu-smi info # 2. 确认CANN版本 cat /usr/local/Ascend/ascend-toolkit/latest/version.cfg # 3. 确认环境变量 source /usr/local/Ascend/ascend-toolkit/set_env.sh echo $ASCEND_HOME # 4. 看推理进程是否把卡占满 npu-smi info -t usages -i 0一张卡同时被多个进程使用时务必确认每个进程的显存申请和释放都是完整的。pyACL写得不严谨时进程退出后设备显存可能没有完全释放时间长了会累积出“显存不足”的假故障。我在开发阶段习惯在测试程序退出后执行npu-smi info看一眼显存占用是不是归零了。6.3 说一个经常被忽略的细节日志级别CANN的日志默认级别很啰嗦生产环境建议调成ERROR级别否则日志文件会以惊人的速度膨胀。设置方式通常是修改环境变量export ASCEND_GLOBAL_LOG_LEVEL3这个变量在调试阶段设为1DEBUG看细节上线前改成3。我见过有人带着默认DEBUG日志上了生产一个星期磁盘满了应用告警最后排查才发现是日志写爆的。最后分享一点个人体会Atlas这套东西和GPU最大的区别在于GPU生态里框架帮你把“从训练到部署”的路铺好了你只需要照着文档走Atlas则需要你自己把模型转换、预处理下沉、内存管理、后处理编排这几个环节串起来。这听起来麻烦但一旦把这套流程吃透它的性能和功耗优势是实打实的。我自己的习惯是把这条链路沉淀成几个固定脚本从ONNX导出、ATC转换到pyACL推理测试每次换模型只需要改路径、输入尺寸和后处理阈值。后面如果要做更复杂的应用比如ReID或者多模型串联也是在这套流程上叠加万变不离其宗。
返回列表