首页 / 资讯中心 / 文章详情

Atlas 300V 24G跑YOLO全流程:从环境搭建到推理优化

Atlas 300V 24G跑YOLO全流程:从环境搭建到推理优化 ★ FEATURED ARTICLE
干了这么多年AI部署说实话被各种推理卡折磨过不少回Atlas 300V 24G 这张卡算是让我印象比较深的一张。一开始单纯以为它就是一张普通的 PCIe 加速卡结果从驱动到算子适配到模型转换每一步都有它自己的脾气。这篇文章就围绕 Atlas 300V特别是 24G 版本跑 YOLO 目标检测的完整流程来写把我踩过的坑、验证过的命令、以及最终能稳定跑起来的部署方案都整理出来希望能让后来的人少走几个礼拜弯路。先说明一下适用对象手里正好有 Atlas 300V / Atlas 300V Pro 这张卡想在 x86 服务器上做 YOLOv5/YOLOv8 推理或者正在 Atlas 和 GPU 之间纠结选型的同学这篇文章可以直接当操作手册看。1. 项目概述24G 推理卡到底能做什么不能做什么1.1 硬件规格拆解先搞清楚手里是什么卡Atlas 300V 系列是华为昇腾生态里的推理加速卡走 PCIe 接口属于典型的“插到普通服务器上就能用”的产品形态。24G 版本用的是 LPDDR4X 显存对不是 GDDR6也不是 HBM整卡功耗不算高散热设计也比较友好半高卡可以直接塞进 2U 机箱。这张卡的定位非常明确推理不是训练。昇腾 310P 芯片本身的算力结构就是为推理设计的INT8 算力远高于 FP16所以你要是拿它去跑训练那基本属于“杀鸡用牛刀但牛刀还不够快”的状态。实际项目中它最常见的场景就是视频流分析、工业质检、安防巡检这类需要长时间在线跑目标检测模型的任务。有一个容易混淆的点需要注意Atlas 300V 和 Atlas 300I Pro 虽然长得像但 300V 系列更强调低功耗和边缘部署两者在 CANN 算子支持、AI Core 数量上略有差异。买卡之前务必确认你的型号因为后面所有环境配置、算子适配都要跟着具体型号走。1.2 为什么 YOLO 部署会选 Atlas 300V说句实在话如果只是图省事YOLO 部署直接上 NVIDIA 的卡是很多人闭眼选的方案毕竟生态成熟、资料多。但 Atlas 300V 在一些特定场景下确实有其不可替代的优势第一是成本。24G 显存做推理单卡价格相比同显存的 GPU 推理卡有明显优势而且功耗低机房散热压力小长期跑电费能省不少。第二是供应稳定。国产化项目里Atlas 系列几乎是绕不开的选项很多项目的招标要求就是“支持昇腾生态”。第三是算力利用率。YOLO 这类模型在推理阶段对 INT8 量化非常友好Atlas 300V 的 INT8 算力可以充分发挥实测在 batch size 足够大的情况下吞吐量并不比同价位的 GPU 差。但它的劣势也很明显算子生态不如 CUDA 完善、调试工具相对简陋、踩坑之后能找到的参考资料少。这意味着用这张卡部署 YOLO不能照搬 GPU 上的经验必须重新走一遍“模型转换—算子适配—推理代码编写”的流程也就是这篇博文要解决的核心问题。2. 环境搭建驱动、固件与 CANN 工具链的版本对齐2.1 安装前必须搞清楚的三个概念Atlas 300V 的环境比普通 GPU 复杂因为软件栈分了三层Driver驱动、Firmware固件、CANN异构计算架构。很多人第一次装环境就把这三者混为一谈结果驱动装好了但固件版本不对或者 CANN 版本和驱动不匹配导致模型加载失败。可以这么理解Driver 是操作系统认识这张卡的“桥梁”Firmware 是卡上芯片自己跑的基础程序CANN 则是开发者直接调用的工具库和运行时。三者必须形成一个版本组合不是随便装最新的就行。我的建议是直接用华为官方发布的“Ascend HDK”配套包里面会标明与 CANN 的兼容版本组合。以我用的组合为例Driver 版本 23.0.3CANN 版本 6.3.RC2配套的固件也是 23.0.3。这个组合在 x86_64 的 Ubuntu 20.04 上很稳定如果你用的是其他组合安装后最好先跑一下官方自带的环境检查脚本。2.2 一步步装环境的实操记录安装过程其实不复杂但有几个细节容易卡住。整体步骤是这样# 检查操作系统架构Atlas 300V 支持 x86 和 ARM但命令和包名不同 uname -m # 安装依赖Ubuntu 系统需要这些基础库 apt-get update apt-get install -y gcc g make cmake zlib1g zlib1g-dev openssl libsqlite3-dev然后下载 Ascend HDK 和 CANN 的安装包这里要特别注意安装驱动和固件必须在 root 权限下执行而且安装驱动时会自动加载内核模块如果服务器里有其他 NVIDIA 卡或 GPU 驱动理论上不冲突但建议还是先确认内核版本和 gcc 版本兼容。# 安装驱动和固件run 包方式 chmod x Ascend-hdk-23.0.3_linux-aarch64.run ./Ascend-hdk-23.0.3_linux-aarch64.run --full # 安装 CANN 工具包 chmod x Ascend-cann-toolkit_6.3.RC2_linux-aarch64.run ./Ascend-cann-toolkit_6.3.RC2_linux-aarch64.run --install安装完 CANN 后一定要执行环境变量配置否则找不到 atc、npu-smi 这些命令source /usr/local/Ascend/ascend-toolkit/set_env.sh这个 source 命令最好写进~/.bashrc里不然每次开新终端都要手动执行一次。另外CANN 安装目录下还有ascend-toolkit/latest软链接可以方便地确认当前激活的版本。2.3 环境验证npu-smi 信息怎么看装完之后别急着跑模型先用官方工具确认卡的状态是否正常。npu-smi info是最常用的命令输出里重点看几项Chip那一行会显示芯片型号比如 Ascend 310P确认和你的卡一致。Memory显示显存总量和已使用量24G 版本的卡正常应该显示约 24GB实际可用略小。Hugepages和Temperature也要留意温度过高会触发降频影响推理延迟。如果执行npu-smi info提示找不到设备优先检查驱动是否加载成功ls /dev/davinci_manager ls /dev/davinci*正常情况下/dev/davinci0应该存在同时/dev/davinci_manager也要存在。如果只有 manager 没有 davinci0说明驱动加载了但设备没被识别大概率是固件版本和驱动不匹配或者卡没插好。另外你还可以跑一下官方自带的样例程序来验证 CANN 环境完整性一般在工具包自带的 samples 目录下就有能跑通就意味着环境基本没问题了。3. 模型转换从 YOLOv5 到 OM 的全流程3.1 为什么不能直接跑 PyTorch这是 Atlas 新人最容易困惑的点明明在 GPU 上 PyTorch 直接加载权重就能推理为什么到了 Atlas 这里非要转成 OM 格式原因在于 Atlas 300V 的芯片架构不是通用的 GPU它内部是 AI Core 专用加速单元CANN 的算子库无法像 CUDA 那样直接兼容 PyTorch 所有算子。运行时需要把模型编译成芯片能高效执行的指令序列也就是 OMOffline Model文件。OM 文件除了包含网络结构还记录了算子调度顺序、内存分配方案和量化信息相当于一张“定制化的执行图纸”。所以整个流程是PyTorch 权重 → ONNX 中间格式 → 通过 ATC 工具转成 OM → 用 ACLAscendCL接口加载推理。这个链路里的每一步都有坑尤其是 ONNX 导出环节很多算子不支持的问题都是从这里埋下的。3.2 PT 转 ONNX导出时的关键细节YOLOv5 官方代码自带了导出脚本python export.py --weights yolov5s.pt --include onnx就能直接导出。但直接导出有一个隐藏问题默认会带上 NMS非极大值抑制后处理逻辑而 NMS 这类动态算子往往是昇腾不支持的重灾区。我推荐的做法是改一下导出脚本的配置把端到端的后处理剥离出去只保留模型本身的推理部分python export.py --weights yolov5s.pt --include onnx \ --opset 11 --batch-size 1 \ --simplify--simplify会调用 onnx-simplifier 做计算图优化这个步骤强烈建议加上能消除很多冗余算子。导出后务必用onnx.checker.check_model做一次完整性校验或者直接用 Netron 打开看一下计算图确认 NMS 没有被包含在模型里。如果你想用 batch size 大于 1 的配置建议固定为一个值不要动态 batch因为后续 ATC 转换时--input_shape必须写死维度动态 shape 会带来额外的算子适配风险。YOLOv8 的导出也类似yolo export modelyolov8s.pt formatonnx opset11 dynamicFalse simplifyTrue。v8 的检测头是解耦头Decoupled Head输出张量的结构跟 v5 差别比较大转换后需要对应调整解码逻辑这个我在后文推理部分会详细讲。3.3 ONNX 转 OMATC 工具完整命令ATCAscend Tensor Compiler是 CANN 自带的模型转换工具核心命令如下atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_320 \ --input_shapeimages:1,3,320,320 \ --soc_versionAscend310P3 \ --insert_op_confaipp.cfg \ --loginfo几个参数逐个解释--framework55 表示 ONNX 格式不能写错。--output输出 OM 文件的路径前缀会自动加上.om后缀。--input_shape必须和导出 ONNX 时的输入维度一致通常 YOLOv5 默认是[1, 3, 640, 640]但是出于性能考虑可以换成 320 或 416模型会重新推理对应尺寸的结果。--soc_version这里最关键要填你芯片对应的版本。Atlas 300V 24G 通常对应Ascend310P3但不同型号可能有所不同可以用npu-smi info查看芯片型号或者查官方兼容列表。填错了会直接报错而且报错信息还不直接。--insert_op_confAIPP 配置文件用来做图像预处理如缩放、归一化能省掉推理代码里的部分预处理工作量但也会带来灵活性下降的问题我会在推理部分讨论。--loginfo转换日志级别建议第一次转换用 info方便定位错误。转换成功的标志是看到屏幕上出现AICoreTime相关的统计信息并且生成了.om文件。如果转换过程中报算子不支持的错误不要慌重点看是哪个算子然后回到 ONNX 导出阶段做调整。3.4 转换结果检查很多人转换成功就立刻跑推理其实应该先检查一下 OM 文件的信息避免后面排查问题时无从下手。用 CANN 自带的工具可以查看 OM 的概要信息omg --modelyolov5s_320.om --output_type1或者更简单的方式直接看转换日志里的输出维度。YOLOv5 单尺度输出通常是一个(1, 25200, 85)的 Tensor如果输入是 320x320那 25200 是三个尺度输出格子数的总和40x40 20x20 10x10 再乘以 3 个 anchor。如果日志里输出的维度和你预期不一致先检查 ONNX 导出是否正常再检查 ATC 的--input_shape是否填对了。有一个很容易被忽略的点ATC 转换时显存分配方案也会被固化进 OM如果后续推理时申请的设备内存小于模型要求加载就会报错。建议转换时不要手动指定内存大小让工具自行分配。4. 推理落地写一个最小可用的 ACL 推理程序4.1 图像预处理顺序比想象中重要OM 模型输入约定是[N, C, H, W]并且默认是 RGB 顺序、浮点类型如果没启用 AIPP。我自己在实际编写时发现很多人在这里会翻车原因在于飞桨和 PyTorch 的预处理差异以及在代码运行时预处理导致 CPU 和 NPU 管线不匹配。推荐做法是用 OpenCV 读取图像BGR 格式先做 letterbox 等比缩放填充再转换颜色空间为 RGB然后归一化到 0~1最后将 HWC 转成 CHW 并扩展 batch 维度。具体流程如下import cv2 import numpy as np def letterbox(img, new_shape(320, 320)): shape img.shape[:2] # H, W r min(new_shape[0] / shape[0], new_shape[1] / shape[1]) new_unpad int(round(shape[1] * r)), int(round(shape[0] * r)) dw new_shape[1] - new_unpad[0] dh new_shape[0] - new_unpad[1] top, bottom dh // 2, dh - dh // 2 left, right dw // 2, dw - dw // 2 img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value(114, 114, 114)) return img, r, (left, top) img cv2.imread(test.jpg) img, ratio, (left, top) letterbox(img, (320, 320)) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0 img img.transpose(2, 0, 1)[None] # - 1,3,320,320这里的关键是 letterbox 填充时记录缩放比例和偏移量解码输出框时需要还原坐标。4.2 核心推理逻辑ACL 的 Python 封装直接用 ACL 的 C 接口写代码相对繁琐项目里我一般先用 Python 封装做快速验证确认模型和预处理没问题后再用 C 做上线版本。Python 调用 ACL 的核心流程是初始化、设置设备、加载模型、创建输入输出数据、执行推理、解析结果。import acl def init_acl(device_id0): acl.init() ret acl.rt.set_device(device_id) context, ret acl.rt.create_context(device_id) return context def load_model(om_path): model_id, ret acl.mdl.load_from_file(om_path) return model_id # 取模型的输入输出描述信息 desc acl.mdl.create_desc() 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)执行推理时需要把数据拷贝到设备侧。这里有个容易踩的坑ACL 默认输入要求是np.float32类型且内存连续预处理完的数据最好做一次np.ascontiguousarray()否则拷贝数据时会报数据长度不匹配的莫名其妙的错。# 输入输出数据申请设备内存 in_data acl.util.np_to_ptr(img_np) # 把 numpy 数据转为 device 指针 out_data np.zeros(output_size, dtypenp.float32) out_ptr acl.util.np_to_ptr(out_data) ret acl.mdl.execute(model_id, [in_data], [out_ptr]) # 将结果拷贝回 host result_np acl.util.ptr_to_np(out_ptr, (output_size,), np.float32)需要注意的是acl.mdl.execute是同步接口如果希望提升吞吐可以用acl.mdl.execute_async配合 stream 做多 batch 并发但代码复杂度会上升不少。第一次调试建议先用同步接口把整条链路跑通。4.3 后处理解码、NMS、画框模型输出的原始张量不能直接用需要解码。YOLOv5 的输出 shape 是(1, 25200, 85)其中 85 4 个坐标 1 个置信度 80 个类别概率。解码时先通过置信度阈值过滤低分框然后把中心点坐标还原成原图坐标乘以 letterbox 的缩放比例并减去偏移再做类的 NMS。def decode_yolov5(output, conf_thres0.25, iou_thres0.45, ratio1.0, (left, top) (0, 0)): pred output.reshape(-1, 85) scores pred[:, 4] # objectness mask scores conf_thres pred pred[mask] if pred.shape[0] 0: return [] boxes pred[:, :4] # 中心点格式 (cx, cy, w, h) - 角点格式 (x1, y1, x2, y2) box_xyxy np.concatenate([ boxes[:, :2] - boxes[:, 2:] / 2, boxes[:, :2] boxes[:, 2:] / 2 ], axis1) # 还原到原始图像坐标 box_xyxy (box_xyxy - np.array([left, top, left, top])) / ratio scores scores[mask] * pred[:, 5:].max(axis1) # 类别置信度 class_ids pred[:, 5:].argmax(axis1) # NMS 排序处理 keep nms(box_xyxy, scores, iou_thres) ...如果你用的是 YOLOv8解码就差很多v8 的输出是(1, 84, 8400)80 类别版本直接解耦了 objectness每个候选框的类别分数就是对应位置的类别概率而且没有 anchor。reshape 时需要注意索引的排序v8 的 8400 是按三个尺度展平的和 v5 的 25200 类似都是一个一维数组包含全部候选框。NMS 我建议直接用 OpenCV 的cv2.dnn.NMSBoxes比自己写要稳得多。Atlas 上别指望用模型里的 NMS 算子现在不支持的网络结构很多。4.4 与模型输出对齐后处理第一个要确认的就是输出维度。很多人在解码时报ValueError: cannot reshape array of size xxx基本都是模型输出维度和预期不一致。最直接的排查方式先把模型输出打出来看 shape 再决定怎么 reshape不要想当然按 YOLOv5s 的 25200 写死。还有一个细节ATC 转换时如果不指定 AIPP模型输出是 FP32 的解码时直接转 float 就行如果配置了 AIPP 做归一化模型的输入图层会自动插入预处理算子输出结构不变但需要确认图像输入的通道顺序是 RGB 还是 BGR这个写错会导致检测准确率大幅下降但模型不会报错属于最隐蔽的坑。5. 性能优化与常见问题实操记录5.1 推理吞吐上不去先看这几个指标Atlas 300V 跑 YOLO 的吞吐瓶颈通常不在芯片算力上而在于数据流。第一步看板卡利用率用npu-smi info看 AI Core 的占用率如果长期不到 50%说明瓶颈在数据搬运或预处理上。典型调优思路有几个一是开启多线程预处理和推理流水线。图像读取、缩放、填充、颜色转换这些操作在 CPU 上耗时很大如果每张图都是同步处理完再推理AI Core 必然有很多时间在空转。把预处理放到线程池里提前把 batch 的输入准备好推理线程只负责上传和下载数据吞吐能提升 30% 以上。二是增加 batch size。ATC 转换时输入 shape 如果写的是1,3,320,320那每次推理就固定一张图。改成4,3,320,320或者8,3,320,320然后把多张图组成一个 batch 再推理能充分利用板卡的多核并行能力。不过 batch 越大单张延迟也会增加线上服务时要根据 RT 要求权衡。三是使用多路 stream 并发。ACL 支持多 stream 并发执行相当于把不同的推理请求分配到不同队列。我在项目中测试过两个 stream 跑 YOLOv5s 320 输入吞吐能提升接近 1.8 倍收益非常明显。四是关闭模型中不必要的算子。YOLOv5 导出 ONNX 时如果保留了某些训练相关的输出比如 p6 大尺度输出层会白白增加计算量。只保留推理需要的分支即可。5.2 常见报错和解决办法速查下面几个错误是我在 Atlas 300V 部署 YOLO 过程中遇到最多的整理成一个速查表格报错信息原因解决办法E10020: The model is invalidOM 文件与当前 CANN/驱动版本不匹配确认 ATC 版本与运行环境一致重新转换E40011: Device memory allocation failed显存不足降低 batch size或者检查是否存在内存泄漏E19999: Unsupported operatorONNX 里的算子昇腾不支持回导出阶段调整模型或者用 AIPP 替代部分操作acl.mdl.load_from_file failedOM 文件路径错误或文件损坏确认文件存在重新转换Init resource failed设备初始化失败驱动或固件异常检查/dev/davinci0是否存在重装驱动np_to_ptr data type not support输入数据不是 float32转成np.float32且内存连续对于Unsupported operator我可以给一个方向性的排查方法先用 Netron 打开 ONNX 模型定位报错的算子节点然后搜索华为 CANN 的算子支持列表官方文档有完整列表看这个算子属于“完全支持”“部分支持”还是“不支持”。如果是“部分支持”往往是因为算子参数中包含了不支持的属性需要在导出源码里修改。5.3 我的踩坑记录说几个别人很难帮你定位的问题第一个坑AIPP 配置了归一化但代码里也做了一遍归一化结果检测框数量骤减准确率几乎为零。原因是 AIPP 会在输入芯片前自动把图像数据做归一化代码里如果再除一遍 255等于输入变成了原来的 1/255特征自然全乱套。排查了大半天才发现是双重重处理。建议策略要么完全用 AIPP 做预处理省 CPU要么完全不用 AIPP在代码里做灵活方便调试不要混合使用。第二个坑ONNX 导出的模型输入名不是images。ATC 命令里写的--input_shapeimages:1,3,320,320中的images必须和 ONNX 模型输入节点的名字一模一样否则 ATC 会报找不到输入张量。这个用 Netron 打开 ONNX 文件就能看到名字可能是images、input或者其他自定义名称转换前一定要确认。第三个坑NMS 在 CPU 上跑实在是太慢了。YOLOv5 的 25200 个候选框在 CPU 上做 NMS一次大概要几毫秒到十几毫秒如果每帧都做瓶颈就转移到 CPU 了。批量处理时建议用向量化的方式实现 NMS避免 Python 循环或者先用类别置信度阈值把候选框压到几百个再做 NMS速度会快很多。第四个坑运行环境的 Linux 内核版本和驱动不兼容。我曾在内核 5.15 的系统上装驱动失败换到 5.4 内核后一次通过。华为官方的兼容性列表里对内核版本有明确要求装系统之前先查一下省得装到一半卡住。6. 模型选型与输入分辨率你也需要想清楚的事6.1 YOLOv5s 和 YOLOv8s 在 Atlas 上的实际差异这两代模型我都跑过简单说下实测感受。YOLOv5s 导出 ONNX 时计算图相对简单算子类型少ATC 转换几乎没有卡过YOLOv8s 因为有解耦头和更复杂的结构转换时偶尔会碰到不支持的算子需要调整导出参数。推理速度上同分辨率下 v5s 比 v8s 快 10%~20%但 v8s 的精度通常略高一些。实际项目里我一般这样选如果对延迟敏感比如实时视频流分析用 YOLOv5s配合 320 或 416 分辨率单卡轻松跑满几十路如果更看重精度且视频路数不多可以用 YOLOv8s分辨率提高到 640换一张卡几张卡也能跑得动。6.2 输入分辨率对吞吐的影响这个影响比很多人想象的大。拿 YOLOv5s 举例同一张 Atlas 300V 上输入 320x320 和 640x640 的耗时大概差 3~4 倍但精度提升可能只有几个点。如果业务场景是检测小目标分辨率不能降如果场景是大的障碍物或人车检测320 或 416 分辨率往往就够了。有一个常见的量化方法先把模型测试集在不同分辨率下的 mAP 跑出来再乘以目标帧率算出每路需要的推理次数最后对比 Atlas 300V 在不同分辨率下的吞吐指标就能找到性价比最高的配置。6.3 多模型并发一张卡同时跑多个模型通过 ACL 的 context 和 stream 机制Atlas 300V 可以同时加载多个 OM 模型。这个功能在做业务时很有用比如一路视频流先跑一个轻量模型做区域筛选命中后再跑精细模型。一张卡上如果两个模型都不大共存的显存占用一般都能接受但要注意模型并发时 AI Core 是分时复用的理论上性能会互相影响需要测试确认。7. 最后的经验总结关于 Atlas 部署 YOLO 的三句实在话我个人实际操作下来最深的体会是用 Atlas 300V 部署 YOLO最大的成本不是卡而是软件链路的熟悉过程。从驱动到 CANN 到 ATC 到 ACL每一层都有自己的一套术语和工具没有 GPU 那种“pip install import torch”的顺畅感。但一旦把链路跑通后续的迭代和优化就顺理成章了尤其是性能调优的空间其实比很多人的预期要大。再分享一个小技巧在开发和调试阶段尽量把模型转换、推理、后处理三个环节解耦每个环节单独写成脚本出了问题可以直接定位。等全流程稳定后再考虑用 C 重写推理部分Python 做业务逻辑既能保证性能又能兼顾开发效率。这个内容后续还可以这样扩展同一套环境也可以用来跑其他检测模型比如 RT-DETR、PicoDet甚至可以做简单的图像分类任务。关键是先把“转换 推理”这套骨架搭好换模型的时候只是换个 ONNX 和 OM 文件的问题。希望这篇 Atlas 部署 YOLO 的实操笔记能帮你省下几天的查资料时间。
阅读完成 · 觉得有帮助?
咨询建站