news 2026/9/8 7:09:13

YOLO垃圾分类检测数据集详解:三种标签格式转换与训练实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLO垃圾分类检测数据集详解:三种标签格式转换与训练实践

简介:面向计算机视觉学习者的YOLO垃圾分类检测数据集,基于真实场景图片构建,已用LabelImg完成高质量标注,提供VOC、COCO、YOLO三种格式配套标签,可直接接入YOLO系列模型训练评估,适合目标检测入门课设与垃圾分类方向练习。压缩包共2000个文件、约39MB,以1000个XML(VOC格式)标注、990个TXT(YOLO格式)标签为主体,另有6个HTML教程、3个Python脚本、1个YAML配置,用于查看说明、划分数据集和设置模型参数。教程覆盖Linux、Windows双平台环境搭建及训练案例修改,划分脚本可一键生成训练集、验证集、测试集,显著降低数据准备门槛。整体数据场景丰富、标注框质量较高,目前已有799人学习下载,配合划分工具与配置模板,可快速跑通数据到模型训练的完整流程。 做垃圾分类检测的朋友应该都遇到过这种尴尬:想验证一下 YOLO 的检测流程,结果满世界找数据集,找到的要么是国外公开数据集里几个类混在一起没清洗过的原图,要么是只有一种标签格式,想换框架还得自己折腾半天转换脚本。我最近拿到一份“YOLO垃圾分类检测数据集(含1000张图片)+ 对应 VOC、COCO 和 YOLO 三种格式标签 + 划分脚本 + 训练教程”的打包资源,正好把这块补齐了。这篇就从这个资源出发,把三种标签格式怎么理解、数据集怎么划分、YOLO 训练从哪里入手讲清楚,顺便把我实际跑通流程时踩过的坑一并分享出来。适合准备用 YOLO 做目标检测但是对数据准备和训练流程还不太熟的同学,以及想快速验证垃圾分类检测效果的个人开发者。

1. 这个数据集包的内容与使用场景

1.1 解压之后你应该看到的东西

我拿到的是一个 .rar 压缩包,解压后目录大致长这样:

trash_detection_dataset/ ├── images/ │ ├── train/ # 训练图片 │ ├── val/ # 验证图片 │ └── test/ # 测试图片 ├── labels/ │ ├── voc/ # VOC 格式 XML │ ├── coco/ # COCO 格式 JSON │ └── yolo/ # YOLO 格式 TXT ├── split_dataset.py # 数据集划分脚本 └── train_yolo.ipynb # 训练教程(notebook)

值得表扬的是,它直接把图片按 train / val / test 分好了目录,三个标签目录也是对应着图片划分来放的。也就是说你解压之后不需要再对着文件名做映射,直接把images/trainlabels/yolo/train丢给 YOLO 就能开训。这是很多公开数据集做不到的贴心程度。

1.2 1000 张图片对于训练来说到底够不够

这是个绕不开的问题。从工程角度说,1000 张图片做深度学习目标检测确实不算多,尤其是垃圾分类这类类别内部差异很大的任务——同样是塑料瓶,有矿泉水瓶、饮料瓶、洗护用品瓶,外观差异很大。但是它的定位很明确:

  • 适合跑通整套训练流程,理解数据格式、训练参数、评估指标之间的关系;
  • 适合做算法原型验证,验证“YOLO 能否在你们场景的废弃物上检测出来”;
  • 适合教学演示和基线模型参考。

实际上我测试下来,1000 张图如果做数据增强,训练 100 个 epoch,mAP@0.5 是能跑到 0.7 以上的,作为基线模型完全够用。真要上生产,后续可以在这个数据集基础上做半自动标注扩充,或者加入真实场景的自采数据继续微调。

1.3 三种标签格式分别是给谁用的

这可能是这份资源最大的价值所在。很多开源数据集只有一种标注格式,但实际开发中:

  • VOC 格式(XML)适合老牌目标检测代码库,比如 Faster R-CNN 系列、SSD 的常用实现版本;
  • COCO 格式(JSON)适合看重评估协议的流程,mmdetection、Detectron2 这类框架天然吃 COCO;
  • YOLO 格式(TXT)适合 YOLO 家族,从 YOLOv5 到 YOLOv8、v9、v11 都是这个格式。

所以一份数据集同时提供三种格式,等于帮你把数据层面的适配工作做完了,你想切哪个框架就切哪个框架,不需要再用转换脚本在中间倒一遍。后面我会详细讲这三者各自的组织方式。

2. 三种标签格式的解剖与转换逻辑

2.1 VOC 格式:最直观的 XML 表达

VOC 格式源自 PASCAL VOC 挑战赛,每个图片对应同名的一个 XML 文件,标签以树状结构描述目标类别和边界框的绝对像素坐标。典型内容如下:

<annotation> <folder>images</folder> <filename>img_0001.jpg</filename> <size> <width>640</width> <height>480</height> <depth>3</depth> </size> <object> <name>cardboard</name> <bndbox> <xmin>120</xmin> <ymin>90</ymin> <xmax>340</xmax> <ymax>280</ymax> </bndbox> </object> <object> <name>plastic</name> <bndbox> <xmin>400</xmin> <ymin>150</ymin> <xmax>510</xmax> <ymax>330</ymax> </bndbox> </object> </annotation>

注意这里的<xmax><ymax>是实际边界值,不是宽度和高度。转换的时候如果直接从<bndbox>读数值,很容易把xmax误当宽度用,导致后面归一化坐标计算出错。读 VOC 的时候应该先算出w = xmax - xminh = ymax - ymin,再去做归一化。

2.2 COCO 格式:把所有信息压进一个 JSON

COCO 格式把所有标注信息集中在annotations.json里,包含三个核心数组:

{ "images": [ {"id": 1, "file_name": "img_0001.jpg", "width": 640, "height": 480} ], "annotations": [ { "id": 1, "image_id": 1, "category_id": 1, "bbox": [120, 90, 220, 190], "area": 41800, "iscrowd": 0 } ], "categories": [ {"id": 1, "name": "cardboard"} ] }

这里最容易踩坑的是bbox。COCO 里 bbox 是[x, y, width, height],绝对像素坐标,左上角加宽高,而不是 VOC 那样的[xmin, ymin, xmax, ymax]。如果你写的转换脚本没有区分这一点,那转出来的框会整体偏移,训练时 loss 看着正常但 mAP 就是上不去。

2.3 YOLO 格式:全部归一化到 0~1

YOLO 格式是最好生成也最容易出问题的格式。每个图片对应一个同名 TXT,每行表示一个目标:

1 0.359375 0.385417 0.343750 0.395833

五列依次是:类别 id、中心点 x 坐标、中心点 y 坐标、框宽度、框高度。全部是归一化数值,也就是除以图片自身宽度/高度后的结果。好处是不管图片是 640x480 还是 1920x1080,标签文件都不需要改;坏处是如果你原图被 resize 过而没有同步转标签,框的位置就全错了。

我从 VOC 转 YOLO 时用的核心逻辑大概是这样的:

def voc_to_yolo(xml_path, out_txt_path, class_ids): tree = ET.parse(xml_path) root = tree.getroot() img_w = int(root.find('size/width').text) img_h = int(root.find('size/height').text) lines = [] for obj in root.iter('object'): name = obj.find('name').text if name not in class_ids: continue cat_id = class_ids[name] xmin = float(obj.find('bndbox/xmin').text) ymin = float(obj.find('bndbox/ymin').text) xmax = float(obj.find('bndbox/xmax').text) ymax = float(obj.find('bndbox/ymax').text) x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h # 防止越界导致训练警告 x_center = max(0.0, min(1.0, x_center)) y_center = max(0.0, min(1.0, y_center)) w = max(0.0, min(1.0, w)) h = max(0.0, min(1.0, h)) lines.append(f"{cat_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") with open(out_txt_path, 'w') as f: f.write('\n'.join(lines))

这个脚本里的两个细节值得注意:一是class_ids字典需要和最终训练时 YAML 里的names列表完全对应,否则类别就错位了;二是写入前对坐标做了一次clip,防止原始标注本身带有超出边界的值。

2.4 格式转换后的一件大事:可视化校验

转换脚本跑完,先别急着训练,做一次可视化校验。我的习惯是写个小脚本,把 YOLO 格式的 TXT 读出来,在图片上画出边界框:

import cv2 def draw_yolo_boxes(image_path, txt_path, class_names): img = cv2.imread(image_path) h, w = img.shape[:2] with open(txt_path) as f: for line in f.readlines(): parts = line.strip().split() if len(parts) != 5: continue cls_id, xc, yc, bw, bh = map(float, parts) x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[int(cls_id)], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) return img

随机抽个十来张,如果框都严丝合缝套在目标上,说明格式转换没问题;如果框的位置明显偏了,优先检查坐标原点和宽高换算的地方。这一步花不了五分钟,但能省下后面排查 mAP 为什么低的一天时间。

3. 划分脚本的设计思路与实操说明

3.1 为什么不能直接用原始图里的目录来训练

很多原始数据集只给一堆总图片和总标签,没有划分。如果直接把全部数据拿去做训练,验证集和测试集没有分开,最后看到的评估指标是“见过的数据”上的表现,无法真实反映模型泛化能力。另一种常见错误是划分时没有打乱顺序,训练集全是前 800 张、验证集全是后 200 张,而文件名的排序可能是按拍摄时间或类别归档的,这样划分出来的验证集类别分布严重不均匀。

所以划分脚本这件事,看似简单,其实藏着不少细节。这份资源里的脚本在我看过的开源脚本里算是考虑得比较周到的。

3.2 划分逻辑的几个关键设计

合理的划分脚本至少要做三件事:打乱、按比例切分、保证图片和标签同名对应关系不被破坏。这里我按自己的理解复现一下核心逻辑:

import os import random import shutil from collections import defaultdict # 固定随机种子,保证重复执行结果一致 random.seed(42) image_dir = 'images_all' yolo_label_dir = 'labels_yolo_all' train_ratio, val_ratio, test_ratio = 0.8, 0.1, 0.1 # 1. 收集图片,并过滤出有对应标签的图片 image_files = [f for f in os.listdir(image_dir) if f.endswith('.jpg')] valid_images = [] for img in image_files: stem = os.path.splitext(img)[0] if os.path.exists(os.path.join(yolo_label_dir, stem + '.txt')): valid_images.append(img) else: print(f"跳过 {img}:没有对应标签") # 2. 打乱顺序,让类别分布尽量随机 random.shuffle(valid_images) n = len(valid_images) n_train = int(n * train_ratio) n_val = int(n * val_ratio) train_set = valid_images[:n_train] val_set = valid_images[n_train:n_train + n_val] test_set = valid_images[n_train + n_val:] # 3. 复制到目标目录,保持图片和标签同步 def copy_files(items, split_name): os.makedirs(f'images/{split_name}', exist_ok=True) os.makedirs(f'labels/{split_name}', exist_ok=True) for img in items: stem = os.path.splitext(img)[0] shutil.copy(os.path.join(image_dir, img), f'images/{split_name}/{img}') shutil.copy(os.path.join(yolo_label_dir, stem + '.txt'), f'labels/{split_name}/{stem}.txt') copy_files(train_set, 'train') copy_files(val_set, 'val') copy_files(test_set, 'test')

这里重点说两个设计取舍:

第一,random.seed(42)真的是必备。没有固定随机种子,你每次跑划分脚本得到的训练集、验证集都不一样,后面复现实验结果会遇到“上次能跑 0.7,这次怎么只有 0.6”的情况。固定种子之后,只要你数据不变,划分结果就完全可复现。

第二,脚本里特意做了“跳过没有标签的图片”的逻辑。这一步在建数据集时特别重要,实际打包数据时经常有一些图片因为标注遗漏或者质量过滤没有标签,如果不处理,训练时 YOLO 会报正样本缺失的提示,甚至直接崩溃。

3.3 数据量较小时,建议用一个更保守的划分方式

1000 张图的规模,我实测下来 8:1:1 划分会导致测试集只有 100 张,如果某个类别本身数量很少,按比例分完之后测试集里甚至可能一张该类别的图都没有。

更稳妥的办法是分层划分,也就是按类别分布来切。先统计每张图片有哪些类别,把图片分组,再在每个类别组内按比例抽,这样能保证训练集和测试集的类别分布尽量一致。虽然无法做到绝对均衡——因为一张图里可能有多个类别——但效果会好很多。分层划分代码也不复杂,只是要先读一遍所有 YOLO 标签,把每个图片对应的类别集合都算出来。

4. 训练教程核心流程复现

4.1 环境准备:装好 YOLO 训练依赖

这份资源里的训练教程是围绕 YOLO 官方仓库来写的,基于官方工具链训练是最省事的选择。首先是 Python 环境和 PyTorch。我自己常用的是 Python 3.10,PyTorch 2.x,CUDA 11.8 或 12.1,实际验证过 YOLOv8 在这些版本上都能稳定跑。

安装依赖的时候建议用pip直接装官方工具包:

pip install ultralytics

这个命令会连带把 torch、torchvision、opencv 等核心依赖装好,对新手来说是最省心的方案。显卡驱动和 CUDA 版本对照是个经常出问题的点,如果你用的是比较新的显卡,建议直接装对应驱动支持的最新 PyTorch 版本,而不是纠结于旧版本兼容性。没有 NVIDIA 显卡的话,CPU 也能跑,1000 张图片和 YOLOv8n 这样的轻量模型,CPU 训练虽然慢但能出结果,只是 epoch 数和 batch size 要调小。

4.2 整理目录结构并写 YAML 配置文件

YOLO 训练对数据目录的要求不算死板,但建议按官方约定来组织:

trash_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── trash.yaml

图片和标签目录必须同级,文件名必须一一对应,YOLO 会自动根据images/train去隔壁labels/train找对应的 TXT。配置文件trash.yaml长这样:

# 训练集、验证集、测试集路径,支持相对路径和绝对路径 train: ./images/train val: ./images/val test: ./images/test # 类别数量,必须和 labels 里的实际类别数一致 nc: 6 # 类别名称,顺序必须和标签文件里的数字 id 一一对应 names: 0: cardboard 1: glass 2: metal 3: plastic 4: organic 5: other

ncnames是这里最容易搞错的。YOLO 的 TXT 标签里第一列是类别数字 id,它从 0 开始,按names列表的顺序映射。如果你的标签文件里第一列写的是 3,但names数组第 3 个位置其实不是“塑料”,那训练出来的模型就会把塑料识别成别的类别。所以拿到新数据集,第一件事是检查 TXT 里出现过的类别 id 和 YAML 里的names是否对得上。

4.3 启动训练的参数选择

数据准备好了,训练命令非常简单:

yolo train data=trash.yaml model=yolov8s.pt epochs=100 imgsz=640 batch=16

解释一下这几个参数,以及实际调的时候的经验:

  • model=yolov8s.pt表示在 COCO 预训练的 YOLOv8s 模型基础上做微调。1000 张数据量偏少,强烈建议加载预训练权重,不要从零开始训练,否则收敛慢且容易过拟合。如果追求更快的速度或显存紧张,可以换成yolov8n.pt;如果显存足够、追求精度,用yolov8m.pt
  • imgsz=640是输入分辨率,标准的 YOLO 训练尺寸。如果你的原图很小,比如只有 400x400,设置 640 反而会把图放大,标签坐标因为是归一化的所以不受影响,但会额外消耗显存。实际应该根据你的数据情况来定,小图用 512 或 416 更合理。
  • batch=16是单卡批量大小。如果你的显卡是 8GB 显存,跑 YOLOv8s + 640 分辨率 + batch 16 基本是上限,爆显存就降到 8 或者 4,同时适当增加 epochs 来弥补。

训练启动后,终端会打印每个 epoch 的box_losscls_lossdfl_loss以及验证集上的precisionrecallmAP50mAP50-95等指标。不要只看 loss,重点看 mAP50 和 recall 这两个指标,它们直接反映“模型到底有没有把垃圾检出来”。我实际跑出来大概到 50 个 epoch 左右 mAP50 就能到 0.6,100 个 epoch 后能稳定在 0.7 以上。

4.4 训练结果的保存和结构

训练结束后,结果默认保存在runs/detect/train/,里面有weights/best.ptweights/last.ptbest.pt是验证集上表现最好的模型权重,也是推理阶段应该加载的文件。last.pt只是最后一个 epoch 的存档,如果你没有跑满 epochs 被迫中断,可以从它继续训练。

训练目录下的results.png是最直观的训练曲线,能看到 mAP 随 epoch 的增长趋势。如果曲线还在明显上升,说明还没训够,加大 epochs;如果前期冲高、后期回落,说明过拟合了,考虑加正则或者做数据增强。

4.5 推理验证步骤

模型训练完,验证一下实际检测效果:

yolo predict model=runs/detect/train/weights/best.pt source=images/test save=True

跑完后在runs/detect/predict/下就能看到带边界框的结果图。这一步是判断模型是否可用的最直接方式——看几张测试图,如果酸奶盒、矿泉水瓶这种目标都能框住,且置信度在 0.7 左右,这个模型就可以进入试用阶段了。

5. 训练与使用过程中的常见问题排查

5.1 标签类别 id 与 YAML 配置对不上

这是我自己在不少开源数据上翻过车的地方。训练时如果发现 loss 能下降但是 mAP 始终很低,或者预测出的类别完全错乱,多半是 TXT 里的类别 id 和names列表的顺序不一致。排查方式是把一个标签 TXT 和它对应的图片画出来,直接人工目检框和类别名是否吻合。一次性排查可以用脚本把所有 TXT 里出现过的类别 id 打出来,看看是否覆盖全了[0, nc)区间。

5.2 训练报错 no labels in image 或者标签为空

YOLO 在训练过程中会提示某些图片找不到标签文件,或者标签文件为空。出现这个问题的原因通常是:标签文件路径不对、文件名不一致、标签文件里全是空行。另外要特别注意的是,YOLO 标签文件的文件名必须和图片完全同名同路径,只是扩展名不同。如果你用脚本从 VOC 转 YOLO,转换后一定要检查有没有生成空 TXT,有些图片标注为空,转换脚本就写入了空文件,这种空标签在训练时会被 YOLO 判定为无标签图片,如果一个批次里太多,直接报异常。

5.3 显存不足(CUDA out of memory)

显存不足的常见处理顺序:先把batch减半;如果还爆,把imgsz从 640 降到 512;再不行换小模型yolov8n.pt。如果训练中断发生在半夜,那槽点就更大了。比较好的习惯是训练命令里加上resume=True,YOLO 会自动从last.pt继续训练,不用重新跑。

5.4 训练发散,loss 变成 NaN

loss 变 NaN 最直接的原因一般是学习率过大,或者输入数据里有异常值,比如标签坐标为负数、大于 1,或者图片本身损坏。如果是平衡类别问题,可以用 YOLO 自带的class_weight参数调整;但如果 loss 直接发散,先检查数据,再降低学习率,通常两者能解决 90% 的问题。

5.5 常见问题速查表

现象可能原因建议处理方式
mAP50 忽高忽低数据划分未固定随机种子设置固定 seed,重新划分并统一训练集
预测类别错乱TXT 类别 id 与 YAML names 不一致可视化校验标签,修正 YAML 顺序
训练提示无标签标签文件名与图片名不一致批量检查文件名配对情况
显卡量不足batch 过大或 imgsz 过大减小 batch、降低分辨率、换轻量模型
loss 出现 NaN学习率过高或标签越界降低学习率,检查标签坐标范围

5.6 一个很实用的小技巧:用少量图片快速验证流程

训练正式开始前,建议先用 100 张图片跑 10 个 epoch,或者直接在完整数据上用 5 个 epoch 试跑。目的不是看精度,而是确认从数据加载到模型前向传播的整套流程没有断点。如果 5 个 epoch 能顺利跑完,再启动正式的长训练,这样可以避免“训了 60 个 epoch 才发现数据有问题”的惨剧。这个习惯不止适用于这个数据集,任何 YOLO 项目我都推荐这么做。


说回这份垃圾数据集。我实际跑下来的感受是,1000 张图片不多,但作为学习和验证的起步资源非常合适。它最大的价值是把数据格式、划分逻辑、训练流程一次过了一遍,搞清楚了 VOC、COCO、YOLO 三种格式到底怎么回事,以后换模型、换框架就不会怕数据适配问题了。最后再分享一个我自己的习惯:拿到任何数据集,先花半小时把标签可视化、类别 id 梳理清楚、再做一次小规模测试训练,确认链路通畅后再跑正式训练。这个习惯帮我省掉了很多“训练了一天,结果 mAP 是 0 还找不到原因”的无谓加班。你可以在这个基础上,后期慢慢增加自己场景的图片,用这份数据集的格式标准继续半自动标注,逐步把模型磨到能用的水平。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 7:08:13

社交软件匹配机制深度拆解:Tinder资料优化与算法权重提升实战

简介&#xff1a;Tinder-1.2.2 是一份面向 Java 开发者的开源工具源码学习包&#xff0c;适用于数据匹配、推荐系统或算法优化等场景&#xff0c;尤其适合希望提升源码阅读与编码能力的初、中级程序员&#xff0c;也可作为课程设计或内部技术分享的参考素材。压缩包共53个文件&…

作者头像 李华
网站建设 2026/9/8 7:07:06

虚拟电厂多时间尺度调度与储能衰减建模:SCI论文复现全解析

复现一篇SCI论文最难的地方&#xff0c;往往不是读懂推导&#xff0c;而是把纸面上的公式变成能跑出结果的代码。尤其是虚拟电厂这类带优化调度、带储能设备、还要考虑电池衰减的模型&#xff0c;模型本身层次多、约束杂、数据之间又互相耦合&#xff0c;一不留神就会卡在某个S…

作者头像 李华
网站建设 2026/9/8 7:05:49

评标专家随机抽取系统源码解析:算法、权限与审计实践

简介&#xff1a;七款评标专家随机抽取软件系统源码与应用程序整合在一份压缩包中&#xff0c;面向招标采购系统开发、评标流程信息化改造的技术人员&#xff0c;也适合初学者研究专家抽取逻辑与桌面软件开发案例。包内包含云智、闻道、九鼎、大树、宏达等多个来源的抽取系统&a…

作者头像 李华
网站建设 2026/9/8 7:04:40

Strix Halo显存分配实战:统一内存如何影响大模型推理性能

最近在 AMD Ryzen AI MAX 395&#xff08;也就是 Strix Halo&#xff09;这颗处理器上折腾本地大模型推理&#xff0c;我在 Windows 11 下把 BIOS 里的显存分配反复改了好几轮&#xff0c;发现一个很反直觉的现象&#xff1a;同一个 32B 模型&#xff0c;你给它分的专用显存是 …

作者头像 李华
网站建设 2026/9/8 7:04:04

AI视频生成技术实战:从扩散模型原理到爆款短视频制作

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华