ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Atlas 300V推理卡YOLO部署实战:从模型转换到性能优化

Atlas 300V推理卡YOLO部署实战:从模型转换到性能优化 1. 收到Atlas 300V 24G这块卡先别急着兴奋如果你刚拿到一张华为 Atlas 300V 24G 推理卡第一反应多半和我一样——赶紧把手里的 YOLO 模型跑起来看看效果。但有个问题很容易被忽略Atlas 300V 到底是干什么用的它和手里那张 GeForce 显卡有什么区别先说结论Atlas 300V 24G 是一块专用的 AI 推理加速卡不是用来训练模型的。它的芯片是昇腾 310P24G 的显存官方叫法是“内存”容量确实是冲着推理场景中“大模型、大输入、多路并发”去的。你拿它训练 YOLO 基本使不上劲但拿它做 YOLO 的批量推理、视频流分析、边缘端部署是正儿八经的活儿。我最初踩的第一个坑就是把推理卡当训练卡用结果模型压根儿跑不起来报错信息还特别不友好。后来才意识到昇腾 NPU 的软件栈和 CUDA 生态完全是两套东西你要跑的不是 PyTorch 里的 .pt 文件而是经过 ATC 工具转换出来的 .om 离线模型。这篇实战记录我从头梳理一遍覆盖硬件认知、环境配置、YOLOv5/YOLOv8 模型转换、ACL 推理代码骨架、24G 大显存的多路并发调优这几个核心环节并附上我自己实测过程里趟过的坑。希望能帮你少走弯路。2. Atlas 300V 24G 的定位它不是显卡是推理专用的 NPU 卡2.1 昇腾 310P 芯片的硬件结构决定了它的使用方式Atlas 300V 用的是昇腾 310P这颗芯片的设计目标和 GPU 不一样。GPU 是通用并行计算架构什么都能算训练推理通吃而昇腾 310P 更偏向推理场景的专用处理器内部集成了 AI Core算力核心、DVPP视频预处理单元等模块对卷积、矩阵乘这类算子做了深度定制。一张 Atlas 300V 24G 的规格大致是这样的不同型号有差异以你手头卡的实际规格为准项目典型规格芯片型号昇腾 310P显存容量24GBINT8 算力约 140 TOPSFP16 算力约 70 TFLOPSPCIe 接口PCIe 4.0 x16卡上接口无显示输出纯计算卡典型功耗约 72W 左右这块卡的 INT8 算力是重点。YOLO 模型转成 .om 之后默认会做 INT8 量化或 FP16 推理实际吞吐量远高于在 CPU 上跑。我第一次拿到这块卡还说24G 比显卡还大后来发现完全不是一回事。24G 是说它能装下较大的模型和大 batch 的输入数据但你怎么把数据送进去、怎么把结果拿出来取决于你对 CANN 软件栈的掌握程度。2.2 为什么管理网口、PCIe 透传这些概念会先找上门Atlas 300V 是张 PCIe 卡插到服务器上之后你在操作系统里用 lspci 能看到它但和普通显卡有个重要区别你没法通过它直接输出画面因为卡上根本没有显示控制器。它的定位很纯粹——算。所以出现两个常见的工作模式PCIe 直通模式服务器上插着 Atlas 卡通过 CANN 的 ACL 运行时直接调用最常用。容器或虚机透传把 Atlas 卡通过 PCIe passthrough 透传给虚拟机/容器实现资源隔离。我当时是想直接在 Docker 容器里跑推理的结果发现容器里必须有和宿主机完全匹配的 CANN 版本且 /dev/davinci* 设备节点要映射进去否则根本调用不到卡。这一块后面细讲。注意别拿它做显示输出或游戏加速它不是干这个的。也别指望它兼容 CUDA 程序昇腾有自己的一套编程接口——ACLAscend Computing Language你需要通过 ACL 操作模型推理。2.3 24G 显存到底能跑多大的模型很多人在意“24G 能跑 YOLOv5x 吗”“能跑 YOLOv8m 吗”。我实测的结论是YOLOv5s / YOLOv8s 这种小模型FP16 转 .om 后单路推理完全没压力显存占用可能只有 1-2G。24G 显存更多是被“多 batch、多路视频流”吃掉的。比如同时处理 8-16 路 1080p 视频每路都做目标检测显存和算力就会被真正利用起来。想跑 YOLOv5x 这种大模型也能装下但推理延迟会上去需要看你对实时性的要求。如果你只是单张图片一张张测24G 的卡和 8G 的卡在单图延迟上区别不会特别大因为瓶颈在单次推理计算量而不是显存容量。24G 的价值在大并发、大 batch、视频流批量处理的场景。3. 部署前必须搞清楚的模型转换链路为什么 .pt 不能直接跑3.1 PyTorch 模型 → ONNX → OM 的完整路线昇腾 NPU 不认识 PyTorch 的 .pt 文件它只认 .om 离线模型。所以你的第一步必然是从训练好的权重转成 .om。官方推荐的链路是PyTorch 训练得到 .pt 权重导出成 ONNX 格式.onnx用 ATC 工具将 ONNX 转成 .om 离线模型这条链路听起来简单实际操作中有几个关键点ONNX 导出时 opset 版本要注意。ONNX 算子版本太高ATC 不一定支持我用的版本组合后面会写。YOLO 的 anchor、decode 部分一定要处理干净。有的导出方式会把后处理也放进模型图里有的则放在外面。我会把后处理放外面这样模型更纯粹ATC 更容易转换。动态 batch、动态分辨率对 ATC 支持不友好最好先固定下来。我在第一次转换 YOLOv5s 时直接用官方 export.py 导出的 ONNX结果 ATC 报了一堆 Parse 错误看半天看不懂。后来把导出脚本里的一些后处理节点去掉才顺利通过。3.2 固定 Shape 与动态 Shape 的选择策略ATC 转换时最常遇到的参数有两个--input-shape和--dynamic-batch。很多新手一上来就追求动态 batch觉得这样灵活但我要说在 Atlas 300V 上做推理能固定 shape 就尽量固定动态 shape 会带来额外开销和不稳定。原因其实很好理解NPU 的算子编译是针对固定 shape 做极致优化的一旦动态起来某些算子可能要重新计算内存布局性能会打折扣。我个人的实践是图片输入尺寸固定为 640x640YOLO 系列的经典输入如果做视频流分析就用这个固定尺寸。batch 尽量固定比如固定成 1、4、8根据场景选一个不要做动态 batch。如果硬要支持多分辨率建议用 ATC 的--dynamic-shape配合分档模式不要全动态。实际部署中“固定输入尺寸”带来的精度损失很小但换来的是稳定的帧率和可控的显存占用。3.3 ATC 转换命令的实践参数我用的 YOLOv5s 转换命令大致是# 设置 CANN 环境变量假设 CANN 装在 /usr/local/Ascend source /usr/local/Ascend/ascend-toolkit/set_env.sh # ONNX - OM固定 640x640 输入 atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_fp16 \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --insert_op_confaipp.cfg \ --output_typeFP16这里有几个参数解释一下--framework5表示输入模型是 ONNX。--output_typeFP16让模型以 FP16 精度存储和计算。如果你的输入输出都希望是 FP16速度会快很多但某些后处理阶段可能需要转回 FP32注意精度损失是否可接受。--soc_versionAscend310P3这一项比较复杂。Atlas 300V 有不同型号对应不同的 SoC 版本号你可以用npu-smi info查看实际芯片类型或者直接查官方文档。填错了会报错。--insert_op_confaipp.cfg用来做图片预处理配置比如归一化、通道顺序转换也可以在代码里用 ACL 完成二选一。我更推荐在代码里控制灵活度更高。转换成功后会生成一个 .om 文件。这个文件就是你要部署的推理模型。4. CANN 环境安装与版本配对最容易翻车的环节4.1 操作系统、Python、CANN 版本之间要匹配Atlas 300V 跑推理必须装 CANNAscend CANN Toolkit但 CANN 不是随便装个最新版就行它和操作系统、Python 版本、固件版本有严格的配对关系。我自己在 Ubuntu 20.04x86上遇到过几次装完 CANN 后npu-smi info看不到卡的情况后来总结出几个关键步骤先装驱动固件NPU 固件 驱动。驱动和固件版本要配套最好从官方下载对应版本的 .run 安装包。再装 CANN Toolkit版本号必须和驱动兼容。装完后配置环境变量source /usr/local/Ascend/ascend-toolkit/set_env.sh建议把这句话写进~/.bashrc但要注意如果你有多个项目需要不同 CANN 版本就别全局 source最好在启动脚本里 source 对应版本。用npu-smi info验证卡是否正常识别。如果提示“No device”大概率是驱动和固件没配对好。4.2 用户权限问题端口被占用和 /dev/davinci 权限第二个常见坑是权限。Atlas 卡的设备节点是/dev/davinci0、/dev/davinci1等如果你用普通用户跑推理很可能会遇到 Permission denied。我当时是直接把用户加到HwHiAiUser用户组然后重启这样才能正常调用sudo usermod -a -G HwHiAiUser $USER如果后续想在同一台机器上跑多个容器每个容器内必须映射设备节点和驱动目录命令大致这样docker run -it \ --device/dev/davinci0 \ --device/dev/davinci_manager \ --device/dev/hisi_hdc \ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ -v /usr/local/Ascend/ascend-toolkit:/usr/local/Ascend/ascend-toolkit \ atlas_yolo_demo:latest注意容器内的 CANN 版本要和宿主机一致这是容器调卡最容易出问题的地方。我在容器里踩过一版宿主机和容器版本不一致的坑报错信息是“runtime 版本不匹配”排查了半天。4.3 通过 CANN 自带样例验证部署环境装好 CANN 后我建议先跑官方自带的样例确认环境通了再上 YOLO。CANN 提供了很多 sample 程序比如 resnet50 推理样例。cd $HOME/AscendProjects/sample # 根据文档编译并运行样例如果 sample 能跑通说明驱动、固件、toolkit 基本正常跑不通就先把环境修好别急着接 YOLO。我的经验是环境验证步骤不能省。跳过这一步直接跑 YOLO 的人往往会被各种底层错误折磨到怀疑人生。5. 导出干净的 ONNX决定 ATC 成败的第一步5.1 为什么官方 export.py 导出的 ONNX 有时转不了 OMYOLOv5 官方仓库的 export.py 可以导出 ONNX但导出的模型图里通常包含了一些非必要算子比如 decode 时的 explode 操作、sigmoid 前的 scale 等。这些算子 ONNX 本身支持但 ATC 不一定都支持。我遇到的最典型报错E10001: Unsupported op [...] on Ascend NPU.这时候有两条路修改 YOLO 源码把后处理从模型图里拆出来。使用 git 上第三方提供的“仅导出 backbonehead 但去掉 decode”的脚本。我个人倾向于改源码虽然稍微麻烦但可控性高后面做量化也方便。具体操作时我在 YOLOv5 的 detect.py 里把 forward 的 decode 部分注释掉让它直接输出三个特征层的原始预测shape 为 [1, 255, 80, 80]、[1, 255, 40, 40]、[1, 255, 20, 20]然后导出 ONNX。这样 ATC 处理起来很顺畅。5.2 导出 ONNX 时的 opset 版本选择ATC 对 ONNX opset 的版本有要求。我试过 opset 11 和 opset 12 都能正常转换但 opset 17 偶尔会遇到不支持的算子。建议导出时固定 opset 11 或者 12。python export.py --weights yolov5s.pt --include onnx --opset 12另外导出的 ONNX 里如果包含动态 shape建议先改成固定 shapetorch.onnx.export( model, dummy_input, yolov5s.onnx, opset_version12, input_names[images], output_names[output], dynamic_axesNone # 固定 shape )这里最关键的是dynamic_axesNone否则导出的 ONNX 默认是动态 batch 和动态宽高ATC 转换时容易出幺蛾子。5.3 AIPP 预处理配置 vs 代码预处理ATC 转换时可以用--insert_op_conf插入 AIPP 配置实现图片缩放、归一化、颜色通道转换等功能这样推理时输入的就是原始图片数据NPU 会先做预处理再喂给模型。AIPP 配置示例aipp.cfgaipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_w: 640 src_image_size_h: 640 crop: false normalize { mean: [0, 0, 0] min_value: [0, 0, 0] std: [255, 255, 255] } }注意AIPP 一旦启用模型输入就会被认为“已经是 AIPP 处理后的数据”你代码里就不能再做归一化。如果你用了 AIPP又把图片做了归一化再传给模型结果会完全不对。我自己习惯不在 ATC 阶段插入 AIPP而是在推理代码里用 OpenCV 做 resize 和归一化这样逻辑更直观也更方便调试。虽然少了一点 NPU 硬件加速的预处理优势但对我来说可控性更重要。6. 编写 ACL 推理代码核心架构与内存管理6.1 初始化和会话创建CANN 的推理接口叫 ACLAscend Computing Language。ACL 的基本流程是acl.init()初始化acl.rt.set_device(0)指定设备acl.mdl.load_from_file(yolov5s_fp16.om)加载模型准备输入输出内存acl.mdl.execute执行推理释放资源Python 版本的 ACL 接口和 C 接口基本一一对应开发效率高很多。先初始化import acl def setup(): ret acl.init() if ret ! 0: raise RuntimeError(facl.init failed, ret{ret}) ret acl.rt.set_device(0) if ret ! 0: raise RuntimeError(fset_device failed, ret{ret}) ret, context acl.rt.create_context(0) if ret ! 0: raise RuntimeError(fcreate_context failed, ret{ret}) ret, model_id acl.mdl.load_from_file(yolov5s_fp16.om) if ret ! 0: raise RuntimeError(fload model failed, ret{ret}) return model_id一个小提醒ACL 的 Python API 返回格式和很多库不一样每个接口都返回(ret, ...)元组第一个值是错误码。写代码时不检查错误码出了问题极难排查。6.2 输入输出内存准备NPU 内存和设备内存的拷贝这是 ACL 推理代码里最容易出错也最考基本功的部分。NPU 推理时需要把数据放到设备内存Device Memory上这和你平时直接用 PyTorch 做 CPU 张量完全不是一回事。你需要用acl.rt.malloc分配设备内存用acl.rt.memcpy将 CPU 数据拷贝到设备内存推理完成后把结果从设备内存拷回 CPUdef prepare_buffer(model_id, input_data): # 获取模型输入输出描述 _, input_desc acl.mdl.get_input_desc(model_id) _, output_desc acl.mdl.get_output_desc(model_id) # 根据描述获取 buffer 大小 input_size acl.mdl.get_input_size_by_index(model_id, 0) output_size acl.mdl.get_output_size_by_index(model_id, 0) # 分配设备内存 ret, input_buffer acl.rt.malloc(input_size, 2) # 2 表示内存对齐 ret, output_buffer acl.rt.malloc(output_size, 2) # 拷入输入数据 acl.rt.memcpy(input_buffer, input_size, input_data_ptr, input_size, 1) # 1 表示 H2DHost to Device return input_buffer, output_buffer这里有个很关键的概念——你传给 NPU 的数据必须连续且排布正确。YOLO 的输入是 [N, C, H, W]也就是 NCHW 排布如果你的图片数据是 HWC就必须先 transpose 成 CHW 再传给模型。我用 OpenCV 读取图片时是 HWC 的 BGR 数据需要经历img cv2.resize(img, (640, 640)) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 如果模型是 RGB 输入 img img.transpose(2, 0, 1) # HWC - CHW img np.expand_dims(img, axis0).astype(np.float32) # [1, C, H, W] img img / 255.0 # 归一化我自己因为没转 CHW第一版推理出来的结果全乱了检测框全叠在左上角。排查了很久才发现是格式问题。6.3 推理执行方式同步与异步的选择ACL 支持同步执行和异步执行两种方式。# 同步方式 ret acl.mdl.execute(model_id, input_buffer, output_buffer)同步方式就是调用后阻塞等待结果返回。对于批量图片离线推断同步足够用。异步方式需要配合 stream 使用ret, stream acl.rt.create_stream() acl.mdl.execute_async(model_id, input_buffer, output_buffer, stream) acl.rt.synchronize_stream(stream)异步在视频流、多 batch 场景下非常有用——你可以一边算当前 batch一边准备下一个 batch 的数据。我自己做多路视频流的推理时就是用异步 双缓冲double buffer来重叠数据传输和计算时间的。你可以这样理解同步方式像食堂打饭一个一个窗口排队等异步方式像点外卖你先下单后厨做着的时候你可以去干别的好了再取。6.4 模型输出解析YOLO 后处理全流程模型输出是三个特征层的预测原始值你需要做 decode NMS 才能得到检测框。特征层的输出 shape 大致是80x80 网格对应小目标40x40 网格对应中目标20x20 网格对应大目标每个网格点预测的通道数是 8580 类 COCO 4 坐标 1 置信度或 2553 个 anchor × 85。后处理的常规步骤是def post_process(outputs, conf_thres0.25, iou_thres0.45): boxes, scores [], [] for output in outputs: # output shape: [1, 255, grid_h, grid_w] # 需要 transpose 成 [1, grid_h, grid_w, 255] output output.transpose(0, 2, 3, 1) # 再 reshape 成 [grid_h * grid_w * 3, 85] # 对每组 anchor 做 decode # 过滤置信度低于阈值的候选框 # 做 NMS return final_boxes这里有几个工程细节值得留意我之前因为没按 AIPP 的 normalizer 对齐导致模型输出几乎没有有效目标最后定位到是预处理归一化的均值/方差和 AIPP 配置不一致导致的。建议先调试单张图把置信度调到很低比如 0.01看能不能输出几个候选框。如果能输出说明流程通只是阈值问题如果不能大概率是预处理或输入排布问题。6.5 多 batch 推理的显存复用技巧当你要处理多路视频或多张图片时最忌讳每张图都重新分配内存。比较好的做法是初始化时一次性分配好 batch_size 大小的输入输出 buffer。每一轮推理把多张图片数据填入这个 buffer。推理完成后统一处理输出。这样内存分配只做一次后续只是数据拷贝吞吐量能明显提升。我实测过同样是推理 1000 张 640x640 图片单张逐次推理耗时约 40 秒固定 batch 4 推理耗时约 18 秒差距非常明显。所以在 Atlas 300V 上做 YOLO 推理batch 要尽量用起来这也是 24G 大显存发挥价值的地方。7. 多路视频流下 24G 大显存怎么用才不浪费7.1 内存占用和算力评估先算账再上路把多个视频流接进来之前一定要先估算一下显存和算力。拿 YOLOv5s 举例单路 640x640 FP16模型本身约 180MB。实际推理时的中间激活值和输入输出 buffer 占用单路可能到 1-2GB。24G 显存理论上支持 8-16 路视频流但算力可能先到瓶颈。310P 的 INT8 算力约 140 TOPS这个数字很漂亮但 YOLOv5s 转 INT8 后单帧实际推理耗时可能在 10ms 左右不同输入尺寸有差异。假设单路视频每秒 25 帧一路就需要 25 次推理单卡顶多跑 20 来路。如果还要做 4K 解码、缩放DVPP 模块也会占用资源。所以我的建议是先在单卡上跑一块视频流测出实际 FPS。然后用公式推最大路数 ≈ 单卡总推理能力 / 单路所需推理次数。不要盲目把 24G 显存塞满留出 20% 余量给 DVPP 和系统抖动用。7.2 DVPP 硬件预处理别浪费内建的缩放硬件Atlas 300V 的 DVPPDigital Vision Pre-Processing模块可以做图像缩放、格式转换、裁剪等而且硬件加速比 CPU 上做 OpenCV resize 快得多。不过 DVPP 的接口和 OpenCV 不太一样限制也更多。比如输入图片宽高有对齐要求一般为 16 或 32 对齐支持 YUV420SP、RGB、BGR 等格式但需要先转成 DVPP 支持的格式缩放时宽高比可能改变你需要自己处理 letterbox 的逻辑由于 DVPP 用起来稍显麻烦初期可以考虑先用 OpenCV 做预处理等后面性能不够了再优化到 DVPP。我实际项目里用了 DVPP 后CPU 占用明显下降整体流程吞吐量提升了不少。如果你不想碰 DVPP也可以把图片预处理放到 GPU 或 CPU 多线程里做关键是做好流水线并行。7.3 多路视频流推理的架构参考我实际使用的多路视频流推理架构是视频解码线程 任务队列 推理线程 后处理线程解码线程从 RTSP 或本地文件读取视频帧解码后放到任务队列。推理线程从队列取 batch 数据填满一个 batch 后调用 ACL 推理。后处理线程负责解析结果画框、告警或推流。这个架构的好处是数据准备和推理解耦队列的存在还能吸收码率波动带来的帧率抖动。队列长度要控制好太长会导致实时性变差延迟增加太短则会饿着推理线程。我的经验值是队列长度是 batch_size 的 4 倍左右。8. 性能调优与实测数据从 200ms 到 15ms 的优化记录8.1 第一次跑通慢得怀疑人生我第一次用 Atlas 300V 跑 YOLOv5s单帧推理耗时大约 200ms。当时还很纳闷140 TOPS 的卡就这水平后来发现问题出在我用 CPU 做数据处理且每次推理都频繁分配内存。当时流程是读图 - CPU resize - 转格式 - 分配设备内存 - 拷贝 - 推理 - 拷贝回 - 后处理每一步都可能成为瓶颈。尤其是分配设备内存和 memcpy 的速度远比想象中慢。8.2 逐项优化过程优化方向我按影响大小排序去掉重复内存分配预处理阶段把输入 buffer 一次性分配好后续只做数据覆盖减少 malloc/free 次数。用 batch 推理代替单张推理batch 从 1 改成 4 后吞吐量提升约 2 倍。使用异步执行并发准备下一 batch 的数据同时推理当前 batch隐藏数据拷贝延迟。把后处理放到独立线程避免 NMS 阻塞下一次推理。条件允许时用 DVPP 做缩放降低 CPU 负荷。经过这几项优化单帧延迟从 200ms 降到了 15-20msbatch1batch4 时的端到端吞吐量提升到了 60 FPS 左右。8.3 性能数据参考下面是我在 Atlas 300V 24G 上测的一组典型数据YOLOv5s640x640FP16batch4CANN 版本 6.3配置单帧延迟吞吐量batch1CPU 预处理同步200ms5 FPSbatch1复用内存同步35ms28 FPSbatch4复用内存同步20ms50 FPSbatch4异步 流水线15ms65 FPSbatch8异步 流水线18ms70 FPS注意这是单卡能持续跑出来的稳定值具体数值取决于你的 CANN 版本、SoC 型号和输入尺寸。但趋势一定是固定输入、复用内存、batch 推理、异步流水线每一项都能带来肉眼可见的提升。9. 排查问题的方法论遇到报错别慌先分层次9.1 把问题分层从底层往上查Atlas 300V 部署 YOLO 的报错信息五花八门但总结下来无非这几类错误层次典型报错排查方向设备层No device found驱动、固件、设备节点权限运行时层ACL_ERROR_RT_PARAM_INVALIDCANN 版本、环境变量、context 未初始化模型转换层E10001: Unsupported opONNX 算子、ATC 参数、动态 shape推理输出层检测框偏移、无输出预处理格式、AIPP 配置、归一化参数性能层延迟高、GPU/CPU 占用异常内存复用、batch、异步流水线遇到问题是先判断在哪一层别一上来就怀疑硬件。我一般按这个顺序排查npu-smi info看卡是否正常。跑官方 sample 验证 CANN 环境。打印模型输入输出 shape检查数据排布和数值范围。把置信度阈值调很低看能否出候选框。用 profiling 工具查看算子耗时。9.2 经典问题转换时 SoC 版本填错这个坑很隐蔽因为报错信息不一定直接告诉你 SoC 填错了。我遇到过E10001: Invalid soc version.或者干脆是ascend_toolkit版本和驱动版本不兼容编译模型时报一堆莫名其妙的错误。查 SoC 版本的方法很简单npu-smi info输出里能看到具体的芯片型号对应到 ATC 的--soc_version参数。常见的有Ascend310P3、Ascend310P1等千万不能搞混。9.3 经典问题输出全为 NaN 或置信度极低这个问题的根源通常是预处理和模型训练时的预处理不一致。YOLOv5 训练时用的是img img / 255.0 # 归一化到 [0, 1]如果没有做归一化直接把 0-255 的整数像素喂给模型模型输出的置信度可能很低甚至全为 0。解决办法是在预处理阶段加归一化或者用 AIPP 配置时把std设置为 [255, 255, 255]。另外一个容易忽略的点是颜色通道顺序。YOLOv5 训练时用的是 RGB但 OpenCV 默认读出来是 BGR。如果模型按 RGB 训练你按 BGR 喂进去检测效果会明显变差。我确保通道顺序正确的方法是先用单张图测试把推理结果可视化出来如果物体颜色像是错乱的就换一下通道顺序试试。10. 写在最后聊点实际项目里的经验Atlas 300V 24G 的实际定位就是用于中大规模 AI 推理场景的专用卡尤其在视频分析、工业质检、智能安防这些需要同时处理十几路甚至几十路视频流的业务里性价比和功耗优势比较明显。它和 GPU 卡不是替代关系而是互补关系训练用 GPU/CANN 的 MindSpore 或 PyTorch推理部署到 Atlas 卡。拿它跑 YOLO 系列模型说简单也简单——只要环境配好、ONNX 导出干净、ACL 代码写对基本就能跑通说复杂也复杂——从模型转换、内存管理、batch 策略到异步流水线每一层都有不少可以优化的细节。我个人实际项目里最有价值的经验有三条第一条先固定输入尺寸再谈性能。动态分辨率在 Atlas 300V 上是性能杀手除非业务强需求否则固定 640x640 能省掉大量麻烦。第二条Batch 一定要用起来。24G 显存在单个 640x640 输入面前根本吃不饱如果你只做单张图片请求这卡的优势发挥不出来。真正要榨干它就往多路视频流、多 batch 并发方向走。第三条调试后处理时把阈值放得很低。这看起来是在“自找麻烦”但能在早期暴露出很多流程上的逻辑错误。等流程完全通了再把阈值调回正常水平。前面说的那些样例命令、优化参数放到你的具体环境里可能需要微调但整体思路不会有太大变化。希望这篇记录能让你少踩几个我踩过的坑。最后再提一句刚开始做的时候不要追求一次到位先用单张图片把链路跑通再慢慢加批量和并发每一步都确认正确了再往前走这样反而更快。
返回列表