ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv5数据集格式详解:自动驾驶目标检测训练避坑指南

YOLOv5数据集格式详解:自动驾驶目标检测训练避坑指南 简介面向自动驾驶目标检测任务提供YOLOV5目录格式的标注数据集覆盖卡车、行人、交通信号灯等11类道路目标配套图像为512×512 RGB每帧含多个目标且边界框清晰适合车辆检测、密集场景识别与自动驾驶感知模型训练。资源包共2000个文件以1999个txt标签文件为主附1个Python可视化脚本压缩后约493MBtxt文件按YOLO标准格式记录类别与框坐标脚本可随机读取对应图像绘制边界框并保存结果无需修改即可运行便于快速核验标注质量。数据整体按训练集与验证集组织类别文本齐全可直接接入YOLOv5等模型完成训练和评估省去自行转换格式的环节也方便批量验证标注效果。已有174人学习/下载既适合目标检测入门者快速搭建可训练的数据流程也适合中高级开发者直接开展自动驾驶场景下的检测实验。1. 拿到目标检测数据集YOLOV5目录格式后先别急着跑训练第一次上手自动驾驶感知最容易踩坑的就是这种“目标检测数据集YOLOV5目录格式”看着 11 个类别、训练集验证集都切好了以为把 YOLOv5 打开就能直接训练结果跑出来的预测不是框偏就是类别错。这份数据集的价值在于省掉了采图、标注、格式转换三件脏活尤其适合做自动驾驶道路信息检测的早期基线——你今天晚上就能看到第一版 YOLOv5 训练曲线而不是花两周去处理标注工具导出的一堆 XML。适合两类人一类是想在自动驾驶场景里做快速验证的算法工程师另一类是刚学目标检测、想把数据处理、训练、验证、导出这条链路完整跑通的学生。但“YOLOV5目录格式”这六个字背后有几条硬性约定目录怎么摆、标签文件里的五个数字怎么读、data.yaml 和类别编号怎么对齐但凡有一处没对好训练结果就会非常“玄学”。下面从拿到数据集到训出可用模型把每一层拆开讲清楚该避的坑一次说透。2. 先看目录格式和标签约定跑 YOLOv5 前置的五个硬性规则2.1 目录结构images 与 labels 在数量上严格一一对应拿到数据集以后第一件事不是打开训练脚本而是先把目录结构看全。用一条命令就能看清出入口在哪。tree -L 3 dataset/正常会看到一套非常固定的形态dataset/ ├── data.yaml ├── images/ │ ├── train/ │ │ ├── 000001.jpg │ │ └── 000002.jpg │ └── val/ │ ├── 000003.jpg │ └── 000004.jpg └── labels/ ├── train/ │ ├── 000001.txt │ └── 000002.txt └── val/ ├── 000003.txt └── 000004.txtimages 和 labels 两个顶层目录必须成对出现下面再各自分 train、val。对自动驾驶这种高分辨率道路图来说图片目录往往特别大肉眼很难发现问题但规则只有一条images 里的每个.jpg必须在 labels 对应子目录里有一个同名.txt。所谓“同名”是去掉扩展名之后的 basename000001.jpg对应000001.txt不能是000001.txt.txt或者大小写不一致。第一次训练时 YOLOv5 会扫描所有图片并生成缓存文件扫描日志里如果出现“missing labels”或“skipped”这类提示要去和总数核对。常见情况是数据集本身没问题但在拷贝、解压的时候丢了一部分 txt或者标注工具导出时把空标签文件省略了。这里的坑在于YOLOv5 只会把那些“图在但 label 不在”的样本跳过而不是报错你可能训了半天模型实际上只用了 70% 的数据。还有一类文件要特别注意内容为空的 txt。自动驾驶场景里大量空旷道路、路口远景是没有目标的这些图像需要保留为“背景帧”对应的 txt 文件写成 0 字节。很多整理脚本会顺手删掉空文件结果是负样本大量减少模型学出来的误检明显变多。后面第五章会专门展开这个坑。2.2 标签 txt 的 5 列类别编号和归一化坐标必须按这个顺序读打开任何一个标注文件内容都是每行一个目标一行 5 列类似这样2 0.516113 0.448242 0.181641 0.352539从左到右分别代表类别编号0 起始的整数、归一化中心点 x 坐标、归一化中心点 y 坐标、归一化框宽度、归一化框高度。上面这行就是类别 2 的目标中心位于原图横向约 51.6%、纵向约 44.8% 的位置框宽约占整张图宽度 18.2%框高约占整张图高度 35.3%。YOLOv5 对坐标系非常敏感。它要求的是比例值不是像素值。如果你打开 txt 发现某个坐标是 643、829 这种大数值说明这份数据集不是纯 YOLO 格式可能是某个标注工具导成了像素坐标。这里给出从像素坐标转归一化坐标的标准做法。# 把像素坐标 (x1, y1, x2, y2) 转成 yolo txt 的一行 img_w, img_h 1920, 1080 # 用原始图像的宽高 cls_id 2 x_center (x1 x2) / 2 / img_w y_center (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h print(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f})转换时最关键的细节是必须使用原图分辨率而不是训练时缩放的 640×640。如果原图是 1920×1080你拿缩放后 640×428 的分辨率去算比例所有框的中心点都会偏训练 loss 会下降但 mAP 始终低。浮点位数一般保留 6 位就够有些数据工程习惯保留 78 位对小目标更友好但我测下来 6 位已经能满足绝大多数模型。至于类别编号它和类别名称没有关系只和 data.yaml 里的排列顺序有关。这也是最容易“张冠李戴”的地方标注工具导出的类别顺序可能是 person0、bicycle1、car2而 dataset 的 data.yaml 写成了 car0、truck1于是所有框的语义都错位。后面要训练前用计数器去核对不能凭文件名猜。2.3 data.yaml 的三段配置路径、类别数量、names 顺序缺一不可训练的第一步就要把数据和代码接起来接起来的枢纽是一个 data.yaml。这是 11 类自动驾驶道路识别任务里很典型的一种写法path: /data/road_dataset # 根目录建议写绝对路径 train: images/train val: images/val nc: 11 names: 0: person 1: bicycle 2: car 3: motorcycle 4: bus 5: truck 6: traffic_light 7: traffic_sign 8: rider 9: dog 10: other_vehiclepath是数据集根目录train与val是相对path的子目录。这里要特别强调不要图省事只写train: /data/.../images/train而不写path也不要让path留空。YOLOv5 在拼接路径时的行为是“以当前工作目录为基准”再去拼相对路径如果你从yolov5/目录下运行python train.py --data ../dataset/data.yaml而 data.yaml 里写的是train: images/train它不会自动退回到上一级目录去找 images。最省心的策略就是在 data.yaml 里写绝对路径。nc是类别总数数值必须等于 names 列表的最大编号加 1。编号从 0 开始连续排中间不允许跳号。如果你发现某个数据集 names 只有 10 项但 txt 里出现了编号 11 的文件说明标签文件里混入了其他类别的数据这种数据集使用前必须先清洗。第一次用预训练权重时还有一个现象要提前知道官方给的yolov5s.pt是 80 类 COCO 权重而这份数据是 11 类。加载权重时日志里会出现“Transferred 362”之类的内容并提示未转移的层数是多少这是正常的——模型把分类头那层重置成了 11 类其余骨干参数继续沿用。不用慌也不需要去改权重。训练一次后这套目录格式如果要在 YOLOv8 里继续用也是兼容的data.yaml、txt 标签全部原样。所以现在把数据检查做扎实后面换 YOLO 系列任何模型都能少踩一遍格式坑。3. 用 YOLOv5 训练 11 类道路数据环境、命令与参数初值3.1 YOLOv5 环境配置的三个常见问题CUDA、PyTorch 版本和反复装包环境配置是这一章里最没有技术含量、却最容易卡住人的地方。照着官方 README 跑一般不会出错。git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt如果数据集里全是高分辨率道路图建议再补装一个pillow升级版避免部分 JPEG 的 EXIF 信息导致读图出错。很多老机器生成 JPEG 存在过旋转标记Pillow 版本低的时候读出来的图和标注坐标系对不上这是比较冷门的坑。库装完之后先验证一个东西PyTorch 到底能不能用 GPU。python -c import torch; print(torch.__version__, torch.cuda.is_available())如果输出True环境基本能跑。如果torch.__version__显示 CPU 版本训练时会慢到让你怀疑人生。常见原因是pip install requirements.txt时把 PyTorch 装成了默认 CPU 版或者机器上 CUDA 驱动与 PyTorch 依赖的 CUDA 版本冲突。解决办法是直接去 PyTorch 官网给出的对应版本安装命令别在 requirements 里硬试。常见组合是 CUDA 11.8 PyTorch 2.0.x近两代显卡也能兼容。环境装完以后不要急着直接跑全量训练。先用一个很小的--epochs 3验证数据能不能被正常读到同时验证 class 数量是否正确。如果这一步先跳过真等了两小时训练才发现类别错位代价就大了。3.2 第一次训练命令epoch、batch、imgsz 怎么给比较稳最小可跑通训练的命令大概是这个形态python train.py \ --data /data/road_dataset/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --name road11_baseline--data指向 data.yaml--weights用来指定预训练权重。第一次做基线建议用 s 或 m别直接用 l 或 x因为 11 类道路数据在 1920×1080 大图上目标尺寸差异极大一旦--img上调显存会迅速被吃穿。--img是训练输入尺寸这个参数对自动驾驶数据的影响在下一节拆开讲先理解一点用 640 能快速跑通用 1280 能明显提升小目标召回。第一次训练建议用 640 跑通链路保存一个基线再把同样的数据用 1280 训练一个增强版。--batch不一定要自己算。你如果不知道当前 GPU 能撑住多大 batch可以直接写--batch -1YOLOv5 会自动做一次显存探测给出一个安全 batch 并打印出来。这个值对新手来说比拍脑袋可靠。训练 100 轮看起来时间成本很高但用 s 模型、640 输入、batch 16在单张 3090 上一般几小时完成很多场景甚至可以跑到 150200 epoch。自动驾驶数据集还要额外考虑一个参数--workers。高分辨率道路图解码很吃 CPU如果机器上的线程数足够把--workers 8加上可以减少 GPU 空等。但如果 CPU 核数不多workers 开太大反而会让数据加载变得不稳定一般设置在 48 之间比较合适。3.3 训练过程中要盯的三个输出loss 曲线、mAP 曲线和验证集预测图训练一启动终端会滚动输出每个 epoch 的指标。大概长这样Epoch GPU_mem Box_loss Obj_loss mAP0.5 30/100 15.2G 0.0583 0.0299 0.721这里真正要关心的是三件事。第一Box_loss 和 Obj_loss 是否在稳定下降。如果 loss 一开始就震荡到天上去先检查标签格式大概率是坐标出了范围。第二mAP0.5 从第 30 到第 100 轮还能不能继续涨。如果 60 轮以后 mAP 直接横盘不是模型坏了而是当前 imgsz 和模型容量到了瓶颈该考虑调大输入或换更大模型。第三验证集预测图。YOLOv5 在训练期间会周期性把验证集的标注结果画成图片存放在runs/train/road11_baseline/下面。别只盯着曲线要打开其中的验证样本图挨个看两件事标注框是不是把目标包得紧类别编号有没有对。很多类别错位问题看这张图一眼就会暴露。人眼抽查永远比改参数快。训练结束后会自动生成weights/best.pt和weights/last.pt。选 best 的原则看 mAP不要只看 loss因为 loss 反映的是整体拟合程度mAP 更能代表目标检测效果。下一章讲的就是怎么用验证集把模型底细看清楚。4. 验证集能提供的真实信号mAP、混淆矩阵与漏检复盘4.1 训练集之外的那部分只有 val 的情况下我建议再切一个 hold-out这份数据集在标题里写明了包含训练集、验证集也就是 train 和 val 已经划分好。但实际做项目时我仍然建议再从 val 里留出一小批图片作为不参与任何参数选择的“最终审计集”。原因很朴素训练过程中我们会反复拿 val 去选 best.pt、去调阈值、去看指标时间一长模型会慢慢“记住”验证集。自动驾驶数据尤其危险相邻两帧画面几乎一样即便划分时已经错开了文件仍然可能保留同一段道路的连续帧这会让 mAP 虚高。简单做法是移动一部分 val 文件到 test 目录mkdir -p /data/road_dataset/images/test /data/road_dataset/labels/test mv /data/road_dataset/images/val/9000*.jpg /data/road_dataset/images/test/ mv /data/road_dataset/labels/val/9000*.txt /data/road_dataset/labels/test/移动的原则不是随机抽而是按时间戳或路径顺序隔段抽。最接近真实部署的做法是把同一路段的连续帧尽量留在同一侧避免 train 和 test 出现同路段相似帧。这是自动驾驶数据集划分的关键点之一不能只靠随机函数。切成 test 之后data.yaml 可以加一行test: images/test。YOLOv5 的 val.py 读取 test 字段的方式和你预想的可能不完全一样有的版本默认 val 字段优先稳妥起见平时实验用 val 选超参最后做最终报告时再临时把--data指向一个只含 test 的 yaml 文件。4.2 用 val.py 把验证集跑出真实数字置信度阈值会骗你验证过程不复杂命令写法决定结果的可信度。python val.py \ --data /data/road_dataset/data.yaml \ --weights runs/train/road11_baseline/weights/best.pt \ --img 1280 \ --conf 0.001 \ --iou 0.6关键参数是--conf 0.001。很多人默认用 0.25 去验证结果 recall 特别低mAP 也偏低其实模型不一定差只是设置阈值太高把大量低置信度的小目标预测过滤了。验证时要把置信度拉到很低让模型把所有“怀疑但不敢确定”的框都报出来再计算 mAP。训练时用的是 640 输入验证时却用 1280 输入相当于把分辨率提高了。如果验证 mAP 明显高于训练时的验证 mAP说明模型对分辨率有依赖正式部署也要用大图推理。命令的输出会包含一组指标Precision、Recall、mAP0.5、mAP0.5:0.95。对自动驾驶 11 类场景我更在意mAP0.5:0.95。这个指标对框位置精度更敏感小目标比如远处的交通灯、路牌只要框偏差一点IoU 到不了 0.75 分就会被扣掉。只看 mAP0.5 很容易觉得模型已经够了放到真实路上发现问题一大堆。同时在runs/val/目录下会生成F1_curve.png、PR_curve.png等曲线。F1 曲线能看懂最好简单来说就是找 precision 和 recall 的平衡点在哪里。如果 F1 曲线在高置信度区域掉得很惨说明模型很犹豫这类问题大概率不是模型参数问题而是训练数据的目标过小或标注不清晰。4.3 看混淆矩阵11 类里哪几对最容易互相伤害val.py 输出里最值得细看的一张图是confusion_matrix.png。自动驾驶道路目标里有几对类别视觉上非常接近比如 traffic_light 和 traffic_signbicycle 和 motorcycle还有 rider 和 person。混淆矩阵能直观体现哪些类别互相抢框某个类别矩阵格子特别亮说明模型经常把 A 判成 B。看到混淆矩阵里有明显的互相串类不要急着去调 anchor 或者改 loss 权重。第一步是回去看标签数据确认是不是类别编号本身错了。如果编号没问题再看两个类的样本量。11 类数据集里如果 car 有上万框而 traffic_light 只有几百框模型天然会把少数类往多数类的方向推这时可以在训练参数里加大--cls的权重。YOLOv5 的--cls默认是 0.5用来控制分类损失占比类别不平衡明显时调到 0.71.0 是有作用的但调太高会让框回归变差要结合 mAP 变化确认。还有一个容易被忽略的点混淆矩阵里最底下那行代表“背景被误判为目标”的 false positive。如果这行数值偏高说明模型把路面、路肩、护栏当成了车或行人。出现这种情况往往不是模型需要调参而是背景帧太少对应到第二章说的空 txt 文件问题。5. YOLOv5 数据集避坑指南训练自己的数据集时最容易翻车的 4 个细节5.1 现象训练 loss 正常下降mAP 却接近 0验证图里所有框类别都错这不是模型没学好而是标签的类别编号和 data.yaml 的 names 顺序对不上。我见过不少数据标注工具里 car 排在第一个导出时 car0数据集组织者认为 person 应该排在第一个于是 data.yaml 里 person0。训练时模型按 txt 里的数字学验证时按 data.yaml 名字打印于是所有类别全错位。原因txt 里的整数类别 id 是“按标注导出顺序”写的data.yaml 是“按人类可读顺序”写的两边没有对齐。解决训练前先跑一个统计脚本把每个类别 id 的出现次数打出来然后与 data.yaml names 对照。具体可以用第五章末尾的体检脚本先把分类 id 数量打印出来。如果发现数量分布和你的预期类别顺序不一致直接把 data.yaml 里的 names 顺序改成和 txt 一致不要改 txt因为重写几千个 txt 反而容易引入新错。5.2 现象训练日志里大量图片被跳过模型误检暴增之前提到过空标签问题。在整理数据集时不少人看到labels/train/里那几百个空 txt觉得没用批量删掉了。结果 YOLOv5 扫描 image 时发现“图在label 文件不在”于是把整张图跳过。更麻烦的是如果只删了部分空 txt那相当于负样本数量骤减模型没见过足够的背景帧就会在验证阶段把道路边缘、护栏误检成目标。原因空 txt 是 YOLO 格式里合法的“背景样本”很多整理脚本却把它当成垃圾文件清理掉了。解决不要删除 labels 目录下的空 txt并保证 images/train 和 labels/train 文件数量一致。可以用一句话检查find dataset/images/train -name *.jpg | wc -l find dataset/labels/train -name *.txt | wc -l两个数字必须一样。如果不一致缺 txt 的图片要补建空文件多出来的 txt 要检查是不是图片丢失。这一步是自动驾驶数据准备的底线。5.3 现象汽车、行人检测效果不错但交通灯和路牌几乎全漏对比前面的 mAP 指标car、truck 的 AP 能到 0.8 以上traffic_light 却只有 0.1。这种现象对应的是目标尺度问题。1920×1080 的原图里一个交通灯可能只有 18×12 像素。当训练输入设为 640×640YOLOv5 会在 letterbox 之后把整个图缩到 640 宽这个交通灯在输入图上只剩 6×4 像素几轮下采样以后在特征图里连一个格子都占不满。原因--img 640加上下采样倍数让小目标在骨干网络里失去信号同时标签里的小目标框边长即使不缩到 0也会因为 anchor 匹配不上而不参与正样本计算。解决把训练和验证分辨率提高到 1280 或更大显存不够就先把 batch 降到 8。下面这个表是自动驾驶数据里比较有经验的取值imgsz显存压力小目标表现适用阶段640低明显丢失快速验证 pipeline1280中高明显改善正式训练1536/1920高全部保留目标极小且资源充足另外标签里如果一个目标的宽或高小于 2 像素即使放到 1280 也很难学好可以考虑直接过滤掉或者在数据预处理阶段把这类目标剔除避免训练时产生无意义正样本。5.4 现象验证集 mAP 很高一上真实视频就露馅这几乎成了自动驾驶数据集的一个“玄学”问题验证指标 0.85拿到城市道路实拍视频上全是漏检。常见原因不是模型不行而是验证集划分出了问题。如果划分 train/val 时采用随机保留 20% 文件的方式而文件是同一台车上连续拍摄的视频帧按序号自动命名那么 train 和 val 里大概率存在大量同一路段的相似帧。模型在 train 里见过几乎相同路面等于 val 在“开卷考试”。原因随机划分破坏了自动驾驶数据的时间连续性造成“数据泄漏”。解决验证集不要按文件名随机抽要按时间片段抽。例如每 10 帧取 1 帧做验证或者按拍摄路段分开。至少要做到 train 和 val 的图片不来自同一段连续 3 秒的视频。如果你只是拿这批数据做 baseline也要把这个问题写进实验记录里明确 val 数字只能做相对比较不能代表真实道路表现。6. 让 11 类道路数据集发挥最大价值训练前跑一次标签体检训练后用难例回喂前面讲完训练和验证最后落在一个我自己每份数据集都会做的动作训练前先对标签做一次体检。核心代码只有一个脚本跑完你就知道该用什么 imgsz、哪些类别数量不够、哪些目标小到没法学。# 数据体检脚本统计每类目标数量与最小目标像素尺寸 import glob import os label_dir /data/road_dataset/labels/train img_w, img_h 1920, 1080 # 换成你数据的实际分辨率 stats {} for txt_path in glob.glob(os.path.join(label_dir, *.txt)): with open(txt_path, r) as f: for line in f: parts line.strip().split() if len(parts) 5: continue cls_id int(parts[0]) box_w float(parts[3]) * img_w box_h float(parts[4]) * img_h if cls_id not in stats: stats[cls_id] {count: 0, min: 1e9, max: 0} stats[cls_id][count] 1 stats[cls_id][min] min(stats[cls_id][min], box_w, box_h) stats[cls_id][max] max(stats[cls_id][max], box_w, box_h) for cls_id in sorted(stats): s stats[cls_id] print(fclass {cls_id:2d} count{s[count]:6d} min_box{s[min]:6.1f}px max_box{s[max]:6.1f}px)如果某类别的min_box大量低于 8 像素这类目标即使人眼能看到YOLOv5 也很难学需要提高--img或考虑数据增强里的马赛克策略。如果 11 个类别里某几类 count 只有三位数训练时会因为样本不足导致 AP 低建议在训练前做类别过采样或者接受这种类别的表现天花板。训练出一个可接受模型后还有一个常见的进阶玩法用 val.py 跑出的低置信度预测图作为硬例挖掘素材。把验证集里 recall 最低的图和类别组合挑出来回到原始数据里找同类样本补充到训练集中训练一个更强版本。对 11 类道路检测来说traffic_light 和 traffic_sign 往往是最值得挖的两类因为它们尺寸小、视觉接近模型先天容易犯错。做这个技术方向值不值得投入我的答案很明确如果目标是快速搭起一个自动驾驶感知基线或者做 YOLOv5 系列对比实验这类数据集的性价比是最高的。它把数据工程中 70% 的体力活做完了剩下的 30% 是你要学会读懂它的标签、验证集和隐含假设。我的习惯是第一轮绝不调任何训练超参先用默认配置跑 30 个 epoch只做一件事盯着数据确认每个类别的框和编号、确认验证集的 mAP 是稳定可信的。数据集这一层黑了后面所有后处理和调参都是在给错模型“补妆”。把数据体检这一关守住你的 YOLOv5 训练基本不会翻大车。希望帮到你。本文还有配套的精品资源点击获取
返回列表