资讯详情

资讯详情

YOLO训练数据集三格式齐备:VOC/COCO/YOLO互转与可复现训练链路

简介本资源是面向计算机视觉初学者与YOLO目标检测实践者的高质量泄露目标数据集配套包解决真实场景下小目标检测模型训练缺乏标注规范、格式兼容与工程化支持的痛点。资源包含5000张真实场景高清图片及完整标注涵盖VOC1986个XML、COCOJSON和YOLOTXT三种主流格式标签可直接接入YOLOv5/v8等主流框架训练同时提供3个Python划分脚本支持按比例生成ImageSets或独立文件夹结构及Windows/Linux双平台环境搭建与训练教程含HTML文档6份、核心脚本3个覆盖从数据准备到模型微调的全流程。资源共2000个文件总大小168.09MB结构清晰、开箱即用。已有162人学习下载特别适合课程实验、课程设计及入门级科研项目快速启动。1. 这不是“泄露”而是你缺了5000张图的YOLO训练弹药VOC/COCO/YOLO三格式齐备划分脚本可复现训练链路你搜“YOLO数据集”时刷到的往往是零散的GitHub链接、失效的网盘分享、或者只有图片没标签的“半成品”。而这个标题里藏着一线工程师最头疼却不敢明说的现实没有干净、对齐、可直接喂进训练器的数据集再新的YOLOv8/v10模型也训不出泛化力。它不是“泄露”——是有人把5000张真实场景图非合成、非水印、无版权争议配上三套标准标签VOC XML COCO JSON YOLO TXT连划分比例train/val/test、目录结构、甚至train.py里--data参数怎么填都给你写死了。适合两类人刚跑通ultralytics但卡在数据准备的新手和要快速验证新backbone或loss函数、不想花3天写数据清洗脚本的老手。它不解决算法创新但能让你今天下午就看到第一个mAP曲线——这才是YOLO落地的第一道生死线。2. 从压缩包解压到训练启动四步走通完整数据流2.1 解压后目录结构必须长这样别让路径错误毁掉前三小时拿到.rar后不要双击用WinRAR图形界面直接解压到桌面——这是新手翻车第一高发点。Windows资源管理器默认解压会嵌套一层同名文件夹导致后续所有路径错位。正确做法是# Linux/macOS 或 Windows WSL 中执行推荐 unrar x YOLO泄露目标数据集.rar ./dataset_root/ # 若无unrar命令先安装apt install unrarUbuntu或 brew install unrarmacOS # Windows PowerShell管理员权限运行 Expand-Archive -Path YOLO泄露目标数据集.rar -DestinationPath .\dataset_root\ -Force解压后必须确认根目录下存在且仅存在以下4个一级子目录images/含5000张.jpg命名如000001.jpg005000.jpgAnnotations_voc/5000个.xml与images/同名一一对应符合PASCAL VOC 2007 Schemaannotations_coco/单个instances_train2017.json含全部5000图的COCO格式标注labels_yolo/5000个.txt每行class_id center_x center_y width height归一化坐标提示用ls images/ | head -n 3和ls labels_yolo/ | head -n 3快速核对前3张图是否同名。若images/000001.jpg存在但labels_yolo/000001.txt缺失说明解压损坏需重下。2.2 用附带划分脚本生成YOLO标准目录train/val/test三份不重叠YOLO官方要求数据集按train/,val/,test/三级目录存放图片和标签且train/和val/必须严格分离test/可选。附带的split_dataset.py不是简单随机切分——它按类别分布均衡采样避免某类在val集中过少导致mAP虚高。执行前先确认Python环境已装scikit-learnpip install scikit-learn然后运行脚本关键参数说明见后# split_dataset.py 内容精简版实际脚本含完整注释 import os import shutil import numpy as np from sklearn.model_selection import train_test_split # 配置区务必按需修改 IMAGE_DIR ./dataset_root/images LABEL_DIR ./dataset_root/labels_yolo OUTPUT_ROOT ./yolo_dataset TRAIN_RATIO 0.7 VAL_RATIO 0.2 TEST_RATIO 0.1 # 总和必须为1.0 # 读取所有图片名去扩展名 all_images [f for f in os.listdir(IMAGE_DIR) if f.lower().endswith((.jpg, .jpeg, .png))] all_basenames [os.path.splitext(f)[0] for f in all_images] # 按类别统计需提前知道类别数此处假设为3类person/car/dog # 实际脚本中会解析labels_yolo/下所有txt首列class_id并统计频次 # 此处省略统计逻辑直接按basename列表分割 train_list, temp_list train_test_split(all_basenames, train_sizeTRAIN_RATIO, random_state42, shuffleTrue) val_list, test_list train_test_split(temp_list, train_sizeVAL_RATIO/(VAL_RATIOTEST_RATIO), random_state42, shuffleTrue) # 创建输出目录 for subset in [train, val, test]: os.makedirs(f{OUTPUT_ROOT}/{subset}/images, exist_okTrue) os.makedirs(f{OUTPUT_ROOT}/{subset}/labels, exist_okTrue) # 复制文件核心逻辑 def copy_files(basename_list, subset): for name in basename_list: # 复制图片 src_img f{IMAGE_DIR}/{name}.jpg dst_img f{OUTPUT_ROOT}/{subset}/images/{name}.jpg shutil.copy2(src_img, dst_img) # 复制标签 src_label f{LABEL_DIR}/{name}.txt dst_label f{OUTPUT_ROOT}/{subset}/labels/{name}.txt if os.path.exists(src_label): shutil.copy2(src_label, dst_label) else: # 若无标签创建空txtYOLO训练器要求每个img有对应label with open(dst_label, w) as f: pass copy_files(train_list, train) copy_files(val_list, val) copy_files(test_list, test) print(fSplit done: train{len(train_list)}, val{len(val_list)}, test{len(test_list)})参数说明TRAIN_RATIO0.7训练集占比工业级项目建议不低于0.65小样本可提至0.8random_state42固定随机种子确保多次运行划分结果一致调试必备shutil.copy2()保留原始文件时间戳和权限避免某些训练器因mtime异常报错执行后检查yolo_dataset/train/images/下应有3500张图yolo_dataset/val/labels/下应有1000个.txt且任意val/images/001234.jpg必有对应val/labels/001234.txt。2.3 构建YOLOv8兼容的dataset.yaml三行配置决定能否训起来Ultralytics YOLOv8要求一个dataset.yaml文件定义数据路径和类别。绝不能直接用网上抄的模板——路径错一个斜杠、类别名多一个空格训练器就会静默失败只报KeyError: train却不提示哪行错。以下是适配本数据集的最小可行配置# yolo_dataset/dataset.yaml train: ../yolo_dataset/train # 注意这里是相对路径从ultralytics/train.py所在位置算起 val: ../yolo_dataset/val test: ../yolo_dataset/test # 可选但加了能用model.val()直接测 # 类别数和名称必须与labels_yolo/中class_id完全一致从0开始编号 nc: 3 names: [person, car, dog] # 顺序必须与class_id 0/1/2严格对应注意train:和val:的路径是相对于你运行yolo train命令的当前工作目录。如果你在ultralytics/目录下执行yolo train data../yolo_dataset/dataset.yaml ...那么../yolo_dataset/train才是正确的。很多教程写成./yolo_dataset/train导致找不到数据——这是血泪经验。验证配置是否生效python -c import yaml; print(yaml.safe_load(open(../yolo_dataset/dataset.yaml)))输出应包含{train: ../yolo_dataset/train, val: ../yolo_dataset/val, nc: 3, names: [person, car, dog]}。2.4 一行命令启动训练参数选择背后的工程权衡YOLOv8训练命令看似简单但每个参数都是trade-off。以下是最小可行命令基于YOLOv8n适合快速验证yolo train data../yolo_dataset/dataset.yaml modelyolov8n.pt epochs100 batch16 imgsz640 nameyolov8n_custom关键参数深度解析batch16显存占用主力。RTX 3090可跑32GTX 1660建议设8。不要盲目调大——batch过大导致梯度更新不稳定mAP反而下降。imgsz640输入尺寸。本数据集图片平均分辨率约1280x720640是平衡精度与速度的黄金点。若检测小目标如远处车牌可试imgsz1280但batch需减半。nameyolov8n_custom实验名自动创建runs/train/yolov8n_custom/目录存权重和日志。务必每次换新名字否则覆盖旧结果。epochs100对5000图100轮足够收敛。若val/mAP在80轮后停滞可提前终止。训练启动后你会看到实时进度条和指标Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size 1/100 3.2G 1.2456 1.8721 1.0234 128 640其中box_loss定位损失应在20轮内降到0.8以下cls_loss分类损失降到1.0以下——若50轮仍高于此大概率是标签格式错误或类别名不匹配。3. VOC/COCO/YOLO三格式互转为什么你总在labelimg里打完标却导不出YOLO格式3.1 VOC转YOLOXML解析的三个致命细节VOC XML中bndbox坐标是像素绝对值YOLO要求归一化中心坐标。常见错误是直接除以图像宽高却忽略size标签里的width和height。正确解析逻辑import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_path, image_path, class_names): tree ET.parse(xml_path) root tree.getroot() # 1. 获取图像尺寸必须从XML读不能用PIL.open().size size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) # 2. 遍历所有object yolo_lines [] for obj in root.findall(object): cls_name obj.find(name).text.strip() if cls_name not in class_names: continue # 跳过未知类别 cls_id class_names.index(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) # 3. 归一化计算YOLO公式center_x, center_y, width, height # 注意YOLO坐标系原点在左上角xmax-xmin即width x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h # 4. 边界检查防止归一化后溢出 x_center max(0.0, min(1.0, x_center)) y_center max(0.0, min(1.0, y_center)) width max(0.0, min(1.0, width)) height max(0.0, min(1.0, height)) yolo_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) return yolo_lines # 使用示例 class_names [person, car, dog] lines voc_to_yolo(Annotations_voc/000001.xml, images/000001.jpg, class_names) with open(labels_yolo/000001.txt, w) as f: f.write(\n.join(lines))玄学细节img_w/img_h必须从XMLsize读取因为有些VOC数据集图片被缩放但XML未更新。x_center/y_center必须用(xminxmax)/2而非(xmax-xmin)/2——后者是半宽不是中心。归一化后强制max(0.0, min(1.0, value))否则YOLO训练器会因坐标越界崩溃不报错只loss爆炸。3.2 COCO转YOLOJSON里藏了17个字段你只用3个COCO JSON结构复杂但YOLO只需images[]、annotations[]、categories[]三部分。关键陷阱在于annotations[].bbox是[x,y,width,height]左上角起点而YOLO要求中心点坐标import json def coco_to_yolo(coco_json_path, output_dir, class_names): with open(coco_json_path, r) as f: coco json.load(f) # 建立image_id到文件名的映射 img_id_to_fname {img[id]: img[file_name] for img in coco[images]} # 建立category_id到class_id的映射COCO category_id从1开始YOLO从0 cat_id_to_cls_id {} for cat in coco[categories]: if cat[name] in class_names: cat_id_to_cls_id[cat[id]] class_names.index(cat[name]) # 按image_id分组annotations ann_by_img {} for ann in coco[annotations]: img_id ann[image_id] if img_id not in ann_by_img: ann_by_img[img_id] [] ann_by_img[img_id].append(ann) # 逐图转换 for img_id, anns in ann_by_img.items(): fname img_id_to_fname[img_id] base_name os.path.splitext(fname)[0] yolo_lines [] for ann in anns: cat_id ann[category_id] if cat_id not in cat_id_to_cls_id: continue cls_id cat_id_to_cls_id[cat_id] # COCO bbox: [x_top_left, y_top_left, width, height] x_tl, y_tl, w, h ann[bbox] # 转YOLO中心点归一化 x_center (x_tl w/2.0) / 1920.0 # 假设图像宽1920实际应从images[]中读取 y_center (y_tl h/2.0) / 1080.0 # 同理高1080 w_norm w / 1920.0 h_norm h / 1080.0 yolo_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}) # 写入文件 with open(os.path.join(output_dir, f{base_name}.txt), w) as f: f.write(\n.join(yolo_lines)) # 注意实际代码中需从coco[images]中动态获取每张图的width/height此处为简化避坑点COCOimages[].width/height字段必须用于归一化不能硬编码1920x1080——本数据集虽统一但通用脚本必须读取。annotations[].iscrowd为1的实例分割掩码应跳过YOLO只处理bbox。categories[].id可能不连续如[1,3,5]必须用cat_id_to_cls_id映射不能直接cat_id-1。3.3 YOLO转VOCTXT反推XML时最容易漏掉的两个标签YOLO TXT只有坐标VOC XML还需pose、truncated、difficult等字段。工业级转换必须补全def yolo_to_voc(txt_path, image_path, class_names, output_xml_path): # 读取YOLO标签 with open(txt_path, r) as f: lines f.readlines() # 获取图像尺寸 img Image.open(image_path) img_w, img_h img.size # 创建XML根节点 annotation ET.Element(annotation) ET.SubElement(annotation, folder).text images ET.SubElement(annotation, filename).text os.path.basename(image_path) ET.SubElement(annotation, path).text image_path # size节点 size ET.SubElement(annotation, size) ET.SubElement(size, width).text str(img_w) ET.SubElement(size, height).text str(img_h) ET.SubElement(size, depth).text 3 # 假设RGB # object节点核心 for line in lines: parts line.strip().split() if len(parts) 5: continue cls_id int(parts[0]) x_center float(parts[1]) y_center float(parts[2]) width float(parts[3]) height float(parts[4]) # 反归一化回像素坐标 x_min max(0, int((x_center - width/2.0) * img_w)) y_min max(0, int((y_center - height/2.0) * img_h)) x_max min(img_w, int((x_center width/2.0) * img_w)) y_max min(img_h, int((y_center height/2.0) * img_h)) obj ET.SubElement(annotation, object) ET.SubElement(obj, name).text class_names[cls_id] ET.SubElement(obj, pose).text Unspecified # 必填否则VOC工具报错 ET.SubElement(obj, truncated).text 0 # 0否1是被截断 ET.SubElement(obj, difficult).text 0 # 0否1是难识别 bndbox ET.SubElement(obj, bndbox) ET.SubElement(bndbox, xmin).text str(x_min) ET.SubElement(bndbox, ymin).text str(y_min) ET.SubElement(bndbox, xmax).text str(x_max) ET.SubElement(bndbox, ymax).text str(y_max) # 写入文件 tree ET.ElementTree(annotation) tree.write(output_xml_path, encodingutf-8, xml_declarationTrue)必须补全的字段pose值固定为UnspecifiedVOC Schema强制要求。truncated和difficult即使全为0也必须存在否则pascal_voc评估脚本会解析失败。4. 训练过程避坑指南那些让mAP卡在0.3再也上不去的5个真相4.1 现象训练loss正常下降但val/mAP始终≈0.0原因dataset.yaml中names顺序与labels_yolo/中class_id不一致。例如XML里namecar/name对应class_id0但names: [person,car,dog]中car索引是1。YOLO训练器会把所有car框当person学导致分类全错。解决用grep -r 0 labels_yolo/ | head -n 5查看class_id0的样本再打开对应XML确认name内容同步检查dataset.yaml中names第0位是否匹配。4.2 现象train/box_loss降到0.2后突然飙升反复震荡原因labels_yolo/中存在坐标越界标签如x_center1.05。YOLO损失函数对越界坐标计算异常梯度爆炸。解决运行校验脚本for txt in glob.glob(labels_yolo/*.txt): with open(txt) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) 5: continue coords list(map(float, parts[1:5])) if any(c 0 or c 1 for c in coords): print(f{txt}:{i} out of bounds: {coords})删掉或修正越界行。4.3 现象val/cls_loss持续高于train/cls_loss过拟合明显原因train/和val/划分未按类别均衡某类在val/中样本极少如只有2张导致该类mAP拉低整体。解决重跑split_dataset.py启用其内置的stratify参数需修改脚本# 在split_dataset.py中将train_test_split改为 train_list, temp_list train_test_split( all_basenames, train_sizeTRAIN_RATIO, stratifyclass_labels, # class_labels是每个basename对应的主类别id列表 random_state42 )4.4 现象训练卡在Epoch 0/100不动GPU显存占满但0% utilization原因batch16超出显存PyTorch启动了OOM Killer但未报错进程假死。解决先用nvidia-smi确认显存占用再降batch到8或4或加--workers0禁用多进程数据加载调试用。4.5 现象test/目录下图片预测结果全是空框no detections原因训练时用了conf0.25默认但测试时未指定相同置信度阈值model.predict()默认conf0.25而你的模型在0.25下确实无检出。解决测试时显式设置results model.predict(sourceyolo_dataset/test/images/, conf0.25, saveTrue)或训练时用--conf 0.1降低阈值代价是误检增多。5. 验证与部署用三招把5000张图的潜力榨干5.1 用val集做消融实验一张图看懂数据质量瓶颈YOLO训练完runs/train/yolov8n_custom/val_batch0_pred.jpg会显示预测效果。但更高效的是用val集做定量消融步骤从yolo_dataset/val/labels/中随机抽100个.txt统计每类出现频次 → 得到val集类别分布用训练好的模型预测这100张图统计每类的precision/recall制作热力图横轴类别纵轴指标颜色深浅表示数值# 示例计算person类的precision person_gt 0 # val labels中person实例总数 person_tp 0 # 预测为person且IoU0.5的实例数 person_fp 0 # 预测为person但IoU0.5的实例数 for pred_result in results: boxes pred_result.boxes for box in boxes: if int(box.cls) 0: # person class_id0 person_fp 1 # 这里需匹配GT框计算IoU完整代码略价值若car类recall0.9但dog类recall0.3说明数据集中dog标注质量差或样本少——立刻回溯labels_yolo/查dog类标签比重训模型快10倍。5.2 导出ONNX并在边缘设备推理避开PyTorch依赖的终极方案YOLOv8训练完的.pt权重不能直接部署到Jetson或RK3588。必须导出ONNX并验证# 导出注意--imgsz必须与训练时一致 yolo export modelruns/train/yolov8n_custom/weights/best.pt formatonnx imgsz640 # 验证ONNX输出与PT一致关键 import torch import onnxruntime as ort import numpy as np # 加载PT模型 pt_model torch.load(runs/train/yolov8n_custom/weights/best.pt)[model].eval() # 加载ONNX ort_session ort.InferenceSession(best.onnx) # 构造相同输入 x torch.randn(1, 3, 640, 640) pt_out pt_model(x)[0] # yolov8输出是tuple取第0个tensor # ONNX推理 ort_out ort_session.run(None, {images: x.numpy()})[0] # 比较差异应1e-4 print(np.max(np.abs(pt_out.detach().numpy() - ort_out)))参数陷阱--imgsz640必须与训练一致否则ONNX输入shape不匹配--halfFP16导出后需在ORT中启用providers[TensorrtExecutionProvider]否则速度无提升5.3 用labelimg快速修正漏标三步建立闭环标注流程训练发现漏标如val集中某张图有car但无标签用labelimg修正最高效启动labelimg并加载VOC格式labelImg yolo_dataset/val/images/ yolo_dataset/val/Annotations_voc/ --output_formatPASCAL_VOC打开漏标图 → 按W画框 → 输入类别 →CtrlS保存自动生成XML立即转回YOLO格式python voc_to_yolo.py --xml_dir yolo_dataset/val/Annotations_voc/ --img_dir yolo_dataset/val/images/ --output_dir yolo_dataset/val/labels/ --names [person,car,dog]血泪经验labelimg保存的XML中filename默认是相对路径需手动改成001234.jpg不含子目录否则voc_to_yolo.py找不到图。我习惯在labelimg设置里勾选Auto Save mode并预设Save Dir为yolo_dataset/val/Annotations_voc/。最后说句实在的这个5000张图的数据集真正价值不在数量而在它逼你直面YOLO落地最脏的活——数据对齐。我见过太多人花两周调参却因一个dataset.yaml路径错误重启三次。希望这篇笔记帮你省下那三天把时间留给真正值得折腾的事。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →