YOLO v5是我认为目前最适合入门目标检测的模型之一。这篇笔记不是把官方教程复述一遍而是我完整走了一遍环境搭建、结构拆解、预训练推理、自建数据集训练、常见坑排查之后把真正能落地的经验沉淀下来的记录。如果你准备学目标检测或者已经在用但经常被各种报错卡住这篇内容应该能帮你省下不少时间。1. 学习之前先想清楚YOLO v5到底解决什么问题1.1 单阶段检测器带来的速度优势YOLO v5属于单阶段目标检测器。所谓单阶段就是输入一张图片经过一次前向传播直接输出所有目标的位置和类别。这种设计和两阶段检测器有本质区别两阶段会先产生候选区域再对每个候选区域做二次分类和回归流程更复杂精度固然有优势但速度很难上去。YOLO的核心理念是把检测当作回归问题来解。网络一次性预测所有目标的中心点坐标、宽高、类别概率不需要额外生成候选框。v5沿用了这个思路在速度和精度之间做了很好的平衡。对于大多数实际项目来说比如工业质检、安防监控、边缘设备部署实时性往往比极致的精度更重要这就是YOLO v5能成为工程首选的原因。我学习的时候有个体会一开始不要纠结于复杂的数学推导先把输入输出关系搞清楚。输入是一张任意尺寸的图片网络内部会统一缩放到640x640或者其他尺寸输出是三个尺度的特征图每个特征图上的每个网格点会预测若干组信息目标置信度、类别概率、边界框坐标。理解了这条主线后续看结构就不会迷路。1.2 YOLO v5的模型形态与适用场景YOLO v5按照模型深度和宽度分成五种规格n、s、m、l、x。从小到大参数量和计算量递增精度也递增。实际使用中s和m用得最多n适合嵌入式设备x通常在离线场景下追求最高精度。模型规格参数量大致范围推荐场景v5n约1.9M移动端、边缘计算追求极端速度v5s约7.2M通用场景平衡速度和精度v5m约21M小目标多、精度要求更高的场景v5l约46M服务器端推理精度优先v5x约86M离线批量处理追求极致精度这里要提醒一句参数和精度数值不同版本有细微差异不必死记。选择模型规模的原则很简单先用默认的s跑通流程再根据显存和测速结果上下调整。很多初学者一上来就用x结果显存爆了训练时间翻几倍完全没有必要。YOLO v5的代码结构非常清晰这也是我推荐它的原因之一。整个项目包含数据加载、增强、模型定义、训练、测试、导出几个模块每个模块的入口都一目了然。对于想深入理解检测原理的人v5是一个很好的学习范本。2. 拆透网络结构看懂主干、颈部、检测头2.1 输入端切片和拼接的组合技巧YOLO v5的输入端有几个关键操作。第一个是Focus模块在新版本中可能被替换但理解它仍然有意义。Focus的核心思想是把空间信息搬到通道维度举个例子输入是640x640x3的图片通过每隔一个像素取一个值的方式拆分成四个320x320的子图然后按通道拼接成320x320x12的张量。这样做的好处是下采样过程中不丢失信息同时减少后续计算量。用生活化的类比相当于把一张纸裁成四份叠在一起信息量没变但体积变小了。第二个关键操作是Mosaic数据增强。训练时会随机读取四张图经过缩放、翻转、拼接成一张大图。这种增强方式能极大丰富背景信息尤其是对小目标的检测效果提升明显。我在实际训练中观察过开启Mosaic的初期loss下降速度会比关闭时快很多这就是数据多样性带来的收益。锚框计算也是输入端的重要环节。YOLO v5默认带有基于COCO数据集聚类好的锚框但训练自己的数据集时程序会自动开启autoanchor根据你的标注信息重新聚类锚框。初学阶段不需要手动调整保持默认即可。2.2 主干网络C3与SPPF的作用主干网络负责提取图片特征。YOLO v5的主干以C3模块为核心。C3模块借鉴了CSPNet的思路把输入分成两条路径一条经过若干个Bottleneck堆叠另一条保持直连最后把两条路径的特征拼接再卷积。这样做有两个好处第一梯度可以通过直连路径顺利回流到浅层缓解深层网络的梯度消失问题第二特征复用让计算量大大减少同样的FLOPs下表达能力更强。SPPF模块是空间金字塔池化的快速版。传统SPP会对特征图做多个不同核尺寸的最大池化得到不同感受野的输出再拼接。SPPF则用三次核大小为5的池化串联每次池化后保留一份输出最后把多份结果拼接。为什么串联能代替并行因为连续池化的感受野是扩张的且计算量比并行池化更小效果几乎一致。我自己在修改结构时对比过SPPF确实是对部署更友好的一种设计。主干输出的特征图是原图的1/32尺寸包含丰富的语义信息但对小目标来说分辨率不够。所以检测网络不能只靠主干输出还需要结合浅层特征。2.3 颈部网络PANet为什么更适合小目标颈部网络的作用是融合不同尺度的特征。YOLO v5使用的是PANet结构可以理解为在FPN基础上增加了一条自底向上的路径。FPN自顶向下传递语义信息把深层的类别特征带给浅层PANet再反向传递位置信息把浅层的边缘、纹理细节带给深层。这个设计对小目标检测很重要。小目标在浅层特征图上还有一定分辨率如果只靠FPN底层的位置信息被压缩后很难恢复。PANet相当于双向高速公路高层语义和低层细节都能互相补充。我在工程中经常遇到一个现象同一批数据去掉PANet改成单纯FPN结构小目标的召回率会明显下降。理论上也能解释通但实际数据不会骗人。2.4 输出端多尺度预测与解码逻辑YOLO v5的检测头通过一个卷积模块输出三个尺度的预测结果分别对应原图的1/32、1/16、1/8下采样尺寸。1/32的特征图每个网格感受野大适合检测大目标1/8的特征图分辨率高适合检测小目标。预测结果不直接是坐标值而是相对于锚框的偏移量。解码时需要用Sigmoid将偏移限制在一定范围再结合锚框的宽高换算成最终的边界框。这一步在训练阶段会自动完成但在使用ONNX导出时要注意保留解码逻辑否则输出格式对不上。锚框在这里扮演的是先验参考的角色。比如要预测一个高瘦的目标锚框里已经有好几个高瘦比例的候选模型只需要学习微调偏移量而不是从零预测大幅度降低了学习难度。这也是为什么anchor-based的收敛速度通常比anchor-free更快。3. 环境准备与第一次推理5分钟跑通预训练模型3.1 配置Python环境与依赖在开始跑代码之前先把环境配好。我建议使用Python 3.8到3.11之间的版本配合PyTorch 1.8以上版本。安装完PyTorch后进入项目目录安装依赖pip install -r requirements.txt需要注意PyTorch、CUDA、显卡驱动三者必须匹配。如果是NVIDIA显卡可以在命令行里先验证CUDA是否可用import torch print(torch.cuda.is_available())输出为True说明GPU可用了。这一步经常会出问题很多人安装完就开跑结果程序默默使用CPU训练速度慢得让人崩溃。我初期就犯过这个错误训练一个几百张图片的数据集用了几个小时检查之后才发现CUDA没启用。3.2 下载权重并执行第一次检测项目自带下载脚本也可以手动下载预训练权重放在weights目录。以s模型为例推理命令很简单python detect.py --weights weights/yolov5s.pt --source data/images/bus.jpg执行完之后带检测框的图片会保存到runs/detect/exp目录。第一次跑通这个流程很有价值它证明了环境、代码、权重都正常。我在教初学者时总是让他们先不要碰训练先把推理跑通建立对输入输出的直观感受再深入内部。如果想检测视频或者摄像头只需要把source参数改成视频路径或者0。这里我踩过一个坑摄像头索引不一定是0笔记本自带摄像头通常是0外接USB摄像头可能是1。逐个试就能找到。3.3 推理参数逐个说清楚detect.py里几个参数在实战中最常用我把它们拆开讲--conf-thres置信度阈值默认0.25。低于这个值的预测会被过滤。实际推理时如果背景误检多可以调高到0.4如果希望召回更多目标可以降低到0.1。--iou-thresNMS的IoU阈值。这个值越高越倾向于保留重叠框越低越倾向于删除重叠框。多目标重叠严重的场景适当调低有助于减少漏检。--imgsz推理分辨率。默认640。对密集小目标场景尝试1280会发现召回率提升但速度会变慢。这是精度和速度的经典取舍。--max-det单张图最多输出多少个目标。默认300对于拥挤场景可以调大。--agnostic-nms跨类别NMS。开启后不同类别的重叠框也会互相抑制类间遮挡严重时可以试试。这些参数不需要背关键是理解每个参数控制的是哪一步操作。我用了一个多月之后才彻底摸清楚conf-thres和iou-thres的作用边界因为两者配合使用会共同影响输出结果。3.4 批量推理的小技巧实际项目中不会只检测一张图片。如果要对大量图片做批量推理直接指定图片目录即可python detect.py --weights weights/yolov5s.pt --source data/images/ --project runs/detect --name batch_result批量推理时建议把imgsz统一避免不同尺寸图片反复resize带来的性能波动。还可以把--save-txt参数加上让程序同时输出检测框坐标的txt文件后续如果要做数据统计或者接业务逻辑这个txt格式很有用。我自己做数据集清洗时就是靠批量推理输出的txt坐标来快速检查标注质量。4. 自建数据集训练从标注到best.pt的完整记录4.1 准备符合YOLO格式的数据集YOLO格式的标注是一个txt文件每行对应一个目标class_id x_center y_center width height其中x_center、y_center、width、height都是相对于图片宽高的归一化值取值0到1。举个例子假设图片宽度1000高度800一个目标的中心点在坐标(500, 400)框宽200高100那么txt内容就是0 0.5 0.5 0.2 0.125我用过好几个标注工具最终习惯还是先用工具生成再脚本检查一遍。为什么这么谨慎因为标注格式错误是训练出废模型的头号原因。常见的错误有类别ID从1开始而不是0、坐标没有归一化、行尾多了空格导致解析失败。数据集目录结构建议这样组织dataset/ images/ train/ val/ labels/ train/ val/图片和标签的文件名必须一致比如001.jpg对应001.txt。验证集不要太少我一般按8:1或9:1划分验证集至少几十张类别分布要覆盖所有类别。4.2 写三个配置文件训练前需要准备三个配置文件数据集描述文件、模型结构文件、超参数文件。数据集描述文件mydata.yaml示例path: /home/user/dataset train: images/train val: images/val names: 0: defect 1: normal这里要特别强调两个容易踩的坑。第一path要写绝对路径或者相对路径相对路径是相对于你执行train.py的位置不是相对于yaml文件的位置。第二names的顺序必须和标注的class_id一一对应。如果你标注时约定0是defect1是normal那names列表里第0个必须是defect。模型结构文件用的是models/yolov5s.yaml只需要修改一个地方把nc改成自己的类别数。比如刚才的例子是两类就写成nc: 2。这个文件里还有很多其他参数比如depth_multiple和width_multiple初学阶段不要动动一下整个网络的大小和结构都会变很可能导致权重加载失败。超参数文件是data/hyps/hyp.scratch-low.yaml里面有学习率、动量、数据增强强度等参数。默认参数对大多数数据集都能用我自己只有在小数据集或难分类的情况下才手动调整。所以这一档先放着。4.3 启动训练并看懂日志训练命令如下python train.py --data mydata.yaml --cfg models/yolov5s.yaml --weights weights/yolov5s.pt --epochs 100 --batch-size 16 --imgsz 640 --device 0几个关键参数解释一下--weights预训练权重路径。使用预训练权重可以大幅加速收敛因为模型之前在大型通用数据集上已经学会了很多底层特征。--epochs训练轮数。小数据集100轮起步我实际经验是50轮之后mAP才开始稳定上升太早停会造成欠拟合。--batch-size受显存限制。如果OOM优先减小batch-size。--device指定GPU编号0表示第一张卡。多个GPU可以用0,1。训练过程中终端会打印如下类似内容Epoch gpu_mem box_loss obj_loss cls_loss P R mAP_0.5 mAP_0.5:0.95这几个指标里mAP_0.5是你最需要关心的。它的含义是IoU阈值为0.5时的平均精度通常达到0.9以上说明模型效果不错。mAP_0.5:0.95则是一个更严格、跨多个IoU阈值的综合评价指标数值一般比mAP_0.5低但更能反映模型的定位精度。训练过程中要注意loss的变化趋势。box_loss和obj_loss应该整体下降允许有小幅震荡但如果出现大幅上下跳动说明学习率可能偏高。初期用warmup让学习率从小变大后期用余弦退火调度这些默认配置已经处理好了不需要手动干预。4.4 训练中断与恢复训练到一半断电或者显存溢出退出不用从头再跑。YOLO v5会自动在runs/train/exp下保存断点权重。恢复训练的命令是python train.py --resume runs/train/exp--resume后面接的是实验文件夹路径程序会读取该目录下的last.pt继续训练同时恢复优化器状态和epoch数。这个功能在长周期训练时太重要了。我有一次训练到80轮突然系统更新导致重启靠这个功能只丢了很少时间。训练结束后runs/train/exp下会生成best.pt和last.pt。best.pt是验证集上表现最好的权重通常部署和推理都用它。last.pt是最后一轮的权重适合继续训练时使用。模型导出为ONNX或TensorRT引擎也很简单python export.py --weights runs/train/exp/weights/best.pt --include onnx engine导出ONNX时如果遇到算子兼容问题先把opset版本调整到12或者13再试。TensorRT导出要求CUDA和TensorRT版本匹配否则会报一堆版本不兼容的错误。5. 常见问题与排查技巧实录5.1 显存不足OOM怎么办训练时最容易遇到的问题就是显存不够。程序直接报错CUDA out of memory。处理顺序我建议这样第一步减小batch-size到8或者4。第二步降低输入分辨率imgsz到512或416。第三步开启自动混合精度训练参数加--amp默认配置下显存占用能减少约30%。第四步使用梯度累积。YOLO v5有相关配置通过累积多个小batch的梯度来模拟大batch的效果。前两步效果最明显。但注意降低imgsz会直接导致小目标检测能力下降如果数据集里小目标多要谨慎。梯度累积也不是无损操作BatchNorm在累积模式下行为会略有不同尽量先用前三种方法。推理阶段显存不足通常是因为imgsz设置过大或者需要处理的视频分辨率太高。可以通过分帧处理来降低峰值显存。5.2 训练完mAP一直为0这个问题的出现频率非常高。围绕mAP为0我总结了一个排查清单标注文件是否为空。用脚本统计一下labels目录下的txt文件字节数如果大量文件是0字节说明漏标了。类别ID是否越界。标注文件里的class_id不能大于names列表长度减1如果写成了3而总共只有2个类别模型训练时遇到未知类别会直接出问题。names顺序是否正确。class_id为0的目标对应names[0]如果names列表写错顺序模型学到的语义和实际数据对不上。验证集图片是否真的存在。有些人的验证集路径写错导致程序用了空目录训练时loss正常下降但mAP始终为0。标签是否归一化。如果标注坐标是像素值而不是相对值模型计算出的IoU几乎为0mAP自然很低。我通常的做法是先跑一次推理用best.pt对验证集图片画框肉眼看输出是否合理。如果什么都检测不到再按上面清单逐项排查。5.3 Loss不降或震荡剧烈Loss不降的原因有很多最可能是这几个学习率不合适。默认学习率对大多数数据集有效但如果发现loss在前几个epoch完全不动可以检查是否为0或者过小如果大幅震荡适当调低学习率。锚框不匹配。训练时开启了autoanchor程序会根据数据集重新聚类但聚类出的锚框如果和真实目标尺寸分布差距太大会影响收敛。可以在训练命令里加上--noautoanchor关闭自动聚类但前提是你手动配置的锚框经过分析是合理的。数据增强过强。YOLO v5默认的增强策略很激进比如HSV扰动、旋转、缩放。如果数据量少且目标很小增强过度可能导致模型学不到稳定特征。此时可以适当降低hsv、degrees、translate等超参数甚至暂时关闭部分增强。还有一个隐蔽问题标注错误。如果一个目标的中心点标偏了或者和真实边界偏差太大模型会学到错误的回归目标导致loss居高不下。数据清洗在深度学习里不是浪费时间而是必做步骤。5.4 推理速度偏慢怎么办相同模型在不同环境下的推理速度差异可能非常大。先检查是不是在用CPU推理。torch.cuda.is_available()返回False却没人发现这种情况我见了不止一次。需要显式指定device参数。如果GPU推理仍慢看这些地方是否开启了批量推理。单张循环推理比批量推理慢得多。是否使用FP16。半精度推理速度在支持的GPU上能提升明显。是否需要TensorRT。导出engine后推理速度通常能再快一倍以上。NMS的iou阈值是否过低。过低会导致大量候选框需要参与NMS计算。imgsz是否过大。640提升到1280会让计算量翻好几倍。做个简单测速不要光看推理时间还要统计预处理和后处理的时间。YOLO v5的预处理和后处理虽然很轻量但在极端低延迟场景下也是优化空间。5.5 零碎问题速查表问题现象常见原因解决建议训练报错找不到图片data.yaml路径配置错误检查path和train/val相对路径加载预训练权重报结构不匹配修改了模型结构但没改nc检查model yaml的nc是否与数据集一致检测结果全部是同一个类别names顺序或标注ID混乱核对标注工具导出时的类别顺序视频检测卡顿未利用GPU或分辨率过高确认device参数降低imgszexport导出ONNX报错opset版本过旧调整opset到12以上速查表的本质是给排查提供方向。实际调试时最有效的办法还是逐步回退配置比如先把Mosaic增强关了、把预训练权重去掉用最小配置跑通后再逐步加回定位是哪一步引入的问题。6. 学习心得与进阶路线6.1 怎么检验自己真的学懂了跑通代码不算学会能回答下面几个问题才算入门输入一张640x640的图网络内部经历了哪些尺寸变化C3模块的梯度是如何流动的SPPF的池化串联和SPP的并行池化在感受野上为什么等价三个输出尺度分别对应原图的多少倍下采样训练时和推理时NMS的作用有什么不同如果让你把Anchor去掉网络输出应该怎么改这些问题看起来偏理论但实际都是在帮助你建立对模型的整体理解。我自己的办法是动手画结构图把每个模块的输入输出尺寸标上去画到第三步基本就明白了。还有一个更粗暴的办法在代码里加print把每一层的输出张量维度都打出来跟着前向传播走一遍理解比看书快得多。6.2 后续往哪个方向进阶YOLO v5不是终点。当你能熟练完成训练和部署之后可以往几个方向延伸轻量化与移动端部署剪枝、量化、知识蒸馏。这些技术能让模型更小更快适合端侧落地。Transformer检测器RT-DETR系列、DETR系列走的是另一条路线不依赖锚框和NMS结构更简洁对理解检测本质很有帮助。实例分割YOLO系列也有分割版本检测和分割共享很多底层特征学起来有迁移价值。多任务扩展比如同时做目标检测、关键点检测、属性识别在实际项目中很常见。技术选型上我个人的建议是追求快速可靠落地YOLO v5仍然是很稳的选择如果追求更高的精度上限和更灵活的结构新的检测器值得投入时间。但不管学哪个新模型核心机制都是一样的比如特征金字塔、锚框机制、损失函数设计这些底层知识永远是相通的。6.3 一个值得坚持的习惯最后分享一个我自己的习惯每次训练完一个模型我会把训练日志、loss曲线截图、最终的参数配置、踩坑记录整理成一个独立的笔记文档。这个习惯在后来做多个相似项目时发挥了大作用。比如当我需要在一个新数据集上快速起步时翻出上次成功训练的参数配置改掉数据路径直接跑往往比从零调参快很多。学习笔记的意义就是这样它不只是记录过程更是建立自己的知识复用体系。YOLO v5这个模型本身在迭代但它的设计思想和实践方法论很多到现在仍然适用。