ARTICLE DETAIL

资讯详情

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

Atlas 300V 24G上YOLOv5/YOLOv8迁移部署全流程:模型转换、推理调优与避坑指南

Atlas 300V 24G上YOLOv5/YOLOv8迁移部署全流程:模型转换、推理调优与避坑指南 最近项目上正好在折腾 Atlas 300V 24G 这块卡手头有一批目标检测任务要从 GPU 迁到昇腾平台模型选的是 YOLOv5 和 YOLOv8。整个流程走下来从最开始连“这卡是不是运算加速卡”都没搞清楚到后面能熟练完成模型转换、推理部署和性能调优踩了不少坑也积累了一些还算能直接复用的经验。这篇东西不是官方文档的复读而是我实际部署过程中的记录和总结。如果你也手头有 Atlas 300V 24G或者正准备在这类昇腾推理卡上跑 YOLO 系列模型那这篇应该能给你省下不少折腾时间。我会从硬件定位、环境准备、模型转换、推理代码落地到问题排查一条线讲清楚。1. 先搞清楚 Atlas 300V 24G 到底是什么卡1.1 它是运算加速卡但它专攻推理第一次接触 Atlas 300V 24G 的人最容易犯的错误是拿它当训练卡用。看到“24G 显存”“运算加速卡”这几个字下意识就会觉得这玩意儿是不是能像 A100 那样做训练。实际上不是这么回事。Atlas 300V 24G 是基于昇腾 310P 芯片的推理加速卡定位非常明确做 AI 推理尤其是视频分析、图像分类、目标检测这类高并发、高吞吐的场景。它不支持完整的训练反向传播流程你没法像用 GPU 那样随便拿它跑 torch 里的model.train()。原因在于昇腾推理卡的计算单元设计以及它依赖的 CANN 软件栈主要优化的是前向推理算子。我自己的理解是如果把训练比作“备课”要把知识反复讲、反复改那推理就是“考试”要求又快又准地给出答案。Atlas 300V 24G 就是为“考试”设计的它把大量精力花在如何让前向计算更高效上。从实际使用角度这意味着两件事已有的 PyTorch 模型不能直接丢到卡上跑需要先转换成昇腾平台支持的离线模型格式OM。跑推理的时候你不需要关心梯度、优化器、反向传播这些东西只要管好输入输出就行。1.2 24GB 存储到底能带来什么Atlas 300V 24G 最吸引人的参数就是这 24GB 的存储。很多人问一个推理卡搞这么大显存干嘛我觉得至少带来三个非常实际的好处能塞下更大的模型像 YOLOv5s、YOLOv8s 这种小模型原始权重大概就 20~40MB转成 OM 后占用的内存也很小。但如果你跑的是 YOLOv8x、YOLOv7 这类大模型或者想直接跑一些视觉 Transformer 结构24G 的余量就很宽裕了。能同时处理更多路视频流视频分析场景里每路视频流都需要占用一定模型内存和推理缓存。24G 的存储意味着你可以开更多的推理实例不用频繁担心“显存不够”的问题。我们实测同一模型下24G 版比 8G 版能多跑接近两倍的并发路数。单卡可以放多个模型我习惯把 YOLOv5 的检测模型和人脸关键点模型同时加载到一张卡上让一张卡同时承担两个推理任务。24G 的容量在做这种多模型混合部署时非常从容。1.3 和 GPU 推理卡相比优势在哪儿很多人喜欢拿 Atlas 300V 24G 和英伟达的 T4 比。我个人的感觉是两者定位有重叠但昇腾卡有一个很现实的优势成本可控且能覆盖国产化场景。在合规要求比较严格的项目里昇腾平台几乎是必选。从性能角度说Atlas 300V 24G 的 INT8 推理能力是它的强项。YOLO 这类检测模型转成 INT8 后精度损失通常不大但吞吐能明显提升。我们跑 YOLOv8sINT8 量化后单卡吞吐能到 200 多 FPS在 batch1 时这个数字和同价位 GPU 卡相比是不落下风的。具体算力数值建议以官方型号规格为准因为 Atlas 300V 系列还有不同的子型号。但有一点我可以确认选卡的时候千万别只看显存推理卡的并发能力和软件生态支持才是项目能不能落地的关键。2. 部署 YOLO 前的环境准备2.1 硬件检查与驱动版本核对拿到 Atlas 300V 24G 之后第一步不是装 CANN而是先看驱动是否正常。昇腾卡自带一个类似 NVIDIAnvidia-smi的工具叫npu-smi用法很像npu-smi info执行之后会列出卡的型号、芯片、驱动版本、固件版本、显存使用这些信息。我当时做的第一件事就是确认驱动版本和后续要装的 CANN 版本是否匹配。这里有个我踩过的坑驱动和 CANN 版本不匹配后面模型转换的时候各种诡异报错非常浪费时间。版本匹配关系以昇腾官方“驱动固件与 CANN 版本配套表”为准。我的建议是如果你是自己玩直接装最新稳定版驱动 对应版本 CANN。如果是公司生产环境先问运维要现有的软件栈版本再按版本表去装不要擅自升级。2.2 CANN 工具链安装与用户环境变量CANN 是昇腾平台的计算架构类似 CUDA 的角色。装它的时候要注意两个部分Toolkit 和 NNAL或者叫 nnrt运行时库。我当时的安装流程大致是这样的从昇腾社区下载对应版本的 CANN Toolkit 安装包。以root用户执行安装./Ascend-cann-toolkit_xxx_linux-aarch64.run --install注意Atlas 300V 有 ARM 和 x86 两种服务器形态安装包架构别选错安装完成后有一个全局的环境变量脚本需要 source 到当前 shellsource /usr/local/Ascend/ascend-toolkit/set_env.sh这个set_env.sh很重要它会把编译工具链、ATC 工具、Python 开发库路径都加进环境变量。忘记 source 的话你运行atc命令会直接提示command not found。我建议把 source 命令写进~/.bashrc避免每次开新终端都要手动执行。但有一点要注意如果你服务器上同时有多个版本的 CANNset_env.sh默认指向的是默认版本切换版本时要手动修改 PATH别搞混了。2.3 理解昇腾推理的整体链路在跑命令之前我建议你先在脑子里建立一条链路PyTorch / ONNX 模型 - ATC 工具转换 - OM 离线模型 - ACL 推理接口 - 推理结果为什么不能直接在卡上跑 PyTorch因为 PyTorch 是面向 GPU/CPU 的框架昇腾硬件不认识它的计算图。你需要把 PyTorch 模型先导出成 ONNX然后再用 ATCAscend Tensor Compiler工具把 ONNX 编译成昇腾专用的 OM 格式。OM 模型是优化后的计算图里面包含了算子调度、内存复用这些硬件相关的信息。类比一下ONNX 相当于一份跨平台的“菜谱”什么炉灶都能看OM 则是专门针对你的“锅灶”优化过的“烹饪流程”每一步都精确到工具和时间。理解这条链路之后后面所有操作都是围绕它展开的。3. YOLO 模型迁移从 PyTorch 权重到 OM 离线模型3.1 导出 ONNX 模型时要注意什么我自己用的比较多的 YOLOv5 和 YOLOv8这两个官方仓库都自带了导出脚本。比如 YOLOv5 里python export.py --weights yolov5s.pt --include onnx --imgsz 640 --batch-size 1YOLOv8 类似yolo export modelyolov8s.pt formatonnx imgsz640 batch1但这里有一个关键问题导出的 ONNX 是否需要固定 batch size我强烈建议在昇腾上转 OM 之前先把 ONNX 的 batch size 固定下来。因为 OM 模型在转换的时候要确定输入张量 shape动态 batch 虽然能提供灵活性但要么受限于算子支持要么会牺牲一部分性能。我们实际项目中推理 batch 要么是 1要么是 4所以在导 ONNX 的时候就直接固定好后面转 OM 也更省事。还有一个细节是模型的opset_version。我遇到过一次某个新版本模型导出的 ONNX 算子版本太高ATC 不识别报了一堆算子不支持的错误。解决方法是导出时指定低一点的 opset比如python export.py --weights yolov5s.pt --include onnx --opset 11YOLOv8 则可以在导出参数里加ops11。如果对算子支持不确定可以先从低版本 opset 试起。3.2 配置 AIPP 做预处理归一化YOLO 系列模型在 PyTorch 里的预处理通常是缩放、归一化除以255、转 CHW。如果你把整个预处理放在应用层做也可以但昇腾卡更推荐用 AIPPAI Preprocessing在硬件上完成这部分操作这样可以减少 CPU 开销提升整体吞吐。AIPP 配置是一个.cfg文件我常用的是这个模板aipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_w: 640 src_image_size_h: 640 csc_switch: true rbuv_swap_switch: false crop: false mean_chn_0: 0 mean_chn_1: 0 mean_chn_2: 0 min_chn_0: 0 min_chn_1: 0 min_chn_2: 0 var_reci_chn_0: 0.00392156862745098 var_reci_chn_1: 0.00392156862745098 var_reci_chn_2: 0.00392156862745098 }var_reci_chn就是归一化用的倒数1/255 ≈ 0.00392156862745098。如果你的模型训练时用的是 ImageNet 的 mean/std就要把对应的值填进去。关于 AIPP 我要多说一句改了 AIPP 配置之后应用层就不要再做同样的归一化操作了否则等于做了两次归一化推理结果肯定不对。我们项目里就有人犯过这个错误查了很久才发现是预处理重复了。啥意思呢就是说如果你用了 AIPP 做归一化和 resize那你在往模型输入里塞数据时给的是原始图像数据就行不用再除以 255。这一点非常重要。3.3 ATC 命令转换 OM 模型环境准备好、ONNX 导好、AIPP 配好之后就可以执行转换了。我使用的命令大致长这样/usr/local/Ascend/ascend-toolkit/latest/bin/atc \ --framework5 \ --modelyolov8s.onnx \ --outputyolov8s_640_b1 \ --input_shapeimages:1,3,640,640 \ --input_formatNCHW \ --soc_versionAscend310P3 \ --insert_op_confaipp.cfg \ --output_typeFP16 \ --logerror解释一下几个关键参数--framework5表示输入是 ONNX 模型。CANN 里不同框架有不同编号5 对应 ONNX。--model输入的 ONNX 文件路径。--output输出 OM 文件的名称前缀。--input_shape如果输入有多个节点需要用:分隔YOLO 一般只有一个输入所以就是images:1,3,640,640。注意这里的images是 ONNX 里输入节点的名称你导出的模型可能叫images也可能叫input可以用工具查看不要照搬。--soc_version这个要根据实际芯片型号填。Atlas 300V 24G 常见的是Ascend310P3但不同批次可能有差异。先用npu-smi info查一下芯片型号再填最稳妥。--output_typeFP16指定输出数据类型。检测模型一般用 FP16 就够了精度影响很小但速度会快一点。--logerror只在出错时输出日志避免刷屏。转换成功后会生成yolov8s_640_b1.om文件。我一般会顺带检查一下文件大小如果只有几 KB那大概率是转换失败了正常几十 MB 级别。3.4 用 ATC 静态量化做 INT8可选如果你想进一步提升推理性能可以考虑 INT8 量化。ATC 支持校准量化需要准备一批校准数据比如几百张典型的图片。量化的命令格式和转 FP16 差不多但需要加--enable_compression之类的参数不同 CANN 版本差异比较大。我个人的建议是先在 FP16 下跑通整个流程再考虑 INT8。因为 INT8 调试成本高一上来就做量化遇到精度问题会很痛苦。先 FP16 跑通了再量化就只关注精度损失这一个变量。4. 推理代码落地基于 ACL 的推理框架4.1 初始化昇腾设备与加载模型OM 模型转换好之后下一步就是写推理代码。昇腾提供的最底层开发接口是 ACLAscend Computing Language类似 CUDA Runtime API。你可以用 C 或者 Python 写。我这边主要用 Python 快速验证接口调用方式相对简单。核心流程是这样的import acl def init_device(device_id0): ret acl.init() assert ret 0, acl.init failed ret acl.rt.set_device(device_id) assert ret 0, set_device failed context, ret acl.rt.create_context(device_id) assert ret 0, create_context failed return context初始化完成后用acl.mdl.load_from_file加载 OM 模型model_id, ret acl.mdl.load_from_file(yolov8s_640_b1.om) assert ret 0, load model failed # 获取模型的输入输出信息 input_desc acl.mdl.create_desc() acl.mdl.get_input_desc(model_id, input_desc, 0) output_desc acl.mdl.create_desc() acl.mdl.get_output_desc(model_id, output_desc, 0)这里有个非常容易踩的坑加载 OM 之前一定要确认设备已经初始化成功。否则模型加载会报错而且错误码往往很模糊让人摸不着头脑。4.2 数据准备与内存分配模型推理前需要把输入图像数据拷贝到昇腾设备的内存上。ACL 提供acl.rt.malloc来分配设备内存input_tensor_shape (1, 3, 640, 640) input_tensor_size 1 * 3 * 640 * 640 * 4 # FP32 的 size input_data, ret acl.rt.malloc(input_tensor_size, 2)这里的2是内存对齐单位一般用 2即 2 的幂对齐就行。图像读取后你要把图像数据 resize 到 640x640转成 RGB并按 CHW 排列。这部分逻辑和普通 CV 一样但要注意如果之前配了 AIPP你只需要把 resize 后的原始图像数据喂进来不用再除以 255。如果你没配 AIPP就需要自己在应用层做归一化。把数据拷贝到设备内存acl.rt.memcpy(input_data, input_tensor_size, host_data_ptr, input_tensor_size, acl.rt.MEMCPY_HOST_TO_DEVICE)如果用的是 numpy 数组可以用acl.util.numpy_to_ptr获取数据的指针。4.3 执行推理与后处理推理执行的 API 非常直接ret acl.mdl.execute(model_id, [input_data], [output_data])output_data是输出设备内存指针。推理完成后把数据拷回主机端acl.rt.memcpy(host_output_ptr, output_tensor_size, output_data, output_tensor_size, acl.rt.MEMCPY_DEVICE_TO_HOST)拿到输出后YOLO 的后处理套路大家都熟悉解码框、过滤低置信度、NMS。这部分逻辑和在 GPU 上跑没有本质区别唯一要注意的是输出张量的格式和顺序建议先用一个固定图片在 GPU 上跑一遍对比两侧输出的 shape 和数值范围确保解码方式正确。我们当时比较 YOLOv8s 在 PyTorch 和 OM 上的输出shape 是一样的1, 84, 8400这就说明 ATC 转换没有改变输出结构后处理代码可以直接复用。实际输出可能因模型输入尺寸不同而不同但思路一致。4.4 性能调优的四个方向模型能跑通之后大部分人关心的是“怎么让它跑得更快”。我在 Atlas 300V 24G 上调优主要关注四个方向batch 推理不要一张一张送尽量攒够 batch4 或 batch8 再推理。Atlas 300V 对多 batch 的优化非常明显吞吐能提升数倍。代价是单次推理延迟会稍微变高航线和视频流场景一般都能接受。流水线并发用多线程或进程池让数据预处理、推理、后处理三个环节并行起来。昇腾推理 API 本身是异步的可以用acl.mdl.execute_async 回调函数把推理和拷贝并行处理。这个优化对整个系统吞吐提升很大。内存复用每次推理都重新 malloc 设备内存是很大的浪费。我习惯在初始化时一次性分配好输入输出 buffer后面推理只更新数据内容不重新分配。多 Stream 并发ACL 支持多 Stream 并发执行可以同时运行多个推理任务。但多 Stream 会带来资源竞争需要结合实际模型大小测试不是 Stream 越多越好。我用 batch4 双线程流水线把 YOLOv5s 的吞吐从 batch1 时的约 120 FPS 提升到了 250 FPS效果非常明显。所以如果你想榨干这张卡的性能优化优先级应该是batch 流水线 内存复用 多 Stream。5. 常见问题与排查速查表5.1 模型转换报算子不支持这个是我遇到最多的报错。典型错误是TE.ImplError或者Unsupported op。排查思路看看是不是 ONNX 的 opset 版本太高降低 opset 重新导出。看模型里有没有昇腾不支持的算子比如一些新出的注意力机制。如果确实有需要改写模型结构或者用 MindSpore 的昇腾迁移工具辅助。注意--soc_version是否正确填错了也会出现莫名的算子错误。5.2 推理输出全零输出全零基本可以断定是输入数据有问题。优先级排查以下两点图像数据没有正确拷贝到设备内存或拷贝的数据长度不对。AIPP 配置和应用层预处理重复导致输入数据范围不对。我遇到过最离奇的一次是因为输入数据用numpy.ctypeslib转指针时数组不是连续内存导致数据错乱。解决办法是提前调用np.ascontiguousarray。5.3 性能达不到预期如果单卡吞吐上不去先看是不是 batch1 时跑测试。batch1 的性能本来就不是这张卡的强项一定要开 batch。再确认一下是否开启了算子缓存算子编译后会有 cache第二次跑会快很多。首次推理比后续推理慢是正常的因为要现场编译算子。如果每次都重新编译就检查一下算子缓存目录是否可写。5.4 卡不是自己想要的芯片版本npu-smi info看到的芯片型号和 ATC 参数不一致会导致转换后无法加载。这个问题的根源是型号填错。建议以npu-smi info显示的Chip Version为准比如我这边显示Ascend310P3那--soc_version就必须填Ascend310P3。如果你看到的是Ascend310P1或Ascend310P2也要跟着改。填错的结果要么是转换失败要么是运行时报错说模型与设备不匹配非常靠后才发现就麻烦了。下面是一个沉淀下来的排查速查表现象常见原因处理方式atc: command not found未 source set_env.sh重新 source 环境变量脚本转换报算子不支持ONNX opset 太高或算子不支持降低 opset重构模型结构加载 OM 报错soc_version 不匹配按 npu-smi info 修改推理输出全零输入复制失败或预处理重复检查内存拷贝和 AIPP 配置首次推理慢后续快算子编译缓存属于正常现象不需要处理吞吐上不去batch1 或流水线未开启开启 batch 和并发流水线最后再分享一点我的个人体会Atlas 300V 24G 这块卡我觉得最大的价值在于用一个可控的成本把 YOLO 这类常见模型的推理需求承接得非常好。尤其是 24G 的大存储让它在一张卡上同时跑多个模型、多路视频流时非常从容。你不需要一开始就把所有性能优化手段都用上先把模型转换跑通再逐步调 batch 和流水线性价比最高。如果你手头正卡在模型转换或者推理代码上不妨回去看看是不是某一环节忽略了上述细节。我遇到的大多数问题最终都指向版本匹配或预处理重复。先把这两点排查干净再谈优化。这也是我在多次踩坑之后最想提醒后来者的一句话在昇腾平台上细节决定成败。
返回列表