ARTICLE DETAIL

资讯详情

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

Atlas 300V 24G上部署YOLO:从硬件认知到工程化落地全流程

Atlas 300V 24G上部署YOLO:从硬件认知到工程化落地全流程 我拿到这台服务器时里面插着的正是Atlas 300V 24G。当时项目要求在这张卡上把YOLO跑起来我在搜索引擎里也看到不少人问“atlas 300v 24g 是运算加速卡吗”。这里统一回答它确实是运算加速卡而且是一张专职干AI推理的加速卡但它的用法和你熟悉的GPU完全不是一回事。这篇博文就记录我从零开始在这张卡上完成YOLO部署的完整过程包括硬件认知、环境搭建、模型转换、推理代码、多路视频流工程化以及我踩过的一堆坑。不管你是刚拿到Atlas卡、准备从GPU迁移过来还是只想搞清楚这东西到底怎么用、能不能部署YOLO这篇都能给你一个可以落地参考的路线。1. Atlas 300V 24G的真实身份算力卡但和GPU是两个物种1.1 它和GPU的差别比你想的大得多很多人第一次接触Atlas 300V习惯性把它当成“另一个品牌的显卡”来用这是后面各种折腾的根源。Atlas 300V 24G是昇腾AI计算系列里的一张推理卡核心是NPU不是GPU。GPU的全称是图形处理器最初为了解决图像渲染里的并行计算问题而生后来被引入通用计算NPU则是专门为神经网络计算设计的芯片把卷积、矩阵乘、激活函数这些算子固化成了高效的硬件单元。说人话就是GPU要是全能选手什么活都能接NPU更像专项运动员专注吃透深度学习推理这一类动作。这不是说谁强谁弱而是使用逻辑完全不同。GPU生态里你装了CUDA之后PyTorch几乎能无缝跑模型转成TensorRT只是性能优化不是必须。Atlas不一样它不能直接加载PyTorch的.pt权重也不认TensorRT的.engine文件。它有一套自己的软件栈模型需要先导出为ONNX再转成OM离线模型推理时通过ACL接口调用。这个“先转换再使用”的步骤是每个从GPU转过来的人必须接受的第一步。1.2 拿到卡之后我会先看哪些硬件特征Atlas 300V 24G最直观的参数就是24GB的板载内存这也是它在推理场景里能站住脚的原因之一。24GB意味着它可以装下参数量不小的模型像YOLOv8m、YOLOv8x这种级别的目标检测模型完全够用甚至可以在同一张卡上同时部署多个模型只要它们的显存总和不超过上限。我实际用下来比较关心的几个点PCIe形态Atlas 300V是一条PCIe卡可以插在x86或者鲲鹏服务器上不需要单独的机箱供电模组装机门槛很低。低功耗设计整卡功耗比我用过的多数GPU要低不少2U机箱里塞两张卡散热压力也不大。多AI Core架构卡内有多个AI Core可以并行这意味着不是只能一路一路跑推理可以设计多Stream并发这是后面调优的关键。下面这张表是我自己关注的几个核心参数具体数值以官方规格书为准但选型思路可以参考关注点我的评估方式说明显存24GB是否够塞下当前模型单模型或同卡多模型的总占用要低于总量留出推理临时buffer算力定位偏推理还是偏训练Atlas 300V系列是推理卡训练不建议上它功耗单卡功耗与机箱供电余量两张卡时尤其要算好整机功耗和散热软件栈驱动、固件、CANN是否匹配版本不匹配是部署期最耗时间的问题1.3 从GPU迁移过来思维上要切换什么用GPU推理久了最舒服的一点是生态统一训练代码和推理代码同源最多做点量化、动态shape处理。Atlas给不了这个舒适区它的推理链路是“模型转换ACL单独写推理代码”不是一个torch.load就完事。实际项目中我把这套链路拆成了四段模型准备用训练框架导出ONNX这个通用性好格式转换用ATC工具把ONNX转成OM这一步最关键也最容易出问题推理开发用ACL的Python/C接口写推理代码包括前处理、模型调用、后处理性能调优通过固定shape、多Stream、AIPP等手段压榨硬件能力。想明白这个流程后面每个环节的坑都有迹可循。下面进入实际操作阶段。2. 部署前的环境栈驱动、固件、CANN少一个都会卡在原地2.1 我的服务器环境清单先说环境。我这次用的部署机器是一台x86的2U服务器操作系统是Ubuntu 20.04卡是Atlas 300V 24G软件栈用的CANN 6.3版本社区版。注意这里说的是CANN这是整个Atlas软件栈里最重要的一个工具包里面有开发推理代码的ACL库、做模型转换的ATC工具、还附带一些算子库和样例。写这段时我特意把版本写清楚是因为在Atlas的部署生态里版本匹配比什么都重要。驱动版本、固件版本、CANN版本三者之间常常有对应的兼容关系如果你手头的版本组合跟我不同安装时可以少走弯路但遇到问题时第一反应应该是去查官方兼容列表而不是怀疑自己操作有误。CANN分社区版和商用版社区版免费包含的算子覆盖面足够跑YOLO这类主流模型商用版主要是面向正式交付场景的长期支持版本。个人学习和项目验证阶段社区版完全够用。2.2 驱动、固件、CANN的安装顺序Atlas的软件栈安装顺序有讲究我按以下次序装先装NPU驱动操作系统识别这张PCIe卡驱动不上后面什么都白搭再装固件固件负责AI Core内部微码驱动和固件经常是同一个安装包分两个步骤装的最后装CANN toolkit可以是社区版也可是商用版它依赖前面两项正常工作。安装CANN时官方给的.run安装包通常会先做环境依赖检查缺什么会提示你补。这里最容易被人跳过的一个地方是环境变量。CANN装完之后不会自动生效需要source它的set_env.sh脚本source /usr/local/Ascend/ascend-toolkit/set_env.sh我第一次就是忘了这步结果命令行里敲atc找不到命令白白排查了半天。后来我直接把这段写进了.bashrc每次开新终端都自动加载后面就再没遇到这种基础问题。提示如果你同时装了多个CANN版本环境变量指向的必须是当前想用的那个版本否则版本串了会出各种莫名其妙的错误。2.3 装完先别急着转模型做两个探针验证装完环境第一步用npu-smi info命令看卡是否被正常识别。这个命令会输出卡的型号、健康状态、显存占用、温度、AI Core使用率等信息类似NVIDIA的nvidia-smi。如果这里看不到你的卡说明驱动或固件没装好停下来先解决而不是继续推进度。第二步跑一个CANN自带的推理样例比如ResNet50图像分类样例确认整套链路是通的。这一步不是浪费时间它能验证你的ACL环境、ascend目录权限、设备创建这些底层逻辑是否正常。等这条链路通了再上YOLO才有意义。我见过很多人上来直接转YOLO的OM模型结果转出来一跑就崩排查到最后发现是底层环境压根没验证过这种基础没打牢后面会反复出问题。3. ONNX转OMYOLO权重上Atlas的第一道鬼门关3.1 导出ONNX时NMS要不要带进去YOLO系列的官方或第三方权重一般都会给出导出ONNX的脚本比如YOLOv8的yolo export modelyolov8s.pt formatonnx。这步本身不难难在导出时怎么选择模型结构。最核心的一个选择是ONNX里要不要带NMS后处理。我的建议是不要带。YOLO的导出选项里有时会有一个NMS开关打开后ONNX模型里会包含NMS算子输出直接就是过滤好的检测框。听起来方便但到了Atlas上NMS这类动态逻辑需要根据检测结果决定输出个数输出数量不确定恰恰是NPU不太擅长、转换时也最容易报算子不支持的。把NMS留在模型外面推理时在CPU上做后处理一来规避了算子支持问题二来输出shape固定模型转换更顺畅。最终我导出的ONNX输入是images:1,3,640,640输出是YOLOv8s的原始输出张量shape大约是1,84,8400。8400是YOLOv8在640x640输入下三个尺度特征图的总预测框数84是4个坐标信息加上80个类别置信度如果用的COCO 80类数据集。写后处理算法时会用到这个结构。3.2 ATC命令怎么写参数代表什么意思拿到ONNX之后用ATC工具把它转成OM。ATC全称Ascend Tensor Compiler就是专门干模型转换的。一个典型命令长这样atc --modelyolov8s.onnx \ --framework5 \ --outputyolov8s \ --soc_versionAscend310P3 \ --input_shapeimages:1,3,640,640 \ --logerror逐个说参数--framework55代表ONNX这个别记错填错了解析直接失败--output输出的OM文件名最好跟项目语义一致--soc_version指定芯片型号可以用npu-smi info查看当前卡对应的SoC版本填错了ATC会报芯片型号不存在--input_shape固定输入shape这个非常重要后面会细说--logerror只输出错误日志转换过程信息太多改成error模式更容易定位问题。这里我要强烈建议第一次转换尽量用固定shape。动态shape虽然更灵活比如可以任意尺寸输入但ATC转换时动态shape的算子优化空间小运行时还有额外的shape推导开销。用在生产环境中规中矩的做法是固定一个训练尺寸所有输入都做letterbox后送到模型里。3.3 转换完了先检查什么转换成功会生成一个.om文件同时终端提示Success。但我建议第一步不要急着写推理代码先用ATC自带的模型信息查看能力或者直接写一个极小脚本加载OM确认模型描述正常。检查点包括模型路径、输入张量名、输入shape、输出张量名、输出shape。此时最常遇到的问题集中在两块算子不支持报错会明确指出是哪个算子比如某个自定义算子、NMS算子解决办法是优先考虑改模型结构规避掉不支持的算子而不是硬啃算子适配shape不匹配经常是导出的ONNX里包含了动态维度而ATC默认要求静态shape为了兼容你提供了--input_shape但名字填错了比如ONNX输入名不叫images而叫input。注意ONNX输入节点名可以通过Netron打开模型查看别用PyTorch代码里的变量名去猜。4. ACL推理代码实战前处理对齐、后处理自己写4.1 最小推理骨架先让一张图跑通OM模型有了之后用ACL接口写推理。ACL分C和Python接口我用Python接口做验证代码结构更清晰。以下是推理最核心骨架import acl import numpy as np from PIL import Image def init(): acl.init() acl.rt.set_device(0) context, ret acl.rt.create_context(0) self.stream, ret acl.rt.create_stream() model_id, ret acl.mdl.load_from_file(yolov8s.om) desc acl.mdl.create_desc() acl.mdl.get_desc(desc, model_id) return desc, model_id def prepare_input(desc, model_id, image): # 获取模型输入shape申请device侧内存 input_size acl.mdl.get_input_size_by_index(desc, 0) input_data, input_ptr acl.rt.malloc(input_size, 2) # 将前处理后的numpy数组写入device内存 acl.rt.memcpy(input_ptr, input_size, image.tobytes(), input_size, 1) return input_data, input_ptr def infer(stream, model_id, input_data, input_ptr): # 创建输入输出dataset input_dataset acl.mdl.create_dataset() input_buffer acl.mdl.create_data_buffer(input_ptr, input_size) acl.mdl.add_dataset_buffer(input_dataset, input_buffer) # 输出dataset同理 output_dataset acl.mdl.create_dataset() output_size acl.mdl.get_output_size_by_index(desc, 0) output_data, output_ptr acl.rt.malloc(output_size, 2) output_buffer acl.mdl.create_data_buffer(output_ptr, output_size) acl.mdl.add_dataset_buffer(output_dataset, output_buffer) # 执行推理 acl.mdl.execute(stream, model_id, input_dataset, output_dataset) acl.rt.synchronize_stream(stream) # 把结果拷回host侧 result np.zeros(output_size, dtypenp.uint8) acl.rt.memcpy(result.tobytes(), output_size, output_ptr, output_size, 1) return result这段代码里我不放完整可运行版本重点是让你理解ACL的调用逻辑初始化设备和上下文、创建Stream、加载模型、给输入输出分别申请device内存、执行推理、把结果拷回内存。和CUDA的流程很像但API完全不同而且每一步都要处理返回的错误码生产代码里一定要检查ret值不要往下走。4.2 letterbox和归一化前处理必须跟训练时对齐YOLO部署前处理有三步读取图像、letterbox调整尺寸、归一化。很多人忽略这步的重要性总觉得“反正都是图随便resize一下就行”。事实上前处理如果和训练时不一致模型的精度会肉眼可见地下降甚至出现漏检错检。我用的是标准letterbox按比例缩放图像短边或长边对齐到640多余部分用灰色填充填充值通常是114。不要用纯黑色0填充YOLO训练时用的就是这个灰色你用黑色就相当于给图片注入了一种训练时没见过的分布模型输出自然不对。归一化就是把像素值除以255转成0到1之间的浮点数。YOLO系列在训练时大多用的是这种最简单的归一化不需要计算均值方差。同时注意颜色通道顺序训练时用的是RGB就把BGR转成RGB别弄反了。这一步我会写成一个独立函数放在单独的preprocess.py里方便不同模型复用。4.3 后处理解码、过滤、NMS的完整思路YOLOv8的原始输出是84x8400这种形状以我上面的示例为准也就是每个预测框有4个坐标值和80个类别分数。后处理要做这几件事解析坐标把模型相对网格的预测值解码成真实坐标。YOLOv8的box分支输出的已经是中心点坐标加宽高的形式不需要像YOLOv5那样做复杂的anchor解码过滤低置信度设定类别的confidence阈值比如0.25把低于阈值的框滤掉NMS对每个类别分别做非极大值抑制用IoU阈值0.45去掉重复框坐标映射因为letterbox改变过图像尺寸最后要把框的坐标映射回原图尺寸。我把一段简化的解码伪代码放出来参考def postprocess(output, conf_thres0.25, iou_thres0.45): # output shape: [1, 84, 8400] preds output[0].transpose(1, 0) # [8400, 84] boxes preds[:, :4] scores preds[:, 4:] # 取每个框最大的类别得分 class_ids np.argmax(scores, axis1) confs np.max(scores, axis1) # 过滤低置信度框 keep confs conf_thres boxes, confs, class_ids boxes[keep], confs[keep], class_ids[keep] # 按类做NMS final_boxes nms_boxes(boxes, confs, class_ids, iou_thres) return final_boxes注意NMS计算是在CPU上做的所以后处理性能也要纳入整体耗时。一张图还好视频流一多后处理代码也要写得高效一点能用numpy向量化就用numpy别写多层Python循环。4.4 内存管理上的一个易踩坑点ACL推理中device侧内存申请了好几次分别是输入数据、输出数据可能还有中间buffer。用完一定要手动释放不然长时间跑推理会内存泄漏最后系统崩掉。我踩过的具体问题是每次推理都重复申请device内存推理完成只释放了模型和上下文忘了释放数据buffer。单次推理看不出问题连续跑几小时之后内存占用越来越高最终显存不足重启才恢复。后来我把内存申请和释放的代码统一封装成上下文管理器靠Python的with语法保证异常退出时也能release这个坑才算稳定填上。5. 工程化提速多路视频流、固定shape与AIPP的取舍5.1 多路输入到底该拼batch还是拆开跑单张卡如果只跑一路YOLO往往跑不满。AI Core有多核并行能力经常我们为了省事在Host侧写一个for循环一路一路把图片送进去。这样其实只用一个Core或少量Core资源浪费很大。工程化时更合理的做法是拼batch推理。比如一次推理放入4张图片形状变成4,3,640,640模型内部会并行处理这4张图吞吐量明显提升。代价是拼batch时如果各张图原始尺寸不一致要先各自letterbox成640x640再拼进来这一步会稍微增加前处理耗时但对整体吞吐提升来说值得。另一个方案用多Stream并发相当于同时向卡内提交多个推理任务芯片自己调度。两种方案可以结合一个batch一张图像用于延迟敏感场景多Stream用于吞吐敏感场景。我实际项目里用的是4路Stream并发每路内部按batch2处理整体效果比较均衡。5.2 固定shape是性能的最好朋友第3节我建议转换时用固定shape原因不只是为了保险性能上差异也很大。固定shape之后ATC可以在编译阶段就把输入输出内存布局、算子调度都安排好推理少了很多运行时判断。如果你用动态shape则每次推理都可能重新计算内存布局和算子选择单次延迟通常会有明显增加。代价是模型输入尺寸被锁死。如果业务需要不同分辨率的图比如有的摄像头是1080p有的是4K那所有输入统一先letterbox缩放到640x640再送模型输出检测框再映射回各自原始分辨率。这套流程稍微多费一点CPU时间但换来的是卡上延迟的稳定性。5.3 我用AIPP把前处理塞进了CANN省出了大量CPU时间ACL提供AIPPAI Preprocessing特性可以在模型转换时或者推理初始化时把resize、cvtColor、归一化这些前处理算子编排到模型中让图传输到NPU后直接在硬件里完成预处理。我第二次部署时就把letterbox和归一化放进了AIPP配置Host端只需要读取原始图像、做简单的内存拷贝CPU占用立刻降了一半。AIPP的配置方式有两种一种是离线配置在ATC转换时绑定到OM模型里一种是在运行时通过ACL的AIPP接口动态设置。我推荐离线方式简单稳定但要求输入shape固定这就跟第5.2的建议呼应上了。提示AIPP适合那些前处理逻辑标准的模型。如果你的前处理里有很多自定义逻辑比如特殊裁剪、数据增强式的随机变换就不要硬塞进AIPP规规矩矩在Host做否则排查问题时会非常痛苦。5.4 三个让我印象深刻的排查记录最后分享三个我实际遇过的故障它们都不是什么高深问题但很典型希望能帮你缩短定位时间。第一个是推理输出全为0。模型转换没问题、代码也没报错但输出结果所有类别分数都是0。查了一晚上最后发现是前处理时忘了做除以255的归一化把0到255的uint8数据直接当成float32送进了模型。模型训练时输入是0到1你喂进去的是0到255输出自然是垃圾。第二个是检测框位置偏移。模型能出框但框的位置明显不对比如物体在左上角框却画在右下角。原因是letterbox之后没有把坐标映射回原图或者映射公式里忘了考虑缩放比例和填充偏移。这类问题写完后处理一定要用单张已知图片做对照验证确定坐标映射公式无误后再上批量数据。第三个是长时间运行内存暴涨。这个我在4.4里已经提过核心就是每次推理循环里创建的dataset、data buffer、device内存没有被释放。ACL的每一层资源最好都在生命周期结束时显式释放养成习惯别依赖进程退出时的垃圾回收。如果你正打算在Atlas 300V 24G上部署YOLO我的建议很直接先按这篇的流程把环境探针验证干净再用固定shape把ONNX转成OM推理代码最小化跑通一张图最后才考虑AIPP、多Stream这些优化手段。不要一开始就玩动态shape和复杂后处理那会让你分不清问题是出在模型转换还是出在推理代码上。部署前可以先用CPU跑通整个前处理、后处理逻辑再把模型推理换成ACL这样出问题时你能快速定位到底卡在哪一段。
返回列表