ARTICLE DETAIL

资讯详情

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

YOLO泄露目标数据集实战:VOC/COCO/YOLO标签格式转换与训练避坑指南

YOLO泄露目标数据集实战:VOC/COCO/YOLO标签格式转换与训练避坑指南 简介本资源为面向目标检测学习者的YOLO泄露目标数据集聚焦真实场景下的泄露目标识别任务适合正在做课程设计、毕业设计或算法练手的中初级开发者使用。数据经labelimg精细标注标注框质量较高并同步提供vocxml、cocojson与yolotxt三种格式标签分别存放于不同文件夹可直接接入YOLO系列模型训练。压缩包共约2000个文件以1000个xml标注文件和990个txt标签文件为主另含少量html说明、py脚本与yaml配置整体约33.75MB。资源附带数据集划分脚本可按需切分训练集、验证集与测试集并配有YOLO环境搭建及训练案例教程覆盖Windows与Linux两种平台帮助读者快速跑通训练流程、理解数据组织方式。目前已有229人学习下载适合希望低成本获取高质量标注数据并快速验证检测方案的学习者。1. 拿到一个 YOLO 泄露目标数据集先别急着 train你从群里或者某个网盘链接里拖下来一个压缩包名字叫「YOLO泄露目标数据集(含1000张图片)对应voc、coco和yolo三种格式标签划分脚本训练教程.rar」。解压之后大概率是一堆文件夹JPEGImages、Annotations、images、labels、scripts还有一份 README 或者 txt 说明。很多人第一反应是直接yolo detect train dataxxx.yaml然后发现路径对不上、类别对不上、标签格式对不上白白浪费一晚上。这个数据集的核心价值不在于那 1000 张图本身而在于它同时给了 VOC、COCO、YOLO 三种标签格式和一份划分脚本。这意味着你可以用它来验证自己的数据管线是否健壮同一批图三种格式互相转换训练结果应该一致。如果你正在入门 YOLO 目标检测或者想找一个带完整标注的小规模数据集来跑通训练、验证、推理全流程这个包是合适的起点。但前提是你得先把格式对齐这件事做对。2. 三种标签格式到底差在哪VOC、COCO、YOLO 的坐标与文件结构2.1 VOC 格式XML 描述每一张图VOC 格式的核心是每张图片对应一个 XML 文件文件名与图片名一致放在 Annotations 目录下。XML 里记录了图片尺寸、目标类别和边界框的左上角、右下角坐标。一个典型的 VOC XML 长这样annotation folderJPEGImages/folder filename000001.jpg/filename size width640/width height480/height depth3/depth /size object nameperson/name bndbox xmin112/xmin ymin96/ymin xmax320/xmax ymax400/ymax /bndbox /object /annotation坐标是绝对像素值原点在左上角。VOC 格式的好处是可读性强坏处是文件多、解析慢而且不同数据集对difficult、truncated这些字段的处理不一致。2.2 COCO 格式一个 JSON 管所有COCO 格式把所有标注塞进一个 JSON 文件结构分images、annotations、categories三块。images里记录图片 id、文件名、宽高annotations里记录image_id、category_id、bbox[x, y, width, height]绝对像素和segmentation如果有分割。categories是类别映射表。{ images: [{id: 1, file_name: 000001.jpg, width: 640, height: 480}], annotations: [ {id: 1, image_id: 1, category_id: 1, bbox: [112, 96, 208, 304], area: 63232, iscrowd: 0} ], categories: [{id: 1, name: person, supercategory: none}] }注意 COCO 的 bbox 是[x, y, w, h]不是[xmin, ymin, xmax, ymax]。这个差异是转换时最容易翻车的地方。2.3 YOLO 格式归一化后的 txtYOLO 格式每张图对应一个 txt 文件每行一个目标class_id x_center y_center width height。所有值都是相对于图片宽高的归一化值范围 0 到 1。class_id 从 0 开始连续编号。0 0.3375 0.5167 0.3250 0.6333这行表示类别 0中心点 x 在 33.75% 宽度处中心点 y 在 51.67% 高度处框宽占 32.5%框高占 63.3%。YOLO 格式最紧凑但可读性最差而且类别 id 必须和 data.yaml 里的 names 顺序严格对应。2.4 三种格式的坐标换算关系格式坐标类型框表示文件组织VOC绝对像素xmin, ymin, xmax, ymax每图一个 XMLCOCO绝对像素x, y, width, height单个 JSONYOLO归一化 0-1x_center, y_center, width, height每图一个 txt换算公式YOLO 的x_center (xmin xmax) / 2 / img_wwidth (xmax - xmin) / img_w。反向换算时乘回图片宽高即可。COCO 的x就是xminwidth就是xmax - xmin。3. 用划分脚本把 1000 张图切成 train/val/test参数怎么设、路径怎么改3.1 先看清目录结构再动手拿到数据集后先别运行任何脚本。用tree或者find看一眼目录层级find . -maxdepth 2 -type d | sort常见结构有两种一种是JPEGImages放图、Annotations放 XML、labels放 YOLO txt另一种是images/train、images/val、labels/train、labels/val已经分好。划分脚本通常假设第一种结构然后按比例复制或移动文件到第二种结构。3.2 划分脚本的核心逻辑与参数一个可靠的划分脚本至少要做三件事固定随机种子、按比例分层抽样、同时处理图片和标签。下面是一个我常用的划分脚本骨架import os import random import shutil from pathlib import Path # 参数区按实际情况改 IMG_DIR Path(JPEGImages) LABEL_DIR Path(labels) # YOLO txt 目录 OUT_DIR Path(dataset) TRAIN_RATIO 0.8 VAL_RATIO 0.1 TEST_RATIO 0.1 SEED 42 random.seed(SEED) # 收集所有图片文件名不含扩展名 stems [p.stem for p in IMG_DIR.glob(*.jpg)] random.shuffle(stems) n len(stems) n_train int(n * TRAIN_RATIO) n_val int(n * VAL_RATIO) splits { train: stems[:n_train], val: stems[n_train:n_train n_val], test: stems[n_train n_val:] } for split, names in splits.items(): img_out OUT_DIR / images / split lbl_out OUT_DIR / labels / split img_out.mkdir(parentsTrue, exist_okTrue) lbl_out.mkdir(parentsTrue, exist_okTrue) for stem in names: shutil.copy(IMG_DIR / f{stem}.jpg, img_out / f{stem}.jpg) lbl_src LABEL_DIR / f{stem}.txt if lbl_src.exists(): shutil.copy(lbl_src, lbl_out / f{stem}.txt) else: print(f警告{stem} 没有对应标签文件)逻辑说明先收集所有图片的 stem用固定种子打乱再按 8:1:1 切分。复制而不是移动保留原始文件作为后悔药。如果标签缺失打印警告而不是静默跳过。参数说明TRAIN_RATIO在 1000 张规模下建议 0.8验证集和测试集各 0.1。如果数据类别极不均衡需要改成按类别分层抽样否则某个类别可能全被分到训练集。SEED固定后每次划分结果一致方便复现。3.3 划分完必须做的三项检查第一检查每个 split 的图片数和标签数是否一致for d in dataset/images/*/; do echo $d: $(ls $d | wc -l); done for d in dataset/labels/*/; do echo $d: $(ls $d | wc -l); done第二随机抽几个标签文件确认 class_id 没有越界。用awk提取每行第一个字段看最大值cat dataset/labels/train/*.txt | awk {print $1} | sort -n | uniq -c第三确认没有空标签文件混入。空 txt 在 YOLO 训练里会被当成负样本如果数据集里本来没有负样本空文件会导致模型学到错误的背景。4. 从 VOC 或 COCO 转到 YOLO转换脚本与四个边界坑4.1 VOC 转 YOLO 的完整脚本import xml.etree.ElementTree as ET from pathlib import Path from PIL import Image VOC_DIR Path(Annotations) IMG_DIR Path(JPEGImages) OUT_DIR Path(labels) OUT_DIR.mkdir(exist_okTrue) # 类别映射必须和 data.yaml 里的 names 顺序一致 CLASS_MAP {person: 0, car: 1, dog: 2} for xml_path in VOC_DIR.glob(*.xml): tree ET.parse(xml_path) root tree.getroot() img_name root.find(filename).text img_path IMG_DIR / img_name if not img_path.exists(): print(f图片缺失{img_name}) continue with Image.open(img_path) as im: w, h im.size lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in CLASS_MAP: continue cls_id CLASS_MAP[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 裁剪到图片范围内 xmin max(0, min(xmin, w)) xmax max(0, min(xmax, w)) ymin max(0, min(ymin, h)) ymax max(0, min(ymax, h)) if xmax xmin or ymax ymin: continue xc (xmin xmax) / 2 / w yc (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) out_file OUT_DIR / (xml_path.stem .txt) out_file.write_text(\n.join(lines))逻辑说明逐 XML 解析读图片真实宽高把 VOC 的绝对坐标转成 YOLO 归一化坐标。类别映射表必须和训练时的 data.yaml 一致否则模型学到的类别是错的。参数说明CLASS_MAP里的 id 从 0 开始连续。如果 VOC 里的类别名有大小写差异比如Person和person需要先统一。裁剪到图片范围是防止标注框超出边界导致归一化值大于 1。4.2 COCO 转 YOLO 的关键差异COCO 的 JSON 里 bbox 是[x, y, w, h]转 YOLO 时xc (x w / 2) / img_w yc (y h / 2) / img_h bw w / img_w bh h / img_h注意 COCO 的category_id不一定从 0 开始连续需要自己建映射表。另外 COCO 的iscrowd1的标注通常要跳过因为 YOLO 不直接支持 crowd 区域。4.3 四个边界坑第一个坑图片尺寸读错。用 PIL 读图时如果图片是 CMYK 模式或者有 EXIF 旋转信息宽高可能和实际显示不一致。解决方法是统一用Image.open().size并在转换前把所有图片转成 RGB。第二个坑坐标越界。VOC 标注里偶尔出现xmax大于图片宽度的情况归一化后值大于 1YOLO 训练时不会报错但会影响收敛。必须在转换时裁剪。第三个坑类别 id 不连续。VOC 里可能只有person和car但 CLASS_MAP 写成了{person: 0, car: 2}中间缺了 1。YOLO 会认为有 3 个类别训练时类别 1 永远没有样本。第四个坑文件名大小写。Linux 下000001.JPG和000001.jpg是两个文件但 VOC XML 里写的可能是大写实际图片是小写。转换脚本里要做大小写兼容匹配。5. 用这份数据跑通 YOLO 训练data.yaml 写法与必调参数5.1 data.yaml 的最小正确写法path: /home/user/dataset train: images/train val: images/val test: images/test nc: 3 names: [person, car, dog]path是数据集根目录train、val、test是相对路径。nc必须等于len(names)且和标签里的 class_id 最大值加一一致。如果标签里出现了 class_id 为 3 但nc写的是 3训练会直接报索引越界。5.2 1000 张图规模下的训练参数yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ seed42 \ projectruns/train \ nameexp1参数说明model选 nano 版本1000 张图用大模型容易过拟合。epochs100配合patience20验证集指标 20 轮不提升就早停。batch16在 8G 显存下跑 640 分辨率基本够用显存不够就降到 8。lr00.01是 SGD 的初始学习率如果 loss 震荡明显可以降到 0.001。seed42固定数据加载顺序方便对比不同实验。5.3 训练过程中看什么指标重点看三个train/box_loss是否稳定下降val/box_loss是否跟着降metrics/mAP50是否在上升。如果 train loss 降但 val loss 升说明过拟合需要加数据增强或者减模型容量。如果两个 loss 都不降检查学习率是否太大或者标签是否有问题。6. 避坑与排查标签、路径、显存、评估的五个血泪教训6.1 现象训练启动就报 “No labels found”原因data.yaml 里的train路径指向了图片目录但 YOLO 默认会在同级的labels目录找标签。如果你的标签不在images/train同级的labels/train就会找不到。解决要么把标签放到 YOLO 期望的目录结构要么在 data.yaml 里显式指定labels路径。最稳妥的做法是保持dataset/images/train和dataset/labels/train的对称结构。6.2 现象mAP 一直是 0原因类别 id 对不上。标签里的 class_id 是 0、1、2但 data.yaml 里的 names 顺序写错了或者 nc 写成了 4。另一种可能是标签文件里的坐标全是 0转换脚本没写对。解决用awk {print $1} labels/train/*.txt | sort -u看实际出现的 class_id和 data.yaml 的 names 索引逐一对照。再抽一个标签文件手动算一下归一化坐标是否在 0 到 1 之间。6.3 现象训练到一半 CUDA out of memory原因batch设大了或者imgsz设成了 1280 但显存只有 6G。YOLO 在训练过程中会缓存数据增强后的图像实际显存占用比推理高不少。解决先把batch降到 8 或 4再把imgsz降到 512。如果还不行开ampFalse关掉混合精度或者用workers2减少数据加载进程。6.4 现象验证集指标比训练集低很多原因1000 张图如果按 8:1:1 划分验证集只有 100 张指标波动会很大。另外如果划分时没有固定种子每次运行验证集都不一样指标没法对比。解决固定SEED并且用分层抽样保证每个类别在 train/val/test 里的比例一致。如果某个类别样本极少考虑用过采样或者数据增强来补。6.5 现象推理时框的位置整体偏移原因训练时用的imgsz和推理时不一致YOLO 会做 letterbox 缩放如果推理时没保持同样的缩放逻辑框会偏。另一种可能是标签转换时图片宽高读错了比如用了缩略图的尺寸。解决推理时显式指定imgsz640和训练保持一致。检查转换脚本里读图片宽高的部分确保用的是原图而不是缓存图。7. 用 1000 张图验证数据管线三个进阶技巧第一个技巧用同一批图分别生成 VOC、COCO、YOLO 三种标签然后各训练一次对比 mAP。如果三种格式转换正确最终指标应该在 ±2% 以内。如果差异很大说明某一种格式的转换脚本有 bug。这个方法我一般用来验证新写的数据转换工具比单元测试更直接。第二个技巧把训练好的模型在验证集上跑推理用yolo detect predict输出带框的图然后和原始 VOC XML 里的框做 IoU 对比。如果某些图的 IoU 普遍偏低回去检查这些图的标签是不是有问题。常见的是标注框只框了目标的一部分或者把两个目标标成了一个。第三个技巧用yolo detect val的conf阈值扫描。默认conf0.001时 mAP 最高但实际部署时可能需要conf0.25。在验证集上跑一遍不同 conf 下的 precision 和 recall画一条 PR 曲线找到适合你场景的阈值。1000 张图虽然少但足够看出趋势。我自己的习惯是拿到任何新数据集先花半小时做格式对齐和可视化检查再花十分钟跑一个 10 epoch 的快速训练。如果 10 epoch 内 loss 不降后面 100 epoch 也是白跑。这个习惯帮我省下了无数个通宵调参的夜晚。希望帮到你。本文还有配套的精品资源点击获取
返回列表