
简介YOLOv5 6.1版本全中文注释工程包专为目标检测学习者和研究生设计尤其适合正在备战创新创业大赛或开展物体识别项目的人群源码中的关键函数、网络模块、训练参数均配有中文注释帮助彻底消除代码阅读障碍快速理解从数据加载到模型推理的完整流程。压缩包共2000个文件涵盖py源码、pyc预编译文件、yaml配置文件、pth模型权重、mat数据以及各类依赖库整体大小约296.99MB目录结构清晰可按模块快速定位。资源还配套CSDN专栏教程逐段讲解运行逻辑与实战细节遇到问题可对应博文排查。已有2785人浏览学习对初学者和进阶开发者都很友好。无论是课程设计、论文复现还是竞赛项目这套带注释的YOLOv5工程都能显著降低上手成本让使用者专注于模型调优与业务创新。1. 为什么是 YOLOV5 6.1 全中文注释包打开黑匣子的方式对了后面全是顺路事拿到 YOLOV5 6.1 版本的全中文注释压缩包很多人第一反应是解压、点开 README、跑一句 detect.py然后就没有然后了。源码包最容易卡住人的从来不是跑不起来而是不知道从哪个文件开始读更不知道注释里那些参数在训练时到底动了哪根神经。6.1 这个版本恰好是 YOLOv5 系列里一个承上启下的节点它没有 5.0 那么老也没有 7.0 之后那一堆接口变化代码结构干净中文注释配合官方结构图能把 backbone、neck、head 一条线读通。这套东西适合三类人刚入目标检测、被各种 demo 忽悠过想真正看懂模型的学生手头有自采数据、想用 yolov5 训练自己的数据集的工程新手以及想从「会跑」进阶到「敢改」的算法岗实习生。这篇笔记就按我自己的阅读和落地顺序来写先读哪几个文件、怎么建 conda yolov5 环境、怎么训练、在哪翻车、最后怎么把模型部署到树莓派 5 上验证一条线走完。2. 读注释代码的入口顺序yolo.py、common.py 与模型 yaml 的三角关系全中文注释包的价值不在注释本身而在于它把三份文件串成了一条可读的线索models/yolo.py 是调度中枢models/common.py 是零件库models/yolov5s.yaml 是图纸。我建议按「图纸 → 零件 → 调度」的顺序读但更快的办法是先读 yolo.py 里的 parse_model再回头看 common.py 里的组件。这套注释拿来当 yolov5 基础笔记非常合适每一段都对应网络结构图上的一个方块。2.1 models/yolo.pyDetectionModel 把 yaml 变成网络的调度逻辑yolo.py 里最核心的函数是 parse_model它接收 yolov5s.yaml 里 backbone 和 head 的定义把每一行[from, number, module, args]翻译成 PyTorch 层。中文注释通常会在两个地方标重点一是n max(round(n * gd), 1)这里 gd 是 depth_multiple 深度系数二是c2 make_divisible(c2 * gw, 8)gw 是 width_multiple 宽度系数。看懂这两行就理解了为什么 s/m/l/x 结构一样、参数数量差几倍。def parse_model(d, ch): anchors, nc, gd, gw d[anchors], d[nc], d[depth_multiple], d[width_multiple] layers, save [], [] ch [ch] # 当前层输出通道数从 3 开始 for i, (f, n, m, args) in enumerate(d[backbone] d[head]): m eval(m) if isinstance(m, str) else m # 深度系数n1 的模块主要是 C3重复次数被缩放 n max(round(n * gd), 1) if n 1 else n layers.append(m(*args)) # 宽度系数输出通道数被缩放并保证 8 的倍数 c2 make_divisible(c2 * gw, 8) ch.append(c2)逻辑说明这段代码遍历配置文件里的每一层先处理模块名字符串再决定这个模块重复几次深度最后决定输出通道数宽度。make_divisible取 8 的倍数是为了让 tensor 在 TensorRT、ONNX 这类推理引擎里有更好的内存对齐。注释里如果标了-1的含义那是在说「把上一层的输出作为这一层的输入」这是整个 yaml 的接线规则。参数说明gd0.33表示 C3 模块里的 Bottleneck 只保留三分之一至少 1 个gw0.50表示所有卷积通道数减半。这也是为什么 yolov5s 只有大约 7.2M 参数而 yolov5x 有 86.7M 的原因。2.2 models/common.pyC3、SPPF、Conv 这些基础组件的注释价值common.py 是所有基础模块的仓库注释包在这里通常标注得最细。6.1 版本里 backbone 开头已经不再用 Focus而是换成了Conv(64, 6, 2, 2)这种 6x6 步长 2 的卷积这是 6.0 之后的一个明显变化。组件里最值得精读的是四个Conv、Bottleneck、C3、SPPF。class C3(nn.Module): # C3 两个 1x1 卷积 n 个 Bottleneck 1 个 1x1 融合卷积 def __init__(self, c1, c2, n1, shortcutTrue, g1, e0.5): super().__init__() c_ int(c2 * e) # 隐藏层通道数 self.cv1 Conv(c1, c_, 1, 1) # 输入降维 self.cv2 Conv(c1, c_, 1, 1) # 旁路降维 self.cv3 Conv(2 * c_, c2, 1) # 拼接后融合 self.m nn.Sequential(*(Bottleneck(c_, c_, shortcut, g) for _ in range(n)))逻辑说明C3 的输入会走两条路一条经过 n 个 Bottleneck 做深层特征提取另一条只做一个 1x1 卷积做浅层特征保留最后 concat 再融合。这种结构比原来的 BottleneckCSP 少了一个卷积梯度回传更顺畅训练也更快。注释里如果画了箭头图通常就是在讲这条「主路 旁路」的并行结构。参数说明e0.5是隐藏层缩放系数shortcutTrue表示 Bottleneck 内部有残差连接。SPPF 则是把 SPP 的三个并行的 5/9/13 池化改成了串行的三个 5x5 最大池化效果一样但速度快很多这个细节在注释里很容易被忽略实际影响不小。2.3 对照 yolov5 网络结构图读 yamls/m/l/x 只差两个系数6.1 的模型配置文件在 models/ 目录下一共有四个yolov5s.yaml、yolov5m.yaml、yolov5l.yaml、yolov5x.yaml。打开对比就会发现它们的 backbone 和 head 部分完全一样唯一区别是文件顶部的 depth_multiple 和 width_multiple 两个数。对照网络结构图读 yaml推荐顺序是先看 anchors 三组先验框再看 backbone 的 10 层结构最后看 head 里 Detect 前面的层。模型depth_multiplewidth_multiple典型用途yolov5s0.330.50边缘设备、快速验证yolov5m0.670.75精度与速度折中yolov5l1.001.00追求 mAP 的常规选择yolov5x1.331.25学术刷分、大算力yaml 里的 anchors 是三组分别对应 P3/P4/P5 三个尺度的先验框anchors: - [10,13, 16,30, 33,23] # P3/8 小目标 - [30,61, 62,45, 59,119] # P4/16 中目标 - [116,90, 156,198, 373,326] # P5/32 大目标逻辑说明读 yaml 时注意每层配置里[from, number, module, args]的 from 可以有多个比如 Concat 层的 from 是[-1, 6]意思是把上一层和 backbone 第 6 层的输出拼在一起这就是 FPN PAN 结构在配置文件里的直接体现。读懂 from 就能在脑内把网络结构图画出来比死背结构图管用。参数说明nc是类别数默认 80 对应 COCO。训练自己的数据集时如果nc写错输出层的通道数就会算错最常见的就是类别数不匹配导致推理全空。3. conda yolov5 环境搭建与首次推理让中文注释包在本地先转起来环境这块我踩过不少坑尤其是用新版 Python 去装 6.1 的依赖经常在 pycocotools 或者 matplotlib 上翻车。这套注释包再全环境跑不起来等于零。我的建议是严格按照「先建 conda yolov5 环境、先装 torch、再装其余依赖」的顺序来能省掉一半排错时间。3.1 用 conda 建 yolov5 虚拟环境Python 与 PyTorch 版本别追新6.1 版本发布时官方支持的是 Python 3.7~3.10 这个区间我一般选 3.8兼容性最好。PyTorch 选 1.10 配 CUDA 11.3 是最省心的组合不是不能用 PyTorch 2.x而是 6.1 的代码在 2.6 之后会遇到 torch.load 的默认参数变化属于可以避免的麻烦。conda create -n yolov5 python3.8 -y conda activate yolov5 python -m pip install --upgrade pip setuptools wheel pip install torch1.10.0 torchvision0.11.0 --index-url https://download.pytorch.org/whl/cu113 python -c import torch; print(torch.__version__, torch.cuda.is_available())逻辑说明前两条命令创建并激活名为 yolov5 的 conda 环境第三条升级基础工具第四条用 PyTorch 官方源安装与 CUDA 11.3 匹配的 torch 和 torchvision。最后一条验证 CUDA 是否可用输出1.10.0 True才算通过。参数说明--index-url指定了下载源如果你本机 CUDA 版本不是 11.3需要换成对应版本号否则会出现 torch 装上了但torch.cuda.is_available()返回 False 的情况。没有 GPU 的机器可以把 cu113 换成 cpu 版本但训练大模型会非常吃力。3.2 安装 requirements.txt 的次序先把 torch 装上再一把梭requirements.txt 是 6.1 版本自带的依赖清单里面把 matplotlib、numpy、opencv-python、PyYAML、scipy、tqdm 等列得比较全还带版本下限。常见做法是直接pip install -r requirements.txt但如果你没先装 torchpip 解析依赖时会顺手把最新版 torch 拉下来新版 torch 会带来前面说的兼容问题这一步是我反复强调要先装 torch 的原因。cd /path/to/yolov5-6.1-zh pip install -r requirements.txt python -c from PIL import Image; import cv2; import yaml; print(deps ok)逻辑说明requirements.txt 里有一个容易被忽略的约束protobuf3.20.1这是为了避免 protobuf 新版和 onnx 的冲突。如果你后面要导出 ONNX 模型务必保留这个版本约束不要手动升级 protobuf。最后一条命令实际导入常用库能立刻暴露缺包或版本冲突。参数说明Windows 上如果 pycocotools 编译失败不用硬刚可以换成把 requirements.txt 里 pycocotools 那行注释掉再单独安装cython和pycocotools-windows。这个包只在计算 COCO 指标时需要训练本身用不到。3.3 第一次 detect.py 推理六个必调参数与它们的坑环境就绪后第一次跑推理建议用官方自带的图片先不要拿自己的图避免把「图片问题」和「环境问题」混在一起。6.1 的 detect.py 参数不多但有几个必须理解清楚否则换图就会出幺蛾子。python detect.py \ --weights yolov5s.pt \ --source data/images/bus.jpg \ --conf-thres 0.4 \ --iou-thres 0.45 \ --imgsz 640 \ --device 0 \ --save-txt逻辑说明--weights指定权重文件如果没有会在首次运行时联网下载但经常因为网络原因卡住我一般提前下好放进目录。--source是输入图片或视频路径--save-txt会额外输出检测结果的 txt 文件格式是类别 x_center y_center width height。跑完在runs/detect/exp目录下能看到标注好的图片。参数说明--conf-thres是置信度阈值调低会放出更多低置信度框调高会过滤更严--iou-thres是 NMS 的 IoU 阈值目标重叠多时调高到 0.5 左右--imgsz是输入分辨率6.1 默认 640显存不够时降到 416 或 320 能救急但小目标会明显变差--device 0指定第一张显卡CPU 机器改成--device cpu。4. yolov5 训练自己的数据集用安全帽数据集串起完整流水线跑通推理只是热身真正让这套中文注释包产生价值的是训练自己的数据集。这里用 yolov5 安全帽数据集举例因为它是公开数据里很适合练手的场景类别少、目标尺度差异大、背景有工业现场噪声。整个流程分三块数据整理、配置文件、训练命令与超参数。每一块都有特别容易踩的坑下面按顺序走。4.1 整理 YOLO 格式数据图片、txt 标签、划分三个目录yolov5 训练要求的数据格式是每张图片对应一个同名 txt 文件txt 每一行是类别id x_center y_center width height四个坐标都是归一化到 0~1 的小数。目录结构必须是 images 和 labels 分开放并且 train 和 val 两套都要有。很多初学者把标签和图片放同一个目录训练器会直接找不到标签。helmet/ images/ train/*.jpg val/*.jpg labels/ train/*.txt val/*.txt如果手上是 VOC 格式的 xml 标注需要先转换。下面这段脚本扫描 xml 并写出 yolov5 格式的 txtimport os, xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_dir, class_map): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w, h int(size.find(width).text), int(size.find(height).text) lines [] for obj in root.iter(object): cls obj.find(name).text if cls not in class_map: continue box obj.find(bndbox) x1, y1 float(box.find(xmin).text), float(box.find(ymin).text) x2, y2 float(box.find(xmax).text), float(box.find(ymax).text) cx, cy (x1 x2) / 2 / w, (y1 y2) / 2 / h bw, bh (x2 - x1) / w, (y2 - y1) / h lines.append(f{class_map[cls]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) out_path os.path.join(out_dir, os.path.splitext(os.path.basename(xml_path))[0] .txt) with open(out_path, w) as f: f.write(\n.join(lines))逻辑说明转换的核心是坐标归一化x_center是 xmin 和 xmax 的平均值除以图片宽框宽是 xmax-xmin 再除以宽高度同理。这段脚本把每行按class cx cy w h写出类别 id 由 class_map 字典决定必须是 0 开始的整数。参数说明转换后一定要抽查几个 txt 文件确认没有x_center为负或大于 1、w为 0 的脏数据这些在 yolov5 里会被直接当成无效标签跳过不会报错但会悄悄降低训练效果。4.2 写数据配置 yamltrain 路径、nc、names 三处最容易错训练前要写一个数据配置文件告诉 train.py 数据集在哪、类别有几个、类别叫什么。这个文件写错是新手最大的坑源尤其是路径yolov5 会把 yaml 里的路径和当前工作目录拼接写相对路径经常找不到数据。# helmet.yaml train: /data/helmet/images/train val: /data/helmet/images/val nc: 2 names: [head, helmet]逻辑说明train 和 val 路径指向的是 images 目录而不是 labels 目录yolov5 会根据同名规则自动去相邻的 labels 目录找标注。nc是类别数安全帽数据集我这里是两类没戴安全帽的头head和戴了安全帽的helmet。names顺序必须和标注时的 class id 完全一致id 0 对应headid 1 对应helmet。参数说明路径建议用绝对路径或者把数据集放进 yolov5 工程目录下再用相对路径。Windows 上路径里的反斜杠和盘符冒号经常出问题换成正斜杠最保险。写完 yaml 后可以跑一句快速检查import yaml, os cfg yaml.safe_load(open(helmet.yaml)) for k in [train, val]: p cfg[k] print(k, 文件数:, len(os.listdir(p)), 路径存在:, os.path.exists(p))4.3 train.py 训练命令与 yolov5 超参数hyp 文件先调这四个训练命令本身不复杂复杂的是超参数。6.1 版本把超参数放在 data/hyps/ 目录下常见的有 hyp.scratch-low.yaml小模型用和 hyp.scratch-high.yaml大模型用。很多人一上来就把几十个超参数全调一遍这其实是玄学真正值得先动的是下面这四个。python train.py \ --data helmet.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --device 0 \ --hyp hyp.scratch-low.yaml \ --name helmet_run逻辑说明--weights yolov5s.pt表示在 COCO 预训练权重基础上微调收敛速度远快于从零训练。--hyp指定超参数文件不指定时默认用 hyp.scratch-low.yaml。--name是实验名训练日志和权重会输出到runs/train/helmet_run/方便多次实验对比。训练中途断了想续跑加--resume runs/train/helmet_run即可断点续训就是后悔药不用每次都从头来。超参数默认值作用与调整建议lr00.01初始学习率安全帽这种小数据集先降到 0.005 更稳mosaic1.0概率性拼接增强小目标多时保持 1.0目标稀疏时可降到 0.5hsv_s0.7饱和度增强幅度工业现场光照不稳定时可以加大到 0.9fl_gamma0.0focal loss 的 gamma正负样本极不均衡时调到 1.5 试hyp 文件里对应的一段长这样lr0: 0.01 # 初始学习率 lrf: 0.01 # 最终学习率 lr0 * lrf box: 0.05 # 边框损失权重 cls: 0.5 # 类别损失权重 mosaic: 1.0 # mosaic 增强概率 fl_gamma: 0.0 # focal loss gamma参数说明我一般调超参数的顺序是先确定 lr0小数据集降、大数据集保持再调 mosaic看目标密集程度然后动 hsv 增强看场景光照鲁棒性最后才碰 fl_gamma。一次只改一两个用 TensorBoard 看曲线对比比一次改十个然后祈祷有用靠谱得多。5. 6.1 版本踩坑记录五个高频翻车场景与排查手法这部分是我实际跑 6.1 过程中积累的血泪经验每一条都是先看到现象再追原因最后给解决手法。把这些坑排掉训练流程基本就能顺畅走完。5.1 新装 PyTorch 后 torch.load 报 weights_only 报错现象用 PyTorch 2.6 以上版本加载 yolov5s.pt 或训练好的 best.pt直接抛异常报错信息里出现weights_only字样加载中断。原因PyTorch 从 2.6 开始把torch.load的weights_only默认值改成了 True只允许加载纯张量而 yolov5 的权重文件里还带着模型结构、超参数、训练配置等额外对象于是被安全检查拦下。解决在代码里给 torch.load 调用显式传weights_onlyFalse。6.1 工程里需要改两处一处是 utils/general.py 的 attempt_load另一处是导出或验证脚本里直接调 torch.load 的地方。# utils/general.py 中找到 torch.load 处改为 ckpt torch.load(file, map_locationcpu, weights_onlyFalse)逻辑说明这个改动本质是告诉 PyTorch「我知道这个文件可能包含代码对象我信任它」。只对你自己训练或从官方渠道拿到的权重这么做别加载来路不明的 .pt 文件。参数说明如果是用 6.1 的 export.py 导出 ONNX 时遇到同样报错同样在 exporters.py 里给 torch.load 加上weights_onlyFalse因为导出流程也要先加载权重。5.2 训练全程 mAP 为 0先怀疑标签别怀疑网络现象训练过程没有任何报错loss 也在下降但每个 epoch 结束打印的 mAP0.5 始终是 0验证集的图片上检测不到任何目标。原因十有八九是标签没被正确读进来。常见的情况是 labels 目录和 images 目录不在同一级、图片文件名和 txt 文件名对不上、或者 txt 里的类别 id 超过了nc-1。解决训练前先跑一个标签自检脚本我一般会先看两个目录的文件数echo 图片数: $(find images/train -name *.jpg | wc -l) echo 标签数: $(find labels/train -name *.txt | wc -l)import os from collections import Counter label_dir /data/helmet/labels/train empty 0 total 0 class_ids Counter() for name in os.listdir(label_dir): if not name.endswith(.txt): continue with open(os.path.join(label_dir, name)) as f: lines [line.strip() for line in f if line.strip()] if not lines: empty 1 for line in lines: total 1 class_ids[int(line.split()[0])] 1 print(空标签文件:, empty) print(标签总条数:, total) print(类别分布:, dict(class_ids))逻辑说明图片数和标签数不一致说明有图片没标注或有孤儿 txt。类别分布里的 id 如果出现不小于nc的值说明标注脚本里 class_map 写错了。空标签文件多了说明标注环节有遗漏YOLOv5 对空标签文件不会报错但那张图就白算了。参数说明检查完后用--epochs 1 --batch-size 8跑一个 epoch 的冒烟测试看训练日志里有没有出现All labels empty或WARNING: no labels found之类的提示比直接训练 100 个 epoch 再后悔快得多。5.3 跑 plot 时 Arial.ttf 找不到离线和权限两个解法现象训练进行到某一个 epoch 结束、准备画训练曲线时报错找不到Arial.ttf整个训练中断像是字体文件缺失。原因yolov5 的 utils/plots.py 在画图时要加载 Arial.ttf它会优先去本地 fonts 目录找找不到就尝试从网上下载。离线环境或者没有写权限的目录下就会卡死。解决两个解法任选。一是提前把 Arial.ttf 放进 utils/fonts/ 目录注意文件名和代码里写的一致二是给代码加一个环境变量指定字体路径。# 解法一确认字体文件在正确位置 ls -la /path/to/yolov5-6.1-zh/utils/fonts/Arial.ttf # 解法二Linux 下用系统字体兜底 cp /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf /path/to/yolov5-6.1-zh/utils/fonts/Arial.ttf逻辑说明这个问题不影响模型权重只影响可视化输出但训练脚本里画图是默认开启的所以会直接中断训练。把字体文件补齐后重新--resume就能继续。参数说明如果是 Windows系统字体在C:\Windows\Fonts\arial.ttf复制过去即可。如果只想跳过画图也可以改 plots.py 里字体加载那段代码但代价是训练过程看不到 loss 曲线不推荐。5.4 别人的 pt 权重加载成功但推理结果全空类别数不匹配现象从别人那里拿到一个训练好的 pt 文件detect.py 不报错能正常加载但不管输入什么图都检测不出任何目标或者检测结果类别名全是乱的。原因pt 文件里自带了训练时的类别信息加载时 yolov5 会读取权重的model.names。如果别人的模型是在 10 类数据集上训练的而你的 detect.py 环境默认按 80 类解析或者你用它来做 2 类的安全帽推理输出层解析就会错位。解决加载后先检查权重的类别信息再决定要不要用import torch ckpt torch.load(someone.pt, map_locationcpu, weights_onlyFalse) model ckpt[model].float().eval() print(类别数:, model.names if hasattr(model, names) else unknown)逻辑说明这个代码读取权重文件里的模型对象并打印它携带的类别信息。如果打印出的名字和你的任务完全不一致说明这个权重不适合直接拿来推理要么重新训练要么至少确认两侧的类别顺序完全一致。参数说明类别顺序不一致是大坑。安全帽数据集里names: [head, helmet]和names: [helmet, head]虽然类别数一样但同一个 id 指的东西完全不同推理出来的结果会张冠李戴。修改测试脚本时我会同时打印nc和names两个字段避免只比对类别数就以为万事大吉。5.5 导出 ONNX 后 detect.py 能跑但精度崩opset 与动态轴现象export.py导出 ONNX 成功detect.py 用.onnx权重也能推理但同一张图onnx 的检测框明显比 pt 的差甚至出现大量漏检。原因最常见的是导出时没有指定 opset 版本和动态轴。yolov5 6.1 里很多算子依赖较高版本的 opset默认值有时不够用另外输入尺寸固定为 640 时没问题一旦换分辨率模型就崩。解决导出时明确指定 opset 和动态输入输出python export.py --weights best.pt --include onnx --opset 12 --dynamic逻辑说明--opset 12覆盖了 6.1 需要的算子上限--dynamic让 ONNX 的输入输出维度变成动态的这样部署时不用限制在固定的 640x640。导出成功后会打印 ONNX 的输入输出节点名和形状这是判断导出是否正确的重要依据。参数说明导出后先用同一张图做 pt 与 onnx 的对比检测我一般保存两次的结果图用脚本比对框数量。如果 onnx 结果仍偏差大检查输入预处理是否一致——onnx 走的是 RGB 归一化到 0~1很多手写推理代码会漏掉img[:, :, ::-1]通道翻转这是精度崩的另一大来源。6. 部署闭环把 best.pt 导出 ONNX 并在树莓派 5 上验证推理训练收尾后模型要落地最现实的一条路是导出 ONNX然后在树莓派 5 上用 onnxruntime 跑推理。树莓派 5 的算力跑 YOLOv5s 大约能到 5~10 FPS做原型验证完全够用这也是 yolov5 部署里性价比最高的验证闭环。先把 best.pt 导出 ONNXpython export.py --weights best.pt --include onnx --opset 12 --simplify--simplify会用 onnx-simplifier 做图优化把一些冗余算子合并掉树莓派这种弱算力设备上能省一点是一点。导出的 best.onnx 拷贝到树莓派后用下面这段最小的推理脚本验证import onnxruntime as ort import numpy as np import cv2 session ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name session.get_inputs()[0].name img cv2.imread(test.jpg) img cv2.resize(img, (640, 640)) x img[:, :, ::-1].transpose(2, 0, 1)[None].astype(np.float32) / 255.0 out session.run(None, {input_name: x})[0] print(输出形状:, out.shape)逻辑说明输出形状如果是(1, 25200, 7)其中 25200 3 个尺度 $\times$ (80x80 40x40 20x20) 个网格7 2 类 4 个框坐标 1 个置信度。这个 shape 是判断 onnx 是否带动态轴、类别数是否正确的最直观指标。树莓派 5 上跑一次推理大约 100~200 毫秒如果慢得离谱先查 onnxruntime 是否装成了 x86 版本再确认用的是 ARM 的 aarch64 wheel。验证结果和 pt 推理对比时我习惯把两边的检测框数量和置信度打出来比对框数差异超过 10% 就回查预处理或导出参数。再说个我自己的习惯模型训练完第一件事不是看 mAP而是拿几张训练时最容易漏检的难例图分别用 pt 和 onnx 跑一遍确认部署端效果没有缩水再谈上板。这条流程走顺之后YOLOv5 6.1 从读注释、训练自己的数据集到树莓派 5 上部署整个链路就通了。希望帮到你。本文还有配套的精品资源点击获取