简介YOLOv5 6.1版本全中文注释代码包专为深度学习初学者、研究生及目标检测项目开发者打造有效解决原生代码注释不足、难以理解内部实现的问题。压缩包内共2000个文件涉及Python源码、C/C扩展、文本说明、YAML模型配置、预训练权重及脚本工具等多种类型总大小约296.99MB目录划分清晰便于按模块查阅。资源特别配套CSDN博客专栏教程对数据增强、骨干网络、损失计算、推理后处理等核心部分进行逐段中文注解同时给出详细的代码逻辑分析和运行演示可帮助读者摆脱“只跑通、看不懂”的困境。无论是课程设计、毕业课题还是创新创业大赛中的物体识别需求都能借助完整注释与教程快速落地。目前已有2785人学习下载值得目标检测入门与进阶者收藏。1. 为什么我建议你直接啃YOLOV5 6.1的中文注释源码一天从跑通到改得动第一次打开 YOLOV5 工程的人十个有八个会卡在同一个地方代码能跑但看不懂。尤其对研究生和准备参加创新创业大赛的团队来说时间是最贵的你不可能花两周去一行行查函数定义。这份 YOLOV5 6.1 版本全中文注释压缩包把 detect.py、train.py、models、utils 等核心文件的注释都换成了人话配合配套教程能让你一天内理清整个调用链。它解决的不是“怎么把模型跑起来”而是“跑起来之后你能不能改得动”。适合目标检测入门者、需要快速出成果的比赛队伍以及所有被源码劝退的开发者。我在给课题组分代码时最常听到的抱怨就是“网上教程都是英文注释看一行查一次词典”所以这个包一出来组里几个人直接原地复制。2. 先看懂 YOLOV5 6.1 的工程结构注释里最容易迷路的三个目录拿到压缩包后第一件事不是急着训练而是建立“地图”。YOLOV5 6.1 的官方仓库本身不算大但文件很杂。models、utils、data、runs 各自承担不同任务注释包虽然把关键文件都翻译成了中文但结构还是要自己理明白。2.1 从入口到模型detect.py、train.py、models/yolo.py 的调用链先说三个最核心的文件。detect.py 和 train.py 是两个并列入口对应推理和训练models/yolo.py 定义了网络主结构。把它们的关系理清整个项目就能横着走了。# 解压中文注释包注意用支持UTF-8的解压工具避免Windows下中文乱码 unzip yolov5-6.1-zh.zip -d yolov5-zh cd yolov5-zh pip install -r requirements.txt # 先跑自带的检测demo验证环境 python detect.py --weights yolov5s.pt --source data/images/bus.jpg这段命令解决“环境通不通”的问题。unzip 解压后requirements.txt 里包含了 torch、opencv-python 等核心依赖。detect.py 是推理入口内部会调用 models.yolo 的 DetectionModel 类最终把检测框画到输出图片上。注意第一次运行 detect.py 时如果本地没有 yolov5s.pt程序会尝试从 GitHub 下载。这一步在有些网络环境下会卡很久我建议你提前把权重文件放到工程根目录具体放在第 4 章的坑里细说。接下来看训练入口。train.py 的代码量比 detect.py 大得多但核心训练循环很短。注释包里在 train.py 里有一段醒目的中文说明告诉你“这是每次迭代都会执行的四步”。类似这样# 前向传播把一批图片喂给模型得到预测特征 pred model(images) # 计算损失pred与targets比较得到loss和各项子损失 loss, loss_items compute_loss(pred, targets.to(device)) # 反向传播把梯度回传这一步决定网络如何更新 scaler.scale(loss).backward() # 更新权重优化器根据梯度调整参数 optimizer.step()这段代码是训练循环的灵魂。pred 是模型输出在 6.1 版本里是一个包含三层特征图的 tupletargets 是标注数据格式为[image_index, class, x_center, y_center, width, height]。compute_loss 由 utils/loss.py 提供内部完成了 anchor 匹配和 GIoU 损失计算。中文注释在 loss 这一块写得非常密因为很多想改检测头或想自定义 loss 的人都要从这里入手。注意 6.1 版本的 loss 代码相比 5.0 做过重构不要拿着旧版本的教程硬套。再回到 detect.py。它的核心其实也短加载模型 - 读取图片 - 预处理 - 推理 - NMS - 画框。其中预处理步骤里有个 letterbox 函数会把图片等比缩放到 640 并补灰边这一步很多人看不懂。注释包里在 utils/augmentations.py 里用中文标明了“缩放到 640x640保持比例不变用 114 灰度填充边缘”并解释了为什么要这样因为网络全卷积层对尺寸不敏感直接 resize 会破坏物体比例。调用链捋一遍detect.py 和 train.py 都从 models/yolo.py 中实例化 DetectionModel各自在 utils 目录中取所需工具。所以除非你想改网络结构否则每天打交道最多的其实是 utils 里的工具文件。另外runs 目录也值得提前搞懂。每次运行 detect.py 或 train.py 后结果都会输出在 runs/ 下面。6.1 版本默认输出到 runs/detect/exp、runs/detect/exp2 等。中文注释包里在 utils/general.py 的 increment_path 函数处做了注释解释了为什么名字会递增而不是覆盖。很多新手找不到输出图片就是因为不知道它在 runs/detect/exp 里。2.2 utils/ 目录里那些“工具函数”其实决定了训练能不能跑很多人忽略 utils 目录以为只是辅助。实际上训练能不能跑、loss 能不能降很大程度取决于这一段。utils/datasets.py 负责加载图片与标签里面的 LoadImagesAndLabels 类在每次取数据时都会执行 mosaic 增强、随机仿射变换等操作。如果你的数据集标签格式不对很多报错恰恰发生在 datasets.py 内部而不是你的训练代码里。# 在中文注释包里用grep快速定位关键函数位置 grep -n def train train.py grep -n class DetectionModel models/yolo.py # 查看mosaic增强相关注释 grep -n mosaic utils/datasets.pygrep -n 会把行号一并输出。配合配套教程的章节名你可以快速跳转到注释对应位置。中文注释包在每段重要代码前都写了类似“这里做 mosaic 增强把四张图随机拼成一张提高小目标检测能力”的说明。对比原版英文注释这种解释对新手理解“为什么写这段代码”帮助极大。utils/general.py 里面的 check_img_size、check_file、check_dataset 是三个“检查狂魔”。很多让人摸不着头脑的报错比如“Dataset not found”或“Image not found”都是它们主动抛出来的。注释包里对这些函数标注了“这个检查是为了避免路径错误导致训练到一半崩溃”。遇到错误时先看抛错的位置是不是这三个函数再按提示改路径比自己瞎猜高效得多。还有一个容易踩坑的目录是 utils/torch_utils.py。它管理设备选择、模型并行、梯度累加等。6.1 版本在这里增加了一些自动混合精度训练的辅助函数。中文注释包特别标出了“当 batch_size 较小且检测目标较小时不建议开启 AMP 训练”原因是半精度在小目标场景下有时会丢精度。这个细节很少有人强调但对比赛调模型很有用。2.3 配套教程怎么用先跑通 demo 再逐行读配套教程是博客形式我建议按“先环境后单张图片再训练”的顺序来。拿到代码包后不要直接开读源码先运行 detect.py 看到结果再反向去读代码。有了输出结果你对变量的含义会有具体的感知。# 在Python里直接查看模型结构确认网络配置是否加载正确 import torch from models.yolo import Model model Model(cfgmodels/yolov5s.yaml, ch3, nc80) print(model)这段代码的逻辑Model 类接收配置文件 cfg、输入通道数 ch 和类别数 nc。cfg 决定网络的深度和宽度ch 是输入图像的通道RGB 就是 3nc 是数据集类别数。打印出来的网络结构很长你会看到从 Conv 到 C3 再到 Detect 的完整流程。中文注释在 Detect 模块附近有大量说明告诉你这个模块如何把三张特征图变成预测框。如果你换了自己的数据集nc 必须改成你的实际类别数否则最后一层维度不匹配训练直接报错。配套教程里还有网络结构图。6.1 版本相比 5.0 的最大改动之一是用 C3 模块替换了 BottleneckCSP参数量更小。你会在 models/yolo.py 的 C3 类旁边看到中文注释说明它由几个 Conv 和 Bottleneck 串联而成。建议把结构图打印出来对着注释一行行看比单独看代码更容易建立整体印象。3. 把 YOLOV5 6.1 改成自己的数据集从标注到训练的超参数设置工程结构搞清楚之后接下来就是把自带的 COCO 模型换成你的数据集。无论是研究生课题还是比赛这一步都会反复用到。在这章你会看到三个核心操作整理数据、改配置、设置超参数。3.1 数据标注与目录组织YOLO 格式到底长什么样目标检测数据集的格式很多VOC、COCO、YOLO 各有各的存储方式。YOLOV5 用的是 YOLO 格式一个图片对应一个 txt 文件txt 里每行表示一个目标五个数字分别是 class_id x_center y_center width height注意这四个坐标都是归一化到 0-1 的。第一次用的人最容易在“中心点坐标”和“左上角坐标”上翻车。# 对应图片 bus.jpg 的标签文件 bus.txt 0 0.45 0.35 0.20 0.42 1 0.62 0.68 0.31 0.12 # class_id从0开始x_center/y_center/width/height均为归一化值这段文本的逻辑如果你用 LabelImg 这类工具标注导出为 YOLO 格式时会自动生成这样的 txt。如果是从 COCO 的 json 转换需要自己写脚本把归一化坐标算出来。常见误区有人把坐标写成了像素值或者把宽高写成了右下角的坐标训练时会报 invalid box 或 loss 变成 nan。目录组织也有讲究。YOLOV5 官方推荐的数据集目录结构是datasets/ your_dataset/ images/ train/ val/ labels/ train/ val/这个结构的核心是images 和 labels 是两个并列的父目录下面再按 train/val 划分。图片和标签文件必须同名后缀不同。训练时YOLOV5 会根据图片路径自动找到同名标签所以标签文件名千万不能改错。我习惯在数据准备阶段写一个检查脚本确认每一张训练图片都有对应 txt反过来也一样。如果从 VOC 格式转换可以按下面这个 Python 脚本操作。这也是我在比赛里经常改的模板# 把VOC的xml标注转成YOLO的txt标注 import xml.etree.ElementTree as ET def voc_to_yolo(xml_file, class_names, out_txt): tree ET.parse(xml_file) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2 / w y_center (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h class_id class_names.index(name) lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) with open(out_txt, w) as f: f.write(\n.join(lines))脚本逻辑用 ElementTree 解析 VOC 的 xml读取图片宽高把每个目标的左上角/右下角坐标换算成归一化的中心点和宽高。class_names 是类别列表比如[person,car]。注意如果 xml 里没有 size 或者某个目标缺失 bndbox脚本会报错所以转换前最好先清洗一遍数据。提示转换脚本只负责格式不负责检查坐标越界。转换后一定要用后面的 awk 命令筛选一遍把越界标签扼杀在训练之前。3.2 修改数据集配置YAML 里的每个字段都别乱动YOLOV5 通过一个 yaml 文件来告诉训练脚本你的数据在哪、有几类。这个文件虽然简单但字段一旦写错程序会以各种奇怪的方式报错。来看一个典型配置# data/custom.yaml path: ../datasets/your_dataset/ # 数据集根目录 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 nc: 2 # 类别数量 names: [person, car] # 类别名称与标注里的class_id一一对应字段说明path 指定数据集根目录train 和 val 是相对 path 的路径。这里最容易踩的坑是 path 用绝对路径换一台机器就崩。我一般使用相对路径并把数据集放在和 yolov5 工程同级的 datasets 目录下。另一个坑是 nc 和 names 长度对不上比如 nc 写了 2 但 names 给了 3 个训练时会报 assert 错误。中文注释包在 data/ 目录下附带的 custom.yaml 模板里对这些字段每一行都有中文解释。修改完 yaml 后建议先跑一个 1 个 epoch 的命令做自检python train.py --data data/custom.yaml --weights yolov5s.pt --epochs 1 --img 640这里的--epochs 1是为了快速验证数据和配置。如果前面有路径错误、标签错误通常还没跑完第一个训练步就会报错。验证通过后再把 epochs 改回实际值。我见过很多人在第一次训练时就设 100 个 epoch结果第 2 分钟报错又得重来浪费大量时间。为了在训练前发现标签错误我还会用两条 shell 命令做体检# 检查数据集里有没有0字节的空标签 find . -name *.txt -size 0 | wc -l # 统计所有标签里的class_id确认没有超过nc-1的值 awk {print $1} labels/train/*.txt | sort -u第一条命令统计空标签数量空标签会导致部分图片被忽略第二条命令打印所有标签里出现的 class_id 值。如果最大值大于等于 nc说明标注的类别编号超出了配置范围训练时会出现越界错误。这两条命令不花时间却能拦住大部分低级问题。3.3 训练超参数与模型选择s/m/l/x 怎么选YOLOV5 6.1 一共有 n/s/m/l/x 五个尺寸的模型配置区别是网络的深度和宽度。n 最轻量x 精度最高但最吃显存。怎么选不是拍脑袋而是看设备和你对速度的要求。如果是笔记本的 RTX 3060我一般选 s 或 m如果是 16G 显存的卡训练自己的数据可以从 m 开始试如果比赛对速度有硬性要求就选小模型。训练命令示例python train.py --data data/custom.yaml --weights yolov5s.pt --epochs 100 --batch-size 8 --img 640 --device 0参数说明--weights有两种用法。给yolov5s.pt是预训练权重属于迁移学习收敛快给yolov5s.yaml是随机初始化从头训。新手建议用预训练权重因为样本量通常不够从零训练。--batch-size要按显存调节不足时先降到 4 或 2而不是换更大的模型。--img是训练时输入的图片尺寸默认 640如果你的目标很小可以提高到 960但训练时间和显存占用都会上涨。超参数文件 data/hyp.scratch-low.yaml 里包含学习率、动量、损失系数等参数。6.1 版本默认的 low 配置对多数任务够用我不建议一上来就改。真要调重点关注 lr0 和 anchor_t。lr0 太大 loss 容易震荡太小收敛极慢。anchor_t 是 anchor 匹配阈值小目标数据集可以考虑稍微调大。中文注释包在 hyp 目录里逐行写了中文解释这在其他版本里是很少见的。最后训练命令里加上--project和--name让每次实验输出到独立目录。这样后面对比模型非常方便python train.py --data data/custom.yaml --weights yolov5s.pt --epochs 100 --batch-size 8 --img 640 --project runs/train --name my_experiment_001这样 runs/train/my_experiment_001/ 下会保存权重、日志和曲线。如果没有这个习惯默认会生成 runs/train/exp第二次就是 exp2时间一长谁也不知道哪个是哪个。这个习惯帮我省了无数找模型的精力。4. 避坑YOLOV5 6.1 跑通的五条血泪经验这一章把我在科研和比赛中踩过的坑集中列出来。每一条都是“现象-原因-解决”结构建议遇到问题时直接查对应的条目。4.1 权重文件下载失败导致程序“卡死”现象是执行 python detect.py --weights yolov5s.pt 时终端长时间没反应最后报连接超时。原因是本地没有权重文件时YOLOV5 会自动从 GitHub 下载在部分网络环境下这个过程极慢看起来就像程序卡住了。解决方法是提前手动下载权重文件放在工程根目录并用下面的命令验证权重完整性python -c import torch; m torch.load(yolov5s.pt, map_locationcpu); print(m.keys())能打印出模型的关键字典就说明文件没问题。我还建议把 detect.py 里自动下载那段代码注释掉免得在演示或比赛现场突然弹出一个下载提示。注意6.1 版本权重与 5.0 不通用不要拿旧权重混用。4.2 中文路径报错现象是图片放在 D:\数据集\训练图片\1.jpg运行 detect.py 时图片加载不出来训练时报错找不到文件。原因是 OpenCV 在 Windows 下对中文路径支持不好路径里的中文经过编码后无法正确找到文件。这不是代码逻辑问题属于环境问题很玄学。解决方法是把所有路径改成英文。数据集、工程、权重文件都不要出现中文。如果你的标签名称需要中文可以放在模型后处理的映射字典里但文件路径必须 ASCII 编码。我有一个课题组成员的样本图片放在“桌面\毕业设计\实验数据”为此折腾了一个下午改成 D:\data\project_data 后一切正常。4.3 显存不够但换小模型治标不治本现象是训练时报 CUDA out of memory于是从 yolov5x 换成 yolov5s结果还是 OOM。原因是显存占用不只是模型大小决定的。batch size 和图片尺寸同样关键甚至影响更大。模型变小了但 batch size 还是默认的 16图片还是 640照样爆显存。解决方法是优先把 batch-size 降到 2 或 4同时把 img 降到 512 或 416。这样通常能在不损失太多精度的情况下跑起原本想用的模型。我的经验是batch size 减半显存占用几乎减半训练时间变长但可控。如果仍然不足再考虑使用梯度累加技巧在 train.py 里把单 batch 的梯度累积起来模拟更大的 batch。注意观察显存用 nvidia-smi 的 Memory-Usage 列而不是只看系统全局内存。4.4 图片尺寸与 anchors 不匹配训练震荡的隐形原因现象是训练时 loss 在某个 epoch 突然从 0.05 跳到 0.8然后又降回去反复多次。很多人以为学习率太大结果调小后依然如此。原因是 YOLOV5 6.1 的默认 anchors 是基于 COCO 数据集的 640 尺寸设置的。如果你的数据集中目标很小或者图片分辨率很特殊默认 anchors 与真实目标尺寸差距过大导致前期的 loss 巨幅波动。解决方法是让 YOLOV5 在训练前自动计算 anchors它会根据你的标签聚类出合适的 anchors。在训练日志里你会看到anchors: 3.5,6.2,...这样的输出。如果看到 “anchors not suitable” 的警告可以在 train.py 里调整 autoanchor 的匹配阈值或者直接去掉--noautoanchor参数。中文注释包在 utils/autoanchor.py 里把这些逻辑都注释清楚了这也是我推荐仔细看的文件之一。4.5 标签格式“看起来对”但训练 loss 为 nan现象是数据集来自网上下载标签 txt 内容类似“0 0.5 0.5 100 200”训练一开始 loss 就是 nan。原因是坐标必须是归一化到 0-1 之间的浮点数宽高不能大于 1。上面的例子显然把宽高写成了像素值导致计算损失时出现除零或无穷大。解决方法是检查标签文件把宽高分别除以图片宽高。另外检查是否出现负数或极端值可以用 awk 命令筛出所有大于 1 的坐标awk {for(i2;iNF;i) if($i1 || $i0) print $0} labels/train/*.txt | head这条命令会把含有越界坐标的标签行打印出来方便定位。这个问题在中文论坛里被问过无数次属于最常见的翻车原因。5. 从模型到落地用 Python 调用 YOLOV5 做批量推理的具体技巧训练完模型不算完比赛 Demo 和实际项目都需要把模型集成到自己的流程里。直接从命令行调 detect.py 看起来简单但每张图片都启动一次 Python 进程速度慢且没法处理动态数据。所以我把常用的封装方法整理成三个小节都是可以直接抄走的代码。5.1 把 detect.py 的 main 逻辑抽成函数省掉重复传参detect.py 本身是一个命令行工具但项目里要反复调用检测的时候每次传一堆参数很烦。常见做法是把 detect.py 的 run 函数改造成一个可调用的函数。我这里写了一个精简版import torch from models.experimental import attempt_load from utils.general import check_img_size, non_max_suppression from utils.torch_utils import select_device def load_model(weightsyolov5s.pt, device0, imgsz640): device select_device(device) model attempt_load(weights, map_locationdevice) model.stride int(model.stride.max()) imgsz check_img_size(imgsz, smodel.stride) return model, device, imgsz def infer_image(model, img, device, imgsz, conf_thres0.5, iou_thres0.45): # img: BGR numpy array img torch.from_numpy(img).to(device) img img.float() / 255.0 # 0-255归一化到0-1 if len(img.shape) 3: img img[None] # 增加batch维 with torch.no_grad(): pred model(img, augmentFalse)[0] det non_max_suppression(pred, conf_thres, iou_thres)[0] return det.cpu().numpy()代码逻辑load_model 负责加载权重并确定设备与输入尺寸。infer_image 接收一张 BGR 图片先转成 Tensor 并归一化然后前向传播最后做 NMS。返回结果是 N*6 的 numpy 数组每行是[x1, y1, x2, y2, conf, class]。注意这里输入的 img 是原始尺寸但模型要求输入尺寸是 stride 的倍数所以我一般在外部会先对图片做 letterbox 处理。如果没有处理小尺寸图片可能报错。我还会在 infer_image 里补一个 letterbox 调用让函数内部处理缩放和坐标映射。具体实现可以复用 utils/augmentations.py 里的原版函数这里不展开。参数说明conf_thres 默认 0.5实际项目根据你对误检的容忍度调整比赛里我一般设为 0.4iou_thres 控制 NMS 的阈值0.45 是经验值。5.2 用 torch.hub 加载本地权重不在命令行里绕圈YOLOV5 官方支持 torch.hub 加载但很多人不知道可以完全离线加载。当你已经把工程和权重文件下载好时用 sourcelocal 方式加载最省事。import torch model torch.hub.load( local_path./yolov5-6.1-zh, sourcelocal, modelcustom, pathweights/best.pt, force_reloadTrue ) results model(./test.jpg) print(results.pandas().xyxy[0])代码逻辑local_path 指向中文注释包的根目录sourcelocal 告诉 torch.hub 不需要联网。modelcustom 是加载自定义权重的标准写法path 指定权重文件位置。results 对象里封装了所有检测结果pandas().xyxy[0] 会打印一张表格包含检测框坐标、置信度和类别 id。force_reloadTrue 保证每次重新加载模型避免 Jupyter 里用了旧的缓存。torch.hub 方式的好处是它会自动处理图片预处理和 letterbox输出坐标直接对应原图适合快速验证。缺点是你必须保留整个工程目录不能只拿一个权重文件去运行。如果比赛要部署到演示机上我建议还是用 5.1 的方式写一个独立的推理类把工程路径封装在类内部这样对外只暴露一个函数演示时不会报找不到模块的错误。5.3 处理大批量图片时的显存管理与结果保存批量推理最容易碰到两个问题图片一次性读入导致 OOM以及结果保存时文件名混乱。我一般用循环逐张推理并加上进度条和异常处理。import os, glob, cv2 from tqdm import tqdm from model_api import load_model, infer_image model, device, imgsz load_model(weightsbest.pt, device0, imgsz640) image_folder ./test_images output_folder ./test_output os.makedirs(output_folder, exist_okTrue) paths sorted(glob.glob(os.path.join(image_folder, *.jpg))) for p in tqdm(paths, descinfer): img cv2.imread(p) if img is None: print(f跳过无法读取的文件: {p}) continue det infer_image(model, img, device, imgsz) # 画框 for x1, y1, x2, y2, conf, cls in det: cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0,255,0), 2) cv2.putText(img, f{int(cls)}:{conf:.2f}, (int(x1), int(y1)-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 2) cv2.imwrite(os.path.join(output_folder, os.path.basename(p)), img)这段代码的逻辑用 glob 收集所有 jpg 路径tqdm 显示循环进度。每张图片单独读、单独推理、单独保存内存占用始终是一个 batch 的量级。infer_image 里已经用了 torch.no_grad()梯度不会累积显存稳定。不过如果图片尺寸小于 imgsz模型内部的 letterbox 会先补边返回的 det 坐标是 letterbox 后图像上的坐标直接画在原始图片上会偏移。需要处理的话可以把 letterbox 操作拿到函数外面再用原始坐标逆变换回去。对于大规模数据集还能考虑把 batch_size 调大在 infer_image 中支持 batch 输入。先对每张图做 letterboxpadding 成一个固定的 batch一次推理多个样本。但要注意不同图片的 letterbox 补边参数不同输出坐标也要分别映射。我一般只在压力测试时才这么做比赛演示用逐张循环完全足够。6. 验证与迭代用 TensorBoard 和混淆矩阵判断模型有没有“真学会”训练结束后很多人只看训练日志里最终 loss 很小就高兴地收工这是不严谨的。loss 只能反映训练过程的稳定程度真正能说明模型好坏的是验证集上的 mAP 和混淆矩阵。在训练输出目录下YOLOV5 会保存 TensorBoard 事件文件。启动它tensorboard --logdir runs/train/my_experiment_001浏览器打开后重点看三个曲线train_loss、val_loss、metrics/mAP_0.5。如果 val_loss 先降后升而 train_loss 持续下降说明模型开始过拟合可以提前停掉而不是硬跑完 100 个 epoch。如果 mAP 曲线在某个节点后变平再训下去也只是浪费时间。然后看混淆矩阵。训练目录会生成 confusion_matrix.png横纵坐标是类别名。矩阵对角线越亮越好如果某一对类别之间的色块特别亮说明模型经常把它们搞混。比如在安全帽数据集里模型总是把“戴安全帽”的人识别成“未戴”那你就要检查这两类样本数量是否均衡或者是否出现了标注错误。中文注释包里在 utils/metrics.py 里对混淆矩阵的计算做了中文说明你可以在推理阶段自己调用它用在比赛报告里作为模型分析。再用 val.py 独立评估一遍这是最稳妥的验证方式python val.py --data data/custom.yaml --weights runs/train/my_experiment_001/weights/best.pt --img 640这条命令会输出每个类别的 precision、recall 和 mAP。如果验证集的 mAP 比训练过程显示的 mAP 低很多说明模型在验证集上泛化能力差数据划分可能有问题或者增强参数过强。我通常在训练完成后立刻跑一次 val.py把结果截图存档作为调参的依据。我第一次用 YOLOV5 时只看 loss 降到 0.0 几就兴奋得不行结果一测实际图片全是漏检。后来才明白loss 只是过程指标mAP 才是最终参考。从那以后我每次训练结束都强制自己先跑一遍 val.py再看混淆矩阵最后才决定要不要调超参数。这个习惯帮我少走了很多弯路。希望帮到你。本文还有配套的精品资源点击获取
