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

资讯详情

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

Atlas 300V 24G推理加速卡上部署YOLO模型完整实战指南

Atlas 300V 24G推理加速卡上部署YOLO模型完整实战指南 最近问我 Atlas 300V 24G 的人特别多上来基本就是两个问题这卡到底是不是运算加速卡能不能拿来跑 YOLO我直接说结论它是而且就是干这个用的。Atlas 300V 24G 是华为昇腾系列里面向 AI 推理场景的 PCIe 加速卡核心是昇腾 310P 芯片官方标称 INT8 算力可以到 300 TOPS 以上配 24GB 显存非常适合在边缘侧或者私有化机房部署目标检测模型。YOLO 这种经典的一阶段检测算法恰好就是它在实际落地时最常见的工作负载。这篇文章我打算结合自己实际部署过的经验把 Atlas 300V 24G 从硬件选型、环境搭建、模型转换到最终用 Python 完成 YOLO 推理的完整流程捋一遍。包括我踩过的坑、查过的日志、调过的参数都会写出来。想入坑昇腾推理的同学这篇可以直接当操作手册来用。1. Atlas 300V 24G 硬件规格与定位解析1.1 先回答它确实是一块运算加速卡很多人听到“Atlas”这个名第一反应是华为的服务器产品线然后就开始怀疑这卡是不是只有华为自己的框架才能用。实际上不是。Atlas 300V 24G 的全称是 Atlas 300V Pro 推理加速卡它通过 PCIe 接口插在标准 x86 服务器或者 ARM 服务器上对外提供 AI 计算能力。你可以把它理解成一块专攻“推理”的显卡只不过它的驱动、运行时环境和 CUDA 完全不同走的是昇腾自己的 CANN 软件栈。回到热搜那个问题“Atlas 300V 24G 是运算加速卡吗”——是而且是明确的人工智能运算加速卡。它上面的昇腾 310P 芯片集成了 AI Core、CPU 和编解码单元其中 AI Core 负责矩阵运算、卷积、激活这些深度学习算子CPU 则负责调度和部分不适宜在 AI Core 上执行的算子。24GB 指的是板载内存容量对于视觉模型来说非常宽裕YOLOv8s 这种规模的模型一个 batch 塞到 16 甚至 32 张图压力都不大。1.2 为什么不直接用 GPU做推理部署的人第一反应往往是我有 GPU 为什么不直接用这里有个很现实的问题消费级显卡如 RTX 4090显存够大但功耗高、体积大多卡部署时机箱散热、电源都麻烦专业推理卡如 T4、L4 价格又很高。Atlas 300V 24G 定价相对低24GB 显存对于很多工业视觉场景来说足够用功耗控制得也不错整卡满载功耗在几十瓦级别被动散热设计对服务器风道友好。这意味着在一个标准 2U 服务器里插四张卡是件很轻松的事实际算力密度很可观。另外在国产化、自主可控的诉求下昇腾平台在能源、交通、制造、安防这些行业里已经成为 GPU 之外的主流选择。很多项目的招标要求里直接写明必须支持昇腾 Atlas 系列所以提前把部署流程跑通对做项目交付的同学来说是刚需。1.3 它的短板在哪里我不吹这卡。它的短板也很明显310P 芯片的 FP16 算力远不如 GPU所以在训练场景下基本帮不上忙至少不适合跟 A100 这种训练卡比。它更擅长的是定点推理尤其是 INT8 量化之后的模型。另外它的算子生态虽然一直在补但和 CUDA 生态比还是有差距如果模型里用了特别冷门的自定义算子转换时大概率要折腾。搞清楚这些边界选型时就不会抱有不切实际的期望。2. 环境准备CANN 软件栈搭建全流程2.1 宿主机基础要求部署 Atlas 300V 24G 之前先确认宿主机满足基本条件。操作系统建议用 Ubuntu 20.04 或者 22.04 LTS内核版本不要太新否则驱动编译容易出幺蛾子。服务器必须有 PCIe x16 插槽供电要满足要求机箱风道得能照顾到被动散热片。我用的是 x86 架构的服务器系统是 Ubuntu 20.04内核 5.4。如果你手头是鲲鹏 ARM 服务器流程基本一样只是安装包要选 aarch64 版本。2.2 安装驱动和固件拿到卡之后第一件事是到昇腾社区下载对应版本的驱动和固件。这里有个关键点驱动、固件、CANN 工具包三者版本必须匹配否则后面跑起来各种莫名其妙的问题。我建议直接下载同一个版本号下的全套比如 8.0.RC1 版本对应的 driver、firmware、CANN toolkit 一起下。驱动和固件安装用 root 用户执行# 安装驱动--full 表示全量安装 ./Ascend-hdk-310P-npu-driver_8.0.RC1_linux-x86_64.run --full # 安装固件 ./Ascend-hdk-310P-npu-firmware_8.0.RC1_linux-x86_64.run --full安装完成后重启机器然后检查驱动是否正常npu-smi info正常情况下能看到类似下面这样的输出每张卡的状态都是 OK-------------------------------------------------------------------------------------------- | npu-smi 22.0.0 Version: 22.0.0 | ------------------------------------------------------------------------------------------ | NPU Name | Health | Power | HBM Usage | Temp | | 0 310P | OK | 28W | 0% / 24GB | 42C | ------------------------------------------------------------------------------------------如果 npu-smi 命令找不到多半是环境变量没配好或者驱动没装成功后面会讲排查方法。2.3 安装 CANN 工具包驱动和固件只是让硬件能工作真正让开发者写代码的是 CANN。CANN 相当于昇腾的 CUDA 运行时里面包含算子库、图编译引擎GE、推理运行时acl等模块。下载 Ascend-cann-toolkit 安装包后执行./Ascend-cann-toolkit_8.0.RC1_linux-x86_64.run --install安装默认路径是 /usr/local/Ascend/ascend-toolkit。装完之后配置环境变量每次开新终端都得 source 一下或者直接写进 ~/.bashrcsource /usr/local/Ascend/ascend-toolkit/set_env.sh验证 CANN 是否装好可以看版本cat /usr/local/Ascend/ascend-toolkit/latest/version.cfg2.4 Python 环境与 torch_npu如果你打算用 PyTorch 在昇腾 NPU 上做模型迁移还需要安装昇腾的 PyTorch 适配层 torch_npu。CANN 本身自带的推理接口是 pyACL但很多时候我们用 PyTorch 做预处理和模型原型验证所以 torch_npu 很有用。安装方式是通过 pip注意 torch 和 torch_npu 版本要对应。我用的组合是# 以 Python 3.8 为例安装与 CANN 8.0.RC1 匹配的版本 pip install torch2.1.0 pip install torch_npu2.1.0.post6安装完测试一下 NPU 是否可见import torch import torch_npu print(torch.npu.is_available()) # 如果输出 True说明昇腾 NPU 已经被 PyTorch 识别这里有个容易忽略的点使用 torch_npu 时设备编号从 0 开始但在多卡环境里你可以通过环境变量 ASCEND_RT_VISIBLE_DEVICES 指定当前进程可见的卡号方式类似 CUDA_VISIBLE_DEVICES。3. YOLO 模型转换从 PyTorch 权重到昇腾 OM 模型3.1 转换链路总览在昇腾平台部署 YOLO核心工作是把 PyTorch 模型转换成昇腾的 OM 格式。OMOffline Model是昇腾推理引擎能直接加载的离线模型文件里面包含了算子的具体实现以及针对特定昇腾芯片的优化信息。转换链路是PyTorch .pt - ONNX .onnx - 昇腾 OM .om为什么不直接把 PyTorch 模型放到 NPU 上跑因为 310P 上的 AI Core 执行的是经过编译优化的算子PyTorch 原生的动态图结构在推理效率上远不如静态图。OM 格式相当于把模型的网络结构、算子调度、内存分配全部提前规划好推理时直接按照既定流程执行性能和稳定性都是最优的。3.2 用官方 YOLOv5 仓库导出 ONNXYOLOv5 官方仓库里已经内置了导出脚本可以直接用的cd yolov5 python export.py --weights yolov5s.pt --include onnx --opset 11导出完成后在工作目录会生成 yolov5s.onnx。这里要注意几个点opset 版本尽量用 11 或者 12老版本的 CANN 对高版本 opset 支持可能不完整。默认导出的是固定输入尺寸 640x640这个在后面 ATC 转换时也要保持一致否则推理会报维度不匹配。导出的时候 YOLOv5 会把 NMS 后处理拿掉ONNX 模型只输出预测特征图。这意味着 NMS 要在转换成 OM 之后由我们在 Host 侧自己实现。别指望 OM 模型里带 NMS至少在当前 CANN 版本下通过 ATC 直接转换含 NMS 的模型会遇到很多算子兼容问题。3.3 使用 ATC 工具转换成 OMATC 是 CANN 自带的模型转换工具位置在 /usr/local/Ascend/ascend-toolkit/latest/bin/atc配置过环境变量后可以直接执行。转换命令如下atc \ --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_bs1 \ --input_formatNCHW \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --loginfo参数含义逐个解释--model输入 ONNX 文件路径。--framework55 表示 ONNX 格式。--output输出文件前缀名上面会生成 yolov5s_bs1.om。--input_format输入张量的数据排布NCHW 是 PyTorch 默认格式。--input_shape固定输入 shape。这里把 batch 固定为 1图片尺寸 640x640。--soc_version非常重要的参数必须指定目标芯片型号。310P 芯片族一般填 Ascend310P3填错的话转换可能成功但加载时会报“so chip version mismatch”。--log日志级别报错时改成 debug 能拿到更多线索。转换成功后会看到类似输出的结尾ATC run success同时目录下多出 yolov5s_bs1.om 文件。3.4 动态 shape 的坑有一个容易踩的坑如果你在 export.py 导出 ONNX 时没有固定 shape或者转换时 --input_shape 写了 -1表示动态维度那 ATC 转换时就需要开启动态 shape 配置格式复杂很多而且 310P 对动态 shape 的支持不如静态 shape 稳定。我的建议是推理场景下 batch 数本来就应该在部署时定好固定成 1 或 4 或 8换来的是更稳的推理性能和更少的内存碎片。不要在边缘设备上追求动态 batch。4. 基于 pyACL 的 YOLO 推理代码实战4.1 pyACL 推理流程模型转换完成之后就可以用 pyACL 来加载 OM 模型做推理了。pyACL 是 CANN 自带的 Python 接口在安装 CANN 之后可以直接 import acl。整个推理流程分这几步初始化 ACL设置设备。加载 OM 模型。准备输入输出内存。执行模型推理。拿到输出后做后处理解码、NMS、画框。下面是一个极简的可运行框架去掉了一些边界检查方便看清楚主线import acl import numpy as np import cv2 # 1. 初始化 acl.init() ret acl.rt.set_device(0) context, ret acl.rt.create_context(0) # 2. 加载模型 model_path byolov5s_bs1.om model_id, ret acl.mdl.load_from_file(model_path) # 3. 获取模型输入输出信息 desc acl.mdl.create_desc() ret acl.mdl.get_desc(desc, model_id) input_size acl.mdl.get_num_inputs(desc) output_size acl.mdl.get_num_outputs(desc) # 分配输入输出设备内存 # 输入图像先预处理为 1x3x640x640float32 类型 input_data np.random.randn(1, 3, 640, 640).astype(np.float32) # 把输入拷贝到设备内存 input_ptr acl.util.np_to_ptr(input_data) # 这里省略了申请 device 内存和 memcpy 的代码CANN 示例中有完整实现 # 4. 执行推理 ret acl.mdl.execute(model_id, input_data_buffers, output_data_buffers) # 5. 取出输出 output_data acl.util.ptr_to_numpy(output_ptr, output_shape, output_dtype) # YOLOv5 输出的 shape 一般是 [1, 25200, 85] # 25200 80x80 40x40 20x20 三个尺度的锚框总和85 4 1 80 类 acl.rt.destroy_context(context) acl.rt.reset_device(0) acl.finalize()这段代码虽然不能直接运行中间缺了内存管理的细节但已经把流程讲清楚了。实际项目中我建议直接用 CANN 自带的 samples 目录下的推理示例在 /usr/local/Ascend/ascend-toolkit/latest/ 下有大量官方示例代码参考里面的 acl_resnet50 示例改成 YOLO 非常方便。4.2 后处理为什么不能在 NPU 上做很多人第一次用 OM 模型跑 YOLO输出拿到的是 1x25200x85 的矩阵然后满脑子疑问NMS 呢怎么全是原始输出原因我在前面说了NMS 在 ATC 转换时被移除了。所以后处理需要在 CPU 上完成。这里我们直接用 NumPy 实现一个简化版的解码和 NMSdef xywh2xyxy(x): y np.copy(x) y[..., 0] x[..., 0] - x[..., 2] / 2 y[..., 1] x[..., 1] - x[..., 3] / 2 y[..., 2] x[..., 0] x[..., 2] / 2 y[..., 3] x[..., 1] x[..., 3] / 2 return y def nms(boxes, scores, iou_threshold0.45): x1 boxes[:, 0] y1 boxes[:, 1] x2 boxes[:, 2] y2 boxes[:, 3] areas (x2 - x1) * (y2 - y1) order scores.argsort()[::-1] keep [] while order.size 0: i order[0] keep.append(i) xx1 np.maximum(x1[i], x1[order[1:]]) yy1 np.maximum(y1[i], y1[order[1:]]) xx2 np.minimum(x2[i], x2[order[1:]]) yy2 np.minimum(y2[i], y2[order[1:]]) w np.maximum(0.0, xx2 - xx1) h np.maximum(0.0, yy2 - yy1) inter w * h iou inter / (areas[i] areas[order[1:]] - inter) inds np.where(iou iou_threshold)[0] order order[inds 1] return keep # 假设 output 是模型原始输出shape [1,25200,85] pred output[0] # [25200, 85] conf pred[:, 4] # 只保留置信度大于 0.25 的框 mask conf 0.25 pred pred[mask] conf conf[mask] # 找每个框中得分最高的类 class_ids np.argmax(pred[:, 5:], axis1) scores pred[:, 4] * pred[:, 5:].max(axis1) boxes xywh2xyxy(pred[:, :4]) # 按类别做 NMS final_boxes [] final_scores [] final_classes [] for cls in np.unique(class_ids): cls_mask class_ids cls cls_boxes boxes[cls_mask] cls_scores scores[cls_mask] keep_idx nms(cls_boxes, cls_scores) final_boxes.extend(cls_boxes[keep_idx]) final_scores.extend(cls_scores[keep_idx]) final_classes.extend([cls] * len(keep_idx))这类后处理代码在 CPU 上执行单张 640x640 图片通常只需要几毫秒到十几毫秒完全可以接受。4.3 图片预处理细节YOLO 推理前对输入图片的预处理有几个细节和 GPU 上跑 PyTorch 时是一样的letterbox 缩放、BGR 转 RGB、归一化、维度变换。def letterbox(img, new_shape(640, 640), color(114, 114, 114)): shape img.shape[:2] 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]) / 2 dh (new_shape[0] - new_unpad[1]) / 2 img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom int(round(dh - 0.1)), int(round(dh 0.1)) left, right int(round(dw - 0.1)), int(round(dw 0.1)) img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return img img cv2.imread(test.jpg) img letterbox(img) img img[:, :, ::-1].transpose(2, 0, 1) # BGR-RGB, HWC-CHW img np.ascontiguousarray(img, dtypenp.float32) / 255.0 img np.expand_dims(img, axis0) # 变成 [1,3,640,640]预处理完的数据直接喂给模型注意输入数据类型要跟 ATC 转换时的保持一致。默认是 float32不要弄成 uint8否则推理结果会差很远。5. 实测经验性能数据与资源规划5.1 不同模型的实测表现我在 Atlas 300V 24G 上实际跑过 YOLOv5s、YOLOv8s、YOLOv8m 这几个模型说一下大概的量级。需要说明的是具体数值跟输入分辨率、batch size、后处理逻辑都有关系下面只是参考。模型输入尺寸BatchINT8量化实测时延ms/张YOLOv5s640x6401否6~8YOLOv5s640x6401是3~4YOLOv8s640x6401否8~10YOLOv8s640x6401是4~5YOLOv8m640x6401否15~18这里说的时延是单张图在 NPU 上的推理时间不含预处理和后处理。如果 batch 提到 8单张平均时延还能再低一些因为算子并行效率上来了但会牺牲一点单张响应速度。对于视频流分析这种高吞吐场景我建议 batch 固定在 4~8 之间实测整体吞吐比 batch1 提升 40% 以上。5.2 是否要做 INT8 量化Atlas 300V 的 AI Core 对 INT8 计算效率远高于 FP16所以做量化往往能带来接近翻倍的性能提升。但量化不是简单的 ptq 一键转换它需要校准数据集而且对精度有影响。从我的实践看YOLOv5s 从 FP16 转 INT8mAP 掉 0.5%~1.5% 左右取决于校准集和原始模型精度在工业检测场景下完全能接受。量化流程一般是用昇腾的 AMCT 工具需要准备几百张有代表性的图片做校准操作比直接 ATC 转换多一个步骤。建议项目上线前做一轮量化测试如果精度达标就上 INT8性价比非常高。5.3 多卡部署时的显存规划24GB 显存看着大但如果开多路视频流分析每个模型实例加上输入输出缓存和预处理中间变量占用的资源会快速累积。一条经验是单张 Atlas 300V 24G 跑 YOLOv5s INT8 模型开 8 路 1080p 视频流做实时检测是很稳的如果模型换成 YOLOv8m建议降到 4~6 路。用 npu-smi info 监控显存如果发现 HBM 使用率超过 90%优先降低 batch 或者减少并发实例数。不要让进程因为显存不足而被 kill。6. 常见问题与排查技巧实录6.1 npu-smi 看不到设备驱动装了、重启了npu-smi 却提示命令找不到。先确认 /usr/local/Ascend/driver/tools/npu-smi 这个路径是否存在如果存在把它加到 PATH 里。如果连文件都没有说明驱动安装失败需要重新安装驱动。有一种情况是驱动安装时报“kernel module compile failed”这通常是因为宿主机内核未安装对应头文件。解决办法sudo apt install linux-headers-$(uname -r)然后重新装驱动。装完再跑一次 npu-smi info 验证。6.2 ATC 转换报错E40001 / 算子不支持ATC 转换是最容易出问题的环节。最常见的错误是某个算子不支持日志里会明确提示不支持算子的名称比如 Slice、Resize 等。这里的矛盾点在于YOLO 的某些实现细节会用一些冷门算子但大部分情况下都是 CANN 版本太老导致的。我的处理思路先看是不是 CANN 版本太旧升级到最新稳定版。如果升级后还报错检查 ONNX 的 opset 版本改成 11 重新导出。查看日志中具体哪个算子不支持到昇腾社区搜一下一般有解决方案比如替换 PyTorch 里 upsample 的实现方式或者用前端算子替换工具。都不行的话考虑换模型规格比如从 YOLOv8m 换到 YOLOv5s很多时候算子复杂度降低后转换就过了。6.3 推理结果全为 0 或者框的位置完全不对这个问题多半出在预处理上。检查三件事输入数据是否做了归一化除以 255ATC 转换时模型内部是按归一化后的输入训练的。输入的维度排列是不是 NCHWPyTorch 的模型默认是 NCHW如果你的预处理代码不小心把 HWC 直接塞进去结果就是乱的。输出解析时YOLOv5 的输出布局是 [batch, 25200, 85]YOLOv8 是 [batch, 84, 8400] 转置后的排列不同版本导出的 ONNX 输出顺序可能不同。先用 Netron 工具打开 ONNX 确认输出的 shape 和 dtype再写解析代码能省很多调试时间。6.4 显存泄漏导致长时间运行后崩溃推理服务跑一两天之后显存爆掉这是很典型的显存泄漏问题。在 pyACL 代码里每一次 acl.rt.malloc 分配的设备内存都要用 acl.rt.free 释放输入输出 buffer 用完立即释放。ACL 不像 Python 的 GC 能自动回收设备内存开发时最容易漏。排查方法在循环推理的代码里逐步注释掉嫌疑内存释放的调用对比 npu-smi 监控看哪一步内存只增不减。官方示例的代码里一般都有申请和释放的配对注释照着改就行。6.5 固件和驱动版本不匹配导致加载模型失败有时候 ATC 转换成功、代码也没问题但 acl.mdl.load_from_file 报错错误码 505 或 507。大概率是驱动、固件和 CANN 三者版本不一致。检查方式npu-smi info -t board查看固件版本再对比 /usr/local/Ascend/ascend-toolkit/latest/version.cfg 里的 CANN 版本。华为昇腾社区的版本配套表写得非常清楚直接去查对应的推荐组合然后统一升级或降级到同一版本。7. 部署落地后的几点心得体会最后聊几句实在的。Atlas 300V 24G 这块卡如果只是跑跑 demo可能感觉不出和 GPU 的差别但真正进了项目交付环节昇腾平台的工具链和调试经验是另一套体系需要花时间适应。我个人踩过最深的坑就是版本匹配问题驱动、固件、CANN、PyTorch 适配层任何一个版本不匹配后面都会用各种奇怪的方式回报你。所以新环境搭建的第一件事一定是去官方查版本配套表把组合固定下来最好写进团队的部署文档里。第二个体会是后处理不能等。很多从 GPU 迁移过来的同学习惯用 torchvision 的 NMS 或者模型自带的 NMS到昇腾这边发现都没有一时不知道怎么写。其实用 NumPy 实现一版 YOLO 后处理并不复杂而且 CPU 后处理的时间占比很低真正要考虑的是如何让整条链路拉流、解码、缩放、推理、后处理、推送并行起来而不是纠结单个环节快了几毫秒。第三个建议是充分利用官方 samples。昇腾社区和 CANN 安装包里已经有很多现成的推理示例包括模型转换脚本、ACL 推理模板、视频流处理 demo。不要从零开始写先把官方示例跑通再往里替换自己的模型和逻辑效率高很多。Atlas 300V 24G 不是万能的但如果你需要的是低功耗、大显存、稳定可交付的 AI 推理方案它确实是个可以认真考虑的选项特别是搭配 YOLO 系列模型做工业视觉项目。希望这篇文章能帮你把从硬件到推理的这条路走通。
返回列表