ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

YOLOv5s目标检测实战:从数据标注到ONNX部署全流程

2026/9/19 11:19:40 拓冰建站 浏览量
YOLOv5s目标检测实战:从数据标注到ONNX部署全流程 做目标检测的朋友应该都听说过YOLOv5s尤其是刚入坑或者需要快速落地一个检测任务时YOLOv5s几乎是绕不开的选项。它属于YOLOv5系列里体积最小、速度最快的一个变体模型参数量只有7.2M左右但在COCO数据集上仍能保持约37.2的mAP兼顾了精度和推理速度。我自己在多个项目里用过YOLOv5s从安防摄像头的人形检测到工厂流水线的缺陷识别再到边缘设备上的实时检测它都能比较稳地扛住任务。这篇文章我想把YOLOv5s从数据准备到实战检测的完整流程讲透包括标注规范、目录结构、训练参数、日志分析、断点续训、ONNX导出以及我踩过的坑和排查方法。不管你是刚开始接触目标检测还是已经跑通过官方示例但想自己训练业务数据都可以跟着这套流程走一遍。1. 先搞清楚YOLOv5s到底能干什么1.1 为什么选YOLOv5s而不是其他版本YOLOv5官方仓库提供了n、s、m、l、x这几种不同规格的模型数字越小模型越小速度越快但精度也相对低。YOLOv5s正好是中间偏轻量的选择它在精度和速度之间的平衡点非常经典。很多人一上来就用YOLOv5x觉得精度越高越好但实际部署时往往发现GPU扛不住或者视频流处理帧率只有个位数。YOLOv5s在RTX 3060上跑1080p视频批量推理能达到80到120 FPS在CPU上也能勉强跑到10到20 FPS这个表现对于大多数原型验证和中小型项目来说完全够用。我选择YOLOv5s还有一个原因它是我见过最容易“调好”的模型。这里不是说它不用调参而是相对大模型来说YOLOv5s对学习率、batch size的波动不那么敏感训练更容易收敛。如果你是在自己的业务数据上训练YOLOv5s即使只训练几十个epoch也能得到一个基本可用的权重这对快速验证需求非常有价值。当然如果检测目标特别小或者遮挡严重可以后续再切到YOLOv5m或YOLOv5l但起步阶段从YOLOv5s开始是最稳妥的。1.2 检测任务的基本流程目标检测任务本质上要解决两个问题目标在哪里目标是什么。YOLOv5s的做法是把输入图片划分成网格每个网格负责预测若干边界框同时输出每个框内目标的类别概率。训练阶段我们给模型看大量已经标注好的图片让它学会从像素中提取特征并回归出边界框位置。推理阶段模型只需要一次前向传播就能输出所有检测结果这也是YOLO系列“You Only Look Once”的由来。完整的训练全流程可以拆成四步数据准备、环境搭建、模型训练、模型部署。每个环节都有自己的坑。数据准备决定模型的上限训练参数影响收敛速度部署方式则直接关系到实际效果。后面我会按照实际操作顺序一步步展开每个命令和参数都会解释为什么这么写方便大家根据自己项目的情况做调整。2. 数据准备训练前80%的工作量都在这2.1 数据采集与标注规范很多教程喜欢直接跳到训练命令但我必须强调数据准备才是整个项目里最花时间也最影响结果的环节。你采集的数据直接决定了模型能不能在真实场景里用起来。采集时要注意场景多样性、光照变化、角度变化、目标尺度变化。如果只拍同一批角度和背景的图片训练出来的模型换个环境就废了。标注这一步推荐使用LabelImg或X-AnyLabeling。LabelImg是老牌工具界面简单支持PascalVOC和YOLO格式导出。X-AnyLabeling集成了多种AI辅助标注功能可以先用预训练模型自动打框再人工修正能节省大量时间。我自己在大规模数据标注时通常先用一个初步训练的模型做预标注然后人工校准效率能提升3倍以上。标注规范有几个必须遵守的点。第一边界框要尽量贴合目标边缘不要留太多背景也不要把目标截断。第二类别标签不要有歧义比如“人”和“行人”不要混用。第三标注文件里一张图如果有多个目标每行一个目标格式是“class x_center y_center width height”其中x_center、y_center、width、height都是相对于图片宽高的归一化值。举个例子一张640x640的图片某个目标中心点位于(320, 320)框宽为80高为160那么标注行就是0 0.5 0.5 0.125 0.25。这里0是类别编号。这一点特别容易错很多人写成绝对像素坐标或者没归一化训练时就会报错或者loss直接崩掉。2.2 数据集目录结构与label格式YOLOv5官方仓库对数据集目录结构有明确要求我建议严格按官方规范来这能避免很多后期路径问题。最基础的目录结构是这样的dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── dataset.yamlimages和labels下的train、val、test文件夹要一一对映。图片文件名和标注文件名必须完全相同只是后缀不同。比如图片是photo_001.jpg对应标注文件就是photo_001.txt。一旦文件名对不上训练的时候这张图就无法读取容易报warning影响训练效率。另外要注意不同版本的YOLOv5对目录名是否区分大小写有一定要求建议统一使用小写。如果你的数据是在Windows上标注后拷到Linux服务器训练一定要检查路径里的反斜杠和盘符最好把数据集完整上传到服务器并重新校验一遍。2.3 数据集划分与配置文件数据划分一般按训练集、验证集、测试集6比2比2或者8比1比1来分。测试集是最后评估用的训练过程中不要碰它。验证集用于每个epoch后评估模型效果帮助调整超参数和选择最佳模型。划分时可以写个小脚本也可以用YOLOv5自带的split工具但最简单的还是随机打乱后按比例分配。需要注意的是同一个场景的连续帧图片如果同时出现在训练集和验证集里会导致验证结果虚高模型实际泛化能力并没有那么好。所以在划分之前最好先按帧序列分组再整组划分。配置文件dataset.yaml是整个训练的关键它告诉YOLOv5数据在哪里、有几类、类别名是什么。内容很简单path: /home/user/dataset train: images/train val: images/val test: images/test nc: 2 names: [person, car]这里path是数据集根目录的绝对路径train和val可以写相对路径也可以写图片文件夹的完整路径。值得注意的是有些初学者在path里写了相对路径但训练时工作目录不在项目根目录就会导致“No labels found”的报错。我建议path直接写绝对路径省心。nc是类别数必须和标注里的类别编号范围一致。比如类别有3类编号就是0、1、2nc就填3。names列表里的顺序也必须和标注文件里的编号逻辑一致否则模型学出来类别全乱了。3. 环境搭建与模型配置3.1 安装依赖与验证环境训练YOLOv5s需要的Python版本建议3.8到3.10PyTorch版本建议1.8以上。我目前常用的是PyTorch 2.0.1 CUDA 11.8的组合跑yolov5s非常稳定。安装命令在官方README里有建议用conda创建新环境避免污染系统Python。我这里列一个完整流程conda create -n yolov5 python3.9 -y conda activate yolov5 cd yolov5 pip install -r requirements.txtrequirements.txt里包含torch、torchvision、opencv-python、numpy等依赖。如果你已经有安装好的PyTorch可以跳过自动安装PyTorch避免版本冲突。装完后先验证一下GPU是否可用import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))如果输出True和显卡型号环境就基本没问题了。很多同学卡在装环境这一步主要原因是网络问题导致包下载慢。建议用国内镜像源比如阿里云或清华源pip install的时候加上-i参数。另外如果是在公司内网环境还要看是否有代理墙的限制不过这点就属于网络配置的常规操作了略过不提。3.2 修改data和yaml文件除dataset.yaml外模型结构文件models/yolov5s.yaml里通常不需要动保持默认即可。训练时通过--data参数指定dataset.yaml--cfg参数指定模型结构yaml--weights指定预训练权重或断点权重。有一个容易忽略的点YOLOv5里有“anchors”的概念官方预训练用的anchor是在COCO数据集上聚类出来的。如果你训练的类别是大目标或小目标直接沿用默认anchor可能效果不佳。YOLOv5提供--noautoanchor参数关闭自动anchor但默认情况下训练前会自动计算当前数据集的anchor。如果你的数据目标尺度很特殊可以先用--noautoanchor跑一次训练然后在训练日志里查看建议的anchor再手动填进模型yaml里。不过对于大多数项目自动anchor已经够用先别折腾这个。3.3 预训练权重与冻结训练策略YOLOv5s最核心的优势就是有在COCO上预训练好的权重。这些权重已经学到了通用特征比如边缘、纹理、形状等。使用预训练权重可以大幅加快收敛速度甚至可以将训练时间缩短到原来的十分之一。下载方式有两种一是训练时直接加--weights yolov5s.pt如果本地没有脚本会尝试从官方下载二是手动下载后放到weights目录。我建议手动下载因为官方服务器在国外训练过程中断网会影响体验。wget https://github.com/ultralytics/yolov5/releases/download/v6.0/yolov5s.pt -P weights/下载后训练命令里的--weights weights/yolov5s.pt。如果你的数据集跟COCO类别差异非常大或者你需要修改类别数加载预训练权重时模型最后一层输出维度会不匹配YOLOv5会自动处理这种情况提示你“Transferred x/y layers”它不加载最后一层权重。这里的“x/y”表示从y层中成功转移了x层不必担心那个警告。冻结训练是指训练初期固定backbone层的参数只训练head部分。这样可以节约显存加快速度也能防止小数据集过拟合。有个经验值当数据集每个类别只有几百张图片时冻结backbone前10层能显著提升稳定性。用YOLOv5训练时我看training命令有--freeze参数。比如要冻结前10层可以加--freeze 10。注意这个参数是冻结模型的前N个模块而不是全部backbone。实践中我建议先用freeze10训练50个epoch再解冻全部层微调效果往往比一次性训练更好。4. 训练过程与监控4.1 训练命令与关键参数解析训练YOLOv5s的标准命令长这样python train.py --data dataset.yaml --weights yolov5s.pt --epochs 100 --batch-size 16 --img 640 --device 0这个命令里边每个参数都有讲究。--epochs别设太大也不要太小。100轮在大多数中规模数据集上够用如果数据复杂可以增加到200。--batch-size受显存限制YOLOv5s在16G显存上可以开64但建议先设为16试一下。如果显存不够把batch降到8但如果你发现loss波动很大或mAP很低往往是因为batch太小梯度更新不稳定。--img是输入图片分辨率默认640。我建议训练和推理保持相同输入尺寸否则部署时可能有性能差异。如果你的目标是大物体可以适当缩小到416提高速度如果小目标多可以尝试896来保留更多细节但显存和速度会翻倍。训练时建议再加一个--project和--name参数用来指定输出路径。很多新手把所有实验结果都放在yolov5/runs/train/exp几个默认目录里结果分不清哪个模型对应哪次训练。我一般这样写python train.py --data dataset.yaml --weights yolov5s.pt --epochs 100 --batch-size 16 --img 640 --device 0 --project runs/train --name person_car_v1这样输出目录就是runs/train/person_car_v1里面会自动生成weights、results.csv和训练日志。长期做项目一定养成这个习惯后面找模型时非常方便。4.2 训练日志与曲线怎么看训练过程中控制台会打印每一轮的信息包括GPU利用率、box_loss、cls_loss、obj_loss、mAP等。很多人只看最终mAP其实中间过程更有参考意义。刚开始训练时loss会快速下降然后逐渐平缓。如果box_loss一直在下降mAP也在缓慢上升说明模型还在学习别急着停。如果loss降到某个值后震荡而且已经跑了大量epoch说明模型基本收敛可以停了。YOLOv5会在输出目录里生成results.png包含多个子图train/box_loss、train/obj_loss、train/cls_loss、val/box_loss、val/obj_loss、val/cls_loss、metrics/precision、metrics/recall、metrics/mAP_0.5、metrics/mAP_0.5:0.95。这些曲线能帮助你判断训练状态。我判断过拟合的一个重要经验如果val loss曲线一路下降后再明显反弹而train loss还在下降说明模型在“背题”而不是在“学规律”此时应该用早停或增大数据增强。YOLOv5默认开启早停patience100如果验证指标连续100轮没有提升会自动停止这个机制很实用。4.3 中断恢复与断点续训训练任务经常因为断电、显卡报错或服务器重启而中断。YOLOv5提供的断点续训非常简单只需要在训练命令里把--weights指定为上一次训练的last.pt即可。比如python train.py --data dataset.yaml --weights runs/train/person_car_v1/weights/last.pt --epochs 200 --batch-size 16 --img 640 --device 0此时epochs要填总共需要的轮数YOLOv5会读取last.pt中记录的上次已训练轮数自动从断点处继续直到达到你设置的总epoch数。除了权重优化器状态、学习率、随机种子也都会被恢复所以续训结果和连续训练几乎一样。我建议每个项目都要养成每10个epoch存一次检查点的习惯可以用--save-period 10参数控制。万一训练中断最多损失10个epoch的工作量。5. 模型评估与实用性调优5.1 指标解读mAP、Precision、Recall训练结束后weights目录下会有best.pt和last.pt。best.pt是验证集上表现最好的模型last.pt是最后一个epoch的模型。一般部署时用best.pt。评估指标主要看验证集上的mAP_0.5和mAP_0.5:0.95。mAP_0.5表示IOU阈值取0.5时的平均精度比较宽松mAP_0.5:0.95则表示从0.5到0.95不同IOU阈值下的平均精度更严格也更考验边界框回归精度。Precision精确率表示模型预测为正样本的结果中真实为正样本的比例。Recall召回率表示真实正样本中被模型找出来的比例。这两个指标往往此消彼长。如果你的任务更关心“漏检率要低”就优先提高Recall如果更关心“误检要少”就优先提高Precision。可以通过调整置信度阈值来权衡。YOLOv5的detect.py里通过--conf-thres控制置信度阈值默认是0.25。调低阈值会提高Recall调高阈值会提高Precision。在部署阶段根据实际业务需求调一下这个参数往往比重训模型更有效。5.2 常见过拟合、欠拟合与数据增强调整如果训练集上mAP很高但验证集或测试集效果很差几乎可以断定过拟合。解决办法有几个增加数据量、调高数据增强、引入dropout或weight decay、冻结部分层。YOLOv5内置了丰富的数据增强包括马赛克增强、随机仿射变换、HSV色域变换、翻转等。数据增强默认是开启的但可以调整超参数。在data/hyps/hyp.scratch-low.yaml或hyp.scratch-high.yaml里可以设置。比如hyp.scratch-high.yaml里hsv_h等参数会调高增强更强适合小数据集。如果你的数据本身已经非常丰富增强太强反而会“矫枉过正”导致模型学不动。遇到这种情况把增强参数适当降低即可。欠拟合的表现是训练集和验证集loss都很高mAP上不去。此时多半是模型容量不足或者训练轮数不够。可以先排除数据集标注错误问题再看是不是分类太难最后考虑换更大的模型YOLOv5m。另外学习率太大也会导致loss下不去可以用默认学习率训练不要一开始手动改得很夸张。5.3 剪枝、量化与模型导出训练好后为了部署一般需要导出模型格式。常见的导出格式有ONNX、OpenVINO、TensorRT等。YOLOv5自带的export.py就支持多种格式一行命令即可。例如导出ONNXpython export.py --weights runs/train/person_car_v1/weights/best.pt --include onnx --img 640 --batch-size 1导出ONNX后可以使用onnxruntime推理CPU上也能跑方便后续跨平台部署。如果要上TensorRT可以先导出engine文件在NVIDIA显卡上实现更低延迟。量化是另一个方向比如使用INT8量化可以把模型体积缩小四倍推理速度提升明显但精度会有一定损失。我的建议是先确保模型效果满足需求再考虑量化和优化不要一上来就压缩模型。6. 实战检测用训练好的权重跑起来6.1 单张图片、视频和摄像头的检测拿到best.pt后最直接的验证方式是用detect.py脚本跑推理。参考命令python detect.py --weights runs/train/person_car_v1/weights/best.pt --source data/images/test.jpg --img 640 --conf-thres 0.25--source参数既可以传图片路径也可以传视频文件路径还可以传摄像头设备号比如--source 0表示本机第一个摄像头。输入为图片时结果保存在runs/detect/exp目录下标注好识别框和置信度。输入为视频时会逐帧检测再合成视频文件。我在实际项目中最常用的是cam feed把Source设为摄像头跑起来帧率还挺满意。需要注意的是如果摄像头分辨率很高建议先缩放到640输入因为YOLOv5s本身输入尺寸是固定正方形的内部会做letterbox填充直接输入原始高分辨率反而增加耗时。6.2 在Python脚本中调用模型进行实时检测除了命令行我们经常需要在自己的程序里调用模型。YOLOv5官方训练好的权重可以非常方便地被torch.hub加载但如果你想加载自己的权重推荐使用以下方式import torch import cv2 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/person_car_v1/weights/best.pt, force_reloadTrue) model.conf 0.25 model.iou 0.45 img cv2.imread(data/images/test.jpg) results model(img) results.print() results.show()这个用法适合快速测试。但如果你要部署到生产环境我建议把模型导出为ONNX然后用onnxruntime推理这样不依赖PyTorch和YOLOv5仓库代码部署自由度更高。一个简单的ONNX推理逻辑如下import onnxruntime as ort import cv2 import numpy as np session ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name session.get_inputs()[0].name input_shape session.get_inputs()[0].shape img cv2.imread(data/images/test.jpg) # 预处理letterbox normalize # 这里省略具体实现核心是把图像resize到640x640并归一化 # 输出形状为 (1, 25200, 85)再通过NMS过滤低置信度框ONNX模型输出的是原始预测张量后处理需要自己写NMS。YOLOv5官方导出ONNX时通常会附上后处理部分但为了更可控很多场景下我们会在模型侧只保留头部输出自己实现解码。这块需要花点时间但调试一次后就能建立起完整的部署链路。6.3 轻量化部署从PC到边缘设备如果你的目标设备是树莓派5、Jetson Nano或RK3588这类边缘设备模型体积和推理速度就变得非常关键。树莓派5上跑YOLOv5sCPU模式下单帧推理大约在200到300毫秒如果使用NCNN或者RKNN的NPU加速可以降到30到50毫秒。我试过在树莓派5上部署自己训练的YOLOv5s模型第一步就是转换为ONNX再用NCNN转换为.param和.bin文件。转换过程中要注意YOLOv5的anchor和输出层NCNN自带yolov5示例很多坑都补过了。部署到边缘设备时输入尺寸可以选择320或416来提速但要注意这会降低检测精度尤其是小目标会损失严重。还有一点模型量化到FP16或INT8后在边缘设备上效果会有所变化建议量化前先做一个包含各种场景的验证集对比量化前后mAP如果精度下降超过可接受范围就考虑用INT8混合量化或退回FP16。7. 常见问题与排查技巧实录7.1 数据集路径和标签格式报错训练时最常见的两个报错一是“No labels found in ...”二是“AssertionError: train: No labels in ...”。这通常是因为labels目录下找不到对应txt文件或者图片和txt文件名不匹配。排查顺序是检查labels/train目录是否存在检查txt文件里是否每一行有5个数值检查图片格式是否是jpg、png等YOLOv5支持的格式。还有一个坑标注文件的路径检查使用LabelImg保存时如果设成了PascalVOC格式生成的.xml文件就不能直接用必须先转换为txt。转换脚本网上很多但是一定要核对归一化坐标是否在0-1之间。7.2 CUDA out of memory这是最普遍的报错我的应对办法是按优先级降级先把batch-size降到8或4如果还不行就把--img从640降到416再不行就把workers数调低比如--workers 0。另外使用--device 0指定GPU避免同时占用多卡。有时候即使batch很小也OOM可能是由于日志或验证阶段缓存了太多数据可以尝试关闭--cache-images参数。还有一个容易被忽略的点如果你的显卡显存只有6G就不要在训练时开着TensorBoard显卡可视化工具它也会占一部分显存。7.3 训练效果差但不知道从哪查当模型mAP一直很低时我一般按这个顺序排查。先随机抽样标注好的图片用可视化脚本把标签框画出来看是否正确。很多问题其实出现在标注阶段比如标注框严重偏移或类别编号错乱。如果标注没问题就看是不是数据量太小少于500张图片的训练集很难让模型达到高精度。再看训练曲线如果loss不下降考虑学习率问题。最后再看模型是不是压根没加载预训练权重如果--weights路径写错模型就从零开始训练收敛会很慢。这里可以整理一个速查表现象可能原因处理办法训练时找不到标签目录结构或文件名不对检查images/labels对应关系显存不足batch_size过大降低batch_size或分辨率loss不下降学习率过大或数据没加载对检查数据加载恢复默认学习率val loss反弹过拟合增加数据增强或提前停止mAP很低标注错误或数据太少可视化标注扩充数据这类问题我几乎每个项目都遇到过按套路排查能节省很多时间。建议每次实验都保留训练日志和曲线图这样即使隔了几天再回头看也能快速定位问题。YOLOv5s的整个训练链路并不复杂但真正做到稳定可靠需要在数据、参数、部署上反复打磨。我个人最喜欢YOLOv5s的一点是它的调试成本低出错时提示信息也足够清晰非常适合作为业务落地的基础模型。希望这篇流程解析能帮你少踩一些坑如果你的数据集准备得足够扎实按照这套流程走下来第一次跑出可用模型应该不成问题。后面我也会把ONNX部署到边缘设备的完整代码整理出来到时候可以继续聊。