YOLO目标检测数据集实战:从三标签格式到迁移训练
简介YOLO泄露目标数据集包含5000张真实场景图片适用于目标检测学习者、算法研究与课程实践可直接用于YOLO系列模型训练。包内含VOC、COCO、YOLO三种格式标签分别存放于不同文件夹配合LabelImg标注信息标注框质量较高另附Linux与Windows版本的环境搭建教程、训练案例教程以及训练集/验证集/测试集划分脚本方便按需拆分数据。压缩包共2000个文件其中XML标签约1986个其余为HTML操作指南、Python划分脚本和TXT列表文件整体体积168.09MB。已有162人学习下载对于需要真实场景检测数据并希望快速上手的用户可省去标注与格式转换时间直接进入模型训练环节。1. YOLO泄露目标数据集5000张真实场景图和三套标签能省多少事做目标检测的人应该都有这种经历想验证一个YOLO改动点翻遍公开数据集要么场景太干净、单类太多要么只有一种标注格式真要拿过来训练还得自己写转换脚本。这份网上流通的YOLO泄露目标数据集解压后是5000张真实场景图片每张都带VOC(xml)、COCO(json)、YOLO(txt)三套标签分别放在独立文件夹里目录设计就是奔着“拿到就能训”去的。对我来说它省掉的不是半小时是一整个晚上。适合四类人刚准备从公开数据集切换到自建数据的目标检测初学者需要多样本快速验证YOLO系列改动的算法工程师做数据划分与标注一致性对比的学生以及只想把环境搭建、训练、测试整条链路跑通一遍的工具党。下面按“标签怎么读 → 脚本怎么切 → 环境怎么搭 → 迁移训练怎么改 → 坑在哪”的顺序把这套资源完整拆一遍。2. 标签格式三件套拆解从VOC的xml、COCO的json到YOLO的txt2.1 同一张图为什么放三份标签三种格式的存储思路差异解压后你会看到 images 目录下是清一色的 jpg另外三个目录分别放 xml、json、txt。同一张图配三份标注不是冗余而是三种流派VOC 是一张图对应一个 xml 文件面向“单张图的物体框描述”COCO 是整个数据集聚合成一个 json面向“数据集级管理、评测和跨数据复用”YOLO 是每张图对应一个 txt面向“训练时加载器直接读取”。格式存储粒度bbox描述是否归一化读取方式VOC(xml)每张图一个.xmlbndbox的xmin、ymin、xmax、ymax否像素值ElementTree/BeautifulSoupCOCO(json)整个数据集一个.jsonbbox为[x, y, width, height]否像素值json/pycocotoolsYOLO(txt)每张图一个.txtclass_id 归一化中心点宽高是除以图片宽高直接按行split实际训练时YOLO 加载器只认 txtxml 和 json 更多是给标注工具、COCO 评测脚本和第三方转换器用的。所以我拿到资源的第一件事是把三套标签各抽一张做对比确认它们描述的是同一个框后面切分脚本才不会切出“图片有、标签无”的残废数据。2.2 三种标签的字段到底长什么样看一张野外场景图 00123.jpg框住一个行人。VOC xml 的核心结构长这样annotation folderleak_dataset/folder filename00123.jpg/filename size width1280/width height720/height depth3/depth /size object nameperson/name difficult0/difficult bndbox xmin87/xmin ymin120/ymin xmax310/xmax ymax455/ymax /bndbox /object /annotationxmin/ymin 是框左上角xmax/ymax 是右下角单位是像素。labelimg 标出来的框通常比较贴边这套数据我看过几十个 xml没发现那种“一整条边都空着”的应付标注。COCO 的 json 把所有图片、类别、标注框聚在一个文件里{ images: [{id: 1, file_name: 00123.jpg, width: 1280, height: 720}], categories: [{id: 1, name: person}], annotations: [ { id: 1, image_id: 1, category_id: 1, bbox: [87, 120, 223, 335], area: 74705, iscrowd: 0 } ] }注意 COCO 的 bbox 是 [左上角x, 左上角y, 框宽, 框高]不是右下角坐标area 是 宽×高categories 的 id 是从 1 开始而不是 0。这些细节在你把 COCO 格式转成其他格式时最容易翻车。YOLO 的 txt 最简洁一行一个框0 0.155078 0.399306 0.174219 0.465278四个数字依次是 类别id、归一化中心点x、归一化中心点y、归一化宽、归一化高。所谓归一化就是像素值除以图片宽高所以这个例子里 0.155078×1280≈198.5和 xml 里的框中心是一致的。2.3 从像素框到归一化坐标换算公式与边界检查如果你手头只有 VOC 或 COCO 标注要转成 YOLO txt核心就四个公式# 输入图片宽 width、高 height像素框 xmin, ymin, xmax, ymax x_center ((xmin xmax) / 2) / width y_center ((ymin ymax) / 2) / height box_w (xmax - xmin) / width box_h (ymax - ymin) / height反过来也可以用 txt 还原像素框做校验。我一般会把每个 txt 都跑一遍这个检查def check_yolo_txt(txt_path, img_width, img_height): for line in open(txt_path, r): parts line.strip().split() if len(parts) ! 5: print(f[格式错误] {txt_path}: {line.strip()}) continue cls_id, x, y, w, h map(float, parts) x1 (x - w / 2) * img_width y1 (y - h / 2) * img_height x2 (x w / 2) * img_width y2 (y h / 2) * img_height if x1 0 or y1 0 or x2 img_width or y2 img_height: print(f[越界] {txt_path}: {line.strip()})这里最常踩的坑是坐标出现负值或者宽高算出来大于1。原因大多是标注时把框拖出了图片边缘或者转换脚本里没做 clip 夹取。遇到这类行直接删掉或者用图片边界截断不要留到训练时让加载器去猜。3. 划分脚本实战把图片和标签按7:2:1拆进新文件夹3.1 三个划分脚本的定位差异资源里给了三个 .py第一次用容易搞混。我按用途重新理一下“训练集、验证集、测试集划分脚本图片标签划分写入新文件夹.py”把全量数据按比例拆成 train/val/test 三份图片和对应标签一起复制到新目录。“训练集、验证集划分脚本图片标签划分写入新文件夹.py”只拆 train/val把 test 留出来做最终评估适合那种对测试集保密要求的实验。“split_train_val生成ImageSets下txt文件划分脚本.py”VOC 风格不移动任何文件只在 ImageSets/Main 下生成 train.txt、val.txt 这类文件清单。train_list.txt一般是所有图片的 stem不带后缀的文件名列表第三个脚本的派生产物也会被其他加载脚本用来构建训练清单。如果你用的是 YOLO 原生训练流程我建议直接用前两个“写入新文件夹”的脚本因为 YOLO 训练读的是目录结构不是 ImageSets 清单。第三个脚本更多是给 VOC 系 Dataloader 或者你自己写的按清单加载的代码用的。3.2 拆分脚本的核心实现复制而不是移动我拆过很多这种“图片标签”打包资源最怕的是脚本把原文件直接 cut 到训练集跑完发现比例错了想重切原数据已经没了。所以好的划分脚本一定用复制。import random import shutil import glob import os # 三个比例加起来必须为1.0想切8:1:1就改成(0.8, 0.1, 0.1) ratio (0.7, 0.2, 0.1) random.seed(42) # 固定随机种子保证两次切分结果一致 images sorted(glob.glob(dataset/images/*.jpg)) random.shuffle(images) total len(images) n_train int(total * ratio[0]) n_val int(total * ratio[1]) parts { train: images[:n_train], val: images[n_train:n_train n_val], test: images[n_train n_val:], } for split_name, img_list in parts.items(): img_dir fsplit_data/{split_name}/images label_dir fsplit_data/{split_name}/labels os.makedirs(img_dir, exist_okTrue) os.makedirs(label_dir, exist_okTrue) for img_path in img_list: stem os.path.splitext(os.path.basename(img_path))[0] shutil.copy2(img_path, img_dir) label_file fdataset/labels/{stem}.txt if os.path.exists(label_file): shutil.copy2(label_file, label_dir) else: print(f[缺标签] {label_file})train/val/test 三个目录互不重叠复制而非移动是“后悔药”切错了随时原数据还在。固定随机种子这点很关键不然每次跑脚本数据分布都变训练结果没法复现。3.3 跑一遍并做一致性校验数量对不上就先别训练脚本改好路径后直接执行然后立刻做两件事数文件、查缺失。python split_train_test_val.py find split_data/train/images -name *.jpg | wc -l find split_data/train/labels -name *.txt | wc -l find split_data/val/images -name *.jpg | wc -l find split_data/val/labels -name *.txt | wc -l两张表数量必须完全相等。如果 labels 少了多半是某张 jpg 本来就没标注或者图片是 .png 但脚本只匹配了 .jpg。我习惯再跑一段交叉校验找出缺标签的图片名for f in split_data/train/images/*.jpg; do stem$(basename $f .jpg) [ -f split_data/train/labels/$stem.txt ] || echo $stem done输出空就是全对有输出就把对应图片和标签单独拎出来看。注意这个数据集的 txt 内容也可能为空文件——空文件代表这张图没目标可以接受但如果你后续要跑 COCO 评测空图会导致 id 匹配不上建议直接滤掉。3.4 划分时最容易犯的错只拷图片、漏了VOC和COCO三划分脚本默认只处理 images 和 labels 目录但资源里还有 xml 和 json。如果你打算用 COCO 格式做评测划分后需要把 JSON 里对应的 image_id 重新映射到新目录。我在这套资源上实际遇到过的情况是脚本拷完图片和 txt忘了把 xml 同步拷到新训练集结果后期想用 VOC 格式对某个类别做单独分析时新目录里根本没有 xml 可用。现象是“验证集 AP 正常但一提 VOC 评测就报 FileNotFoundError”。原因是划分只覆盖了 YOLO loader 依赖的 txt没有同步 VOC 标注。解决办法很朴素划分后把 xml 按同样结构复制一份或者重新从原数据生成不要手动零星补。4. 环境搭建与第一条训练流水线Linux与Windows双路径对照4.1 环境匹配显卡驱动、CUDA和torch三者谁也不能错资源里的两个 HTML 教程分别讲了 Linux 和 Windows 环境搭建内容我大概翻过核心逻辑是一样的先把显卡驱动装对再装对应 CUDA 版本的 PyTorch最后拉项目依赖。这里最容易翻车的是“驱动支持 CUDA 12但 pip 装了一个 CUDA 11 的 torch”结果 torch.cuda.is_available() 永远返回 False。第一步永远是先看驱动nvidia-smi输出右上角的 CUDA Version 是驱动支持的上限不是说你必须装到这个版本而是不能超过它。然后建一个独立 conda 环境别污染系统 Pythonconda create -n yolo python3.8 -y conda activate yolo git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txtWindows 上我一般建议直接用 Anaconda Prompt 而不是 CMD因为 conda 激活环境后 PATH 更好控制。requirements.txt 里默认带的 torch 版本有时不匹配你的 CUDA常见做法是先用 nvidia-smi 确认驱动上限再去 PyTorch 官网选对应的 install 命令。装了之后立刻验一句python -c import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))只要这里输出 True 和你的显卡型号环境就算过关。这一步不做后面跑 train.py 报错你根本分不清是环境问题还是数据问题。4.2 从“能跑demo”到“跑通第一条训练”一张图先过一遍环境就绪后先别急着训自己的数据用项目自带的图片过一遍检测流程确认模型权重能加载、推理管线是通的python detect.py --weights yolov5s.pt --source data/images/bus.jpg --conf 0.25--weights 后面接预训练模型路径--weights 不写时程序会自动下载 yolov5s.pt。YOLO 预训练模型下载是个经常被问的事网络不稳定时自动下载会卡很久我一般手动把 .pt 文件放进项目根目录再指定路径运行。第一次跑会顺手把 labels 也下载一遍coco128保持网络通畅就行。demo 出图之后跑第一条真正的训练用 coco128 这个迷你数据集验证整条流程python train.py --data data/coco128.yaml --weights yolov5s.pt --img 640 --batch-size 16 --epochs 50跑完看 runs/train/exp 下的 results.png如果 loss 曲线在下降说明环境、数据管线、训练循环这三件事都通了。这一步的意义是把“黑匣子”提前戳破后面换自己的数据集出问题时你能确定环境不是变量。4.3 盯住三个lossbox_loss、obj_loss、cls_loss分别看什么训练日志里你会看到三个 loss很多人只看总 loss一旦总 loss 下降就觉得万事大吉。YOLOv5 的 loss 由三部分组成box_loss 是预测框和真实框的 IoU 损失衡量位置准不准obj_loss 是目标置信度损失衡量“这里有没有物体”判断对不对cls_loss 是分类损失只在有目标类别的前提下计算。指标含义下降异常时要查什么box_loss预测框与GT框的位置偏差标签坐标是否越界、归一化是否错误obj_loss前景/背景判断错误负样本太少或太多、锚框尺寸不匹配cls_loss类别判断错误names顺序是否和txt里class_id对应训练过程中可以用 TensorBoard 实时盯tensorboard --logdir runs/train浏览器打开 http://localhost:6006 后重点看 val 侧三个 loss 是不是和 train 侧同步下降。如果 train loss 降了 val loss 反涨优先怀疑过拟合或标签噪声别急着加数据增强。5. 迁移到自己的数据集yaml配置、预训练权重与五类常见问题排查5.1 把数据集描述写进data.yaml四个字段决定成败用这套资源训练时第一步是写一个自己的 data.yaml。很多人直接复制项目自带 coco.yaml忘了改 nc 和 names训练出来的模型类别全是错的。train: /home/yourname/dataset/split_data/train/images val: /home/yourname/dataset/split_data/val/images nc: 1 names: [person]python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch-size 16 --epochs 200train 和 val 指向的是 images 目录YOLO 会自动去同级的 labels 目录找 txt所以划分脚本里 images 和 labels 必须保持同级的兄弟目录关系。nc 是类别总数names 列表里的顺序就是 txt 里 class_id 对应的标签名这里的顺序错一个整个训练就全错了。提示如果你换到 YOLOv8ultralytics 的 data.yaml 写法多一个可选的 path 字段可以写成 path: 数据集根目录然后 train: images/train。四字段语义不变。5.2 用预训练模型继续训练冻结与超参数选择从零训练一个 YOLO 在大数据集上要几百个 epoch你的数据只有几千张正确姿势是从官方预训练权重继续迁移而不是随机初始化。python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch-size 16 --epochs 200 --freeze 10 --lr0 0.01--freeze 10 表示冻结前 10 层让模型先只微调后面的检测头适合数据量少、怕把预训练特征学坏的情况。--lr0 初始学习率我一般按 batch size 来调batch 16 用 0.01batch 64 用 0.04 左右batch 8 就降到 0.005。这个比例不算精确但能避开大多数人遇到的学习率过大导致的 NaN 问题。显存不够时--cache 可以把图片提前缓存进内存加速读取但会吃内存--workers 不要拉太高Windows 上 workers 超过 4 经常死进程我一般设 4 或 8。batch 实在上不去就把 --img 从 640 降到 480影响通常比降 batch 小。5.3 五类高频问题排查5.3.1 Loss打到一半变NaNBN崩溃与学习率失衡现象训练前几十个 epoch 正常某轮开始 loss 变成 nan之后就再也回不来。原因最常见是学习率过大加上 batch 太小BatchNorm 的统计量在少样本上波动过大最终跑飞另一种是模型权重里出现了 inf和标签里的极端坐标也有关系。解决先把 --lr0 降到 0.005 或更低重开一轮batch 至少提到 16如果显存不够就减 --img。还有一个我常用的办法是给第二个 epoch 设个检查点训练满 2 个 epoch 就去看 loss正常再让它跑长。别挂机一整晚早上起来才发现第 3 轮就 NaN 了。5.3.2 训练一切正常但mAP是099%是标签和names对不上现象loss 能正常下降但 val 侧 Precision、Recall、mAP 全是 0results.png 里 P 曲线一条直线贴地。原因txt 里的 class_id 大于等于 nc或者超出 names 列表范围。比如数据里有 3 个类别你 data.yaml 只写了 nc: 1于是 id2 的框全部被当成越界样本丢掉。解决先跑一个标签扫描脚本把最大类别 id 打印出来import glob, os max_cls -1 for txt in glob.glob(dataset/labels/*.txt): with open(txt) as f: for line in f: if line.strip(): cls_id int(line.split()[0]) if cls_id max_cls: max_cls cls_id print(f最大类别id: {max_cls})如果输出比 nc-1 大要么改 yaml 的 nc要么检查是不是标注时类名映射错了。这个问题在“泄露数据集”里不太会出现但你自己用 labelimg 扩标一批数据时基本一定会遇到。5.3.3 混淆矩阵总合不唯一的“玄学”先别急着质疑训练现象训练完打开 confusion_matrix.png发现每一行数字加起来不等于该类的真实目标数甚至差很多。原因YOLO 的混淆矩阵不是按“每个GT只被统计一次”的传统方式画的。GT 和预测框做贪心 IoU 匹配一个 GT 只匹配一个预测框匹配失败就归入背景列多余的预测框则计入背景行。所以行总和 该类GT数 被错误分到该类的FP数列总和也类似看起来“账对不上”是正常现象。解决看混淆矩阵时只盯着对角线占比和背景列不用纠结行总和。如果对角线明显偏低、背景列很高说明模型漏检严重先查数据难度和阈值不要怀疑训练框架。5.3.4 显存差一口气降img、降batch还是换模型现象训练命令敲下去几秒就报 CUDA out of memory尤其 batch 开大或开了 --cache 之后。原因显存占用大头是 feature map 和梯度img 尺寸是平方级影响batch 是线性影响。解决优先降 --img 从 640 降到 480还不够就把 batch 从 16 降到 8再不够就换小模型yolov5s 换到 yolov5n。不要上来就盯着 batch 改img 的收益大得多。如果开了 --cache确认内存不是显存先爆。5.3.5 ImageSets里的txt和后缀名一个最隐蔽的数据路径坑现象用 split_train_val 生成的 ImageSets/Main/train.txt 训练报 FileNotFoundError 或者图片和标签对不上。原因这种 txt 里存的是不带路径、不带后缀的 stem 文件名而部分加载代码默认拼接 .jpg。一旦图片实际是 .png拼接出的路径不存在就会跳过这张图数据量悄然变少。解决把 stem 列表先和真实文件名做一次映射或者干脆不用 ImageSets直接跑三划分脚本把文件复制进目录。我自己的习惯是train_list.txt 只用来存档不作为训练时的数据源因为 YOLO 的 Dataloader 吃目录比吃清单稳得多。6. 训练完别急着收工两分钟自查与验证习惯6.1 六步自查流程我每次换数据集都强制走一遍这套流程从一次惨痛经历里总结的花了三天调参最后发现是 val 集里混进了一张和训练集同名不同内容的图导致验证指标一直在抖。从那以后每次训练收尾我都会按这个清单过一遍步骤做什么命令/工具1标签范围校验check_label.py确认 class_id nc2三格式一致性抽查随机抽5张图对比xml/json/txt框坐标3划分比例复核find wc -l 对比 train/val/test 数量4yaml路径核对cat data.yaml确认 train/val 指向存在5loss曲线盯三轮看 results.png 前三个 epoch 是否下降6测试集可视化detect.py 跑随机20张图看框和置信度第6步的命令很简单python detect.py --weights runs/train/exp/weights/best.pt --source ./test_images --conf 0.25跑完打开 runs/detect/exp 里的可视化图。我会重点看两类问题一是漏检图上明显有目标但没框二是重框一个目标出两个交叠框。前者去查标签和召回率后者去调 NMS 阈值和 conf 阈值。部署时用的 conf 阈值和训练时不一样一般部署会提到 0.4 以上所以可视化阶段先别急着扣阈值看模型本身的检出上限。这套六步法帮我躲过至少十次无效训练尤其是第一步和第六步加起来不到两分钟但能省掉一整天的“调参玄学”。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →