简介:面向垃圾分类检测实践的一套YOLO数据集及配套工具,涵盖约一万张真实场景拍摄的生活垃圾图片,图像清晰、场景多样,适合日常垃圾分类识别、智能分拣等工程应用;经LabelImg人工标注,标注框质量较高,可直接用于YOLO系列模型的训练、验证与测试。压缩包共两千个文件,类型以XML标签、TXT文本、HTML教程和Python脚本为主,整体约410.27MB;其中XML与TXT分别对应VOC和YOLO格式标签,同时提供COCO(JSON)标签目录,并附带训练集、验证集、测试集划分脚本以及生成ImageSets下txt文件的工具,便于按需求灵活拆分数据、适配不同训练流程。配套教程覆盖Windows与Linux双平台的YOLO环境搭建和训练案例,可根据实际场景修改后训练自己的数据集,省去从零探索环境的成本。目前已有1300余人学习浏览,特别适合初次接触垃圾分类检测、期望快速搭建YOLO实战流程的开发者与研究者。
1. 10000张真实场景图:垃圾分类检测为什么绕不开这份数据集
垃圾分类检测和通用目标检测有个本质差别:类别内差异能大到不像同一类,比如同一个"瓶子"类别里,透明矿泉水瓶、绿色啤酒瓶、不透明药瓶在形状和颜色上完全是三套特征;反过来,不同类别之间又长得过于接近,纸盒和塑料包装袋在视觉上经常分不清。很多团队拿着 COCO 预训练权重直接跑,最后发现模型在自家场景里框得准但分类错,问题基本都出在训练数据上,而不是网络结构上。
这份 YOLO垃圾分类检测数据集正好补这个缺口。10000 张图片全部来自真实场景,用 lableimg 逐框标注,同一批标注同时导出了 VOC(xml)、COCO(json)和 YOLO(txt)三种格式标签,训练前不用再花时间做格式转换。更实用的是里面带了三个划分脚本和两套训练教程,Linux 和 Windows 都有对应版本,适合做课程设计、毕业设计,也能当城市垃圾分类项目的第一版 baseline。
2. VOC、COCO、YOLO 三格式标签:目录结构、标注范式与互转思路
拿到压缩包后先把目录结构看一遍,别急着直接 train。资源里的图片和三种格式标签是分开存放的,本质上是同一批标注结果的不同序列化形式,但它们的读取逻辑、坐标表达和适用框架完全不同,新手最容易在这里栽跟头。
2.1 三种标签格式的底层差异
把同一个标注框分别用三种格式打开,你才会理解为什么有的框架认这一种、不认那一种。下面的对比围绕一个 1280×720 的瓶子目标展开。
2.1.1 VOC(xml)的树形标注结构
VOC 格式是一张图片对应一个 xml 文件,整体是一棵树的形状,所有信息都能直接读出来:
<annotation> <folder>JPEGImages</folder> <filename>glass_001.jpg</filename> <size> <width>1280</width> <height>720</height> </size> <object> <name>bottle</name> <difficult>0</difficult> <bndbox> <xmin>120</xmin> <ymin>85</ymin> <xmax>640</xmax> <ymax>520</ymax> </bndbox> </object> </annotation>name节点是类别名,bndbox里存的是绝对像素坐标,xmin/ymin是左上角,xmax/ymax是右下角。这种格式最大的优点是人和工具都能直接修改,用 lableimg 打开一张图就能手工调整某个框的位置。缺点也同样明显:一千张图就是一千个 xml 文件,做大数据集统计时要遍历全部文件;训练框架也很少直接用 xml,需要先转成其他格式。
2.1.2 COCO(json)的数组式组织
COCO 格式把整个数据集塞进一个 json 文件,核心是images、annotations、categories三个数组:
{ "images": [{"id": 1, "file_name": "glass_001.jpg", "width": 1280, "height": 720}], "annotations": [{"id": 1, "image_id": 1, "category_id": 1, "bbox": [120, 85, 520, 435], "area": 226200, "iscrowd": 0}], "categories": [{"id": 1, "name": "bottle"}] }bbox里的四个数字是[x, y, width, height],不是[xmin, ymin, xmax, ymax]。这是从 VOC 转 COCO 时最高频的报错点,很多人把xmax当成width填进去,模型训练出来检测框全是歪的。COCO 的好处是切分训练集、验证集很方便,改一段 json 就行,不用动图片文件。
2.1.3 YOLO(txt)的归一化坐标
YOLO 系列训练真正吃的是 txt 格式。每张图对应一个 txt 文件,每一行是一个目标:
0 0.296875 0.420139 0.406250 0.604167第一个数是类别 id,后面四个数是x_center y_center width height,全部除以图片宽高做了归一化,取值范围在 0 到 1 之间。注意坐标中心点和宽高都做了归一化,不是只归一化中心点。这个设计让不同分辨率图片可以混合训练,模型不关心输入图实际多大,只关心目标在图上占的比例。
用一张表把这三种格式的关键差异串起来:
| 格式 | 文件组织 | 坐标表达 | 修改成本 | 训练框架 |
|---|---|---|---|---|
| VOC | 一图一 xml | 绝对像素(左上/右下) | 低,工具直接改 | Faster R-CNN 系 |
| COCO | 全数据集一个 json | 绝对像素(x/y/w/h) | 中,改 json 段 | Detectron2、MMDetection |
| YOLO | 一图一 txt | 归一化(中心点/宽高) | 低,但可读性差 | YOLO 全系列 |
2.2 目录结构与同图多格式同步
资源里的标签目录大致是这样一个布局:
waste_dataset/ ├── JPEGImages/ # 10000 张原图 ├── VOC/ # 10000 个 xml 文件 ├── COCO/ # 1 个 json 文件 └── YOLO/ # 10000 个 txt 文件三种格式来自同一次标注,同一个glass_001.jpg在 VOC、COCO、YOLO 三个目录里对应的是同一个目标框。这个特性在实际排错时非常值钱:训练阶段发现某个框的预测结果异常,打开对应 VOC 格式的 xml,用 lableimg 加载原图就能直接检查标注框是否错位,不用写脚本去解析 txt。
资源里的数据标注质量比较高,一个重要表现是 txt 文件中基本没有空文件。空文件意味着图片里没有目标,在 YOLO 训练中虽然不报错,但在某些增强策略下会导致梯度异常。
2.3 用一段代码看懂互转逻辑
虽然资源已经给了三种格式,但实际项目中经常会往现有数据集里补充新类别,或者把别人给的 VOC 数据合并进来。这时候手写一段互转代码会派上用场。下面是最小可用的 XML 转 YOLO 逻辑:
import os import xml.etree.ElementTree as ET class_id = {"bottle": 0, "can": 1, "paper": 2} def xml_to_yolo(xml_path, txt_path): tree = ET.parse(xml_path) root = tree.getroot() width = int(root.find("size/width").text) height = int(root.find("size/height").text) lines = [] for obj in root.iter("object"): name = obj.find("name").text box = obj.find("bndbox") xmin = float(box.find("xmin").text) ymin = float(box.find("ymin").text) xmax = float(box.find("xmax").text) ymax = float(box.find("ymax").text) x_center = ((xmin + xmax) / 2) / width y_center = ((ymin + ymax) / 2) / height box_width = (xmax - xmin) / width box_height = (ymax - ymin) / height lines.append(f"{class_id[name]} {x_center:.6f} {y_center:.6f} {box_width:.6f} {box_height:.6f}") with open(txt_path, "w") as f: f.write("\n".join(lines)) xml_to_yolo("VOC/glass_001.xml", "YOLO/glass_001.txt")归一化时除以的是 xml 里size节点的宽高,不是图片实际解析出来的宽高,两者通常一致,但不排除某些标注工具写错的情况。中心点坐标用(xmin + xmax) / 2而不是xmin + box_width / 2,前者可以直接套用原始坐标,少积累一步浮点误差。类别映射字典class_id必须和之后 data.yaml 里的names顺序完全一致,这个顺序错一个,整个训练就是错的。
COCO 转 YOLO 要更麻烦一些,annotations里还混着iscrowd、segmentation这些字段,转换时要过滤掉iscrowd=1的目标。如果只是想跑通 YOLO 训练,直接用资源里现成的 YOLO 目录就好,不需要自己转换。
提示:检查一份标注是否可用的最快方式不是写脚本,而是随手打开一张图和它对应的 txt,目测几个坐标值是否在 0~1 之间。如果出现大于 1 的值,说明归一化时用了错误的宽高。
3. 三个划分脚本怎么选:从 train_val_test 到 ImageSets 的落地逻辑
数据准备好了,下一步是把数据集切成训练集、验证集和测试集。资源里放了三个不同的划分脚本,很多人不明白为什么给三个,其实它们的适用场景完全不同,选错脚本不会报错,但会让后面的评估流程变得别扭。
3.1 三个脚本各自解决什么问题
先把三个脚本的差异理清楚:
| 脚本 | 输出 | 适用场景 |
|---|---|---|
| 训练/验证/测试划分脚本 | 三个独立文件夹 | 需要保留 h留出测试集做最终评估 |
| 训练/验证划分脚本 | 两个文件夹 | 只需验证集看收敛情况 |
| split_train_val 脚本 | ImageSets 下 txt 文件 | 配合 VOC 系框架使用 |
YOLO 原生训练只认目录结构,images/train、images/val这样的路径最省事,前两个脚本的输出正好对齐这个要求。第三个脚本生成的是 ImageSets 下的清单文件,里面写的是图片相对路径列表,这类约定常见于 R-CNN 系列的代码库和部分课程作业模板。如果训练框架是 ultralytics,完全可以忽略第三个脚本。
3.2 划分脚本的核心逻辑
打开脚本会发现逻辑并不复杂,核心步骤只有四步:列出全部文件名、打乱顺序、按比例切片、成对拷贝图片和标签。等效实现如下:
import random import shutil import os random.seed(42) img_dir = "JPEGImages" label_dir = "YOLO" out_dir = "dataset" files = [f for f in os.listdir(img_dir) if f.endswith(".jpg")] random.shuffle(files) total = len(files) train_files = files[:int(total * 0.8)] val_files = files[int(total * 0.8):int(total * 0.9)] test_files = files[int(total * 0.9):] for split, names in { "train": train_files, "val": val_files, "test": test_files }.items(): os.makedirs(f"{out_dir}/images/{split}", exist_ok=True) os.makedirs(f"{out_dir}/labels/{split}", exist_ok=True) for name in names: shutil.copy(os.path.join(img_dir, name), os.path.join(out_dir, "images", split, name)) label_name = name.replace(".jpg", ".txt") shutil.copy(os.path.join(label_dir, label_name), os.path.join(out_dir, "labels", split, label_name))图片和标签在同一个循环里被成对拷进对应目录,这是划分脚本最关键的保证。如果先拷图片再单独拷标签,某些文件在拷贝过程中出问题,训练时就会出现Image not found或者标签文件缺失的报错。random.seed(42)的写法保证了每次运行脚本得到相同的划分结果,方便实验对比。
8:1:1 是目标检测里很常见的默认切分比例。10000 张图实际切出来大约是 8000/1000/1000。如果你的类别分布不均衡,随机切分的风险在于少数类可能集中落在某一个分片里。比如数据集中某种垃圾只出现在 80 张图里,随机打乱后这 80 张可能全部进了训练集,验证集里这种类别一张都没有。
3.3 划分之后目录怎么摆
脚本跑完后,标准的目标检测数据集目录应该长这样:
waste_dataset/ ├── images/ │ ├── train/ # 约 8000 张 │ ├── val/ # 约 1000 张 │ └── test/ # 约 1000 张 ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml训练时 data.yaml 里的train和val指向images下的子目录,YOLO 会自动在同级的labels目录下找对应标签文件,不需要在配置文件里单独指定标签路径。test 目录用于最终模型评估,训练过程中不会碰它,防止验证集信息泄漏到模型调参的循环里。
资源中提到的train_list.txt记录的是训练集清单,一行一个相对路径。这个文件在 YOLO 训练里不是必需项,但部分课程设计或目标检测框架会要求提供。路径分隔符统一用正斜杠,Windows 下生成的\在 Linux 环境跑会失效。
3.4 划分结果的校验
划分完成后先做基本校验,再启动训练。命令行直接对比图片和标签数量:
find dataset/images/train -name "*.jpg" | wc -l find dataset/labels/train -name "*.txt" | wc -l两个数字不一致说明有图片缺标签或标签缺图片,顺着文件名差集去查。随后检查类别分布是否均衡,写一个简单的统计脚本:
from collections import Counter cat_map = {0: "bottle", 1: "can", 2: "paper"} counter = Counter() for file in os.listdir("dataset/labels/train"): with open(f"dataset/labels/train/{file}") as f: for line in f: cat_id = int(line.split()[0]) counter[cat_map[cat_id]] += 1 print(counter)如果统计出的比例和全量数据明显不一致,比如某个类在 train 里占比突然掉了 30%,说明这次随机划分的运气不好,重新 seed 再切一次。这类检查在 10000 张图时问题不大,但类别多、样本少的高校项目里几乎是必踩的坑。
4. YOLO 环境搭建与训练:Linux/Windows 双路径与 train 参数对照
资源里附带四份教程文档,分别覆盖 Linux 环境搭建、Windows 环境搭建和两套训练流程。整体思路是一致的:先装 PyTorch 和 ultralytics,再跑一个公开权重验证环境,最后换成自己的数据训练。
4.1 环境搭建的版本组合
YOLOv8 之后的版本都统一封装在 ultralytics 包里,不需要再从源码编译 darknet,环境搭建过程被大幅简化。推荐用 conda 管理环境,Linux 端典型命令序列:
conda create -n yolo python=3.10 conda activate yolo conda install pytorch=2.1.0 torchvision=0.16.0 pytorch-cuda=12.1 -c pytorch -c nvidia pip install ultralytics先装 PyTorch 再装 ultralytics,顺序不要反。如果先装 ultralytics,pip 可能拉一个 CPU 版本的 torch,后面训练时device=0直接报 CUDA 不可用。装完后验证 GPU 是否可见:
import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))打印True说明环境就绪。Windows 端流程一样,只是 CUDA 验证前先确认显卡驱动版本和 CUDA 版本的兼容性。用nvidia-smi查看驱动对应的最高 CUDA 版本,再选择不超过它的 PyTorch 版本。如果机器是 AMD 显卡,Windows 下官方支持有限,建议直接用 CPU 模式调试小数据集,或者换 Linux 环境跑,不要在这上面浪费太多时间。
4.2 训练自己的垃圾分类模型:修改 data.yaml
环境搭好后,训练自己的数据只需要改一个 yaml 文件。新建waste.yaml:
path: D:/waste_dataset train: images/train val: images/val names: 0: bottle 1: can 2: paper 3: plastic 4: glasspath是数据集根目录的绝对路径,Windows 下用正斜杠或双反斜杠,单反斜杠会被当成转义字符。train和val是相对于path的路径,YOLO 会自动拼接。names的顺序必须和 txt 标签里第一个数字的含义一致,这里如果写错,模型会一直学错目标。
资源里的训练教程强调要按自己的案例修改,实际上涉及的就是三块:yaml 的 names、类别数量、预训练权重的选择。类别数量由你的标签决定,不需要在 yaml 里显式填写,YOLO 会自动从names的键值个数判断。
4.3 train 关键参数与常见翻车点
4.3.1 训练命令以及参数含义
环境验证通过、yaml 配置完毕,启动训练的基准命令:
yolo detect train data=waste.yaml model=yolov8s.pt epochs=150 batch=16 imgsz=640 device=0| 参数 | 取值 | 说明 |
|---|---|---|
| model | yolov8s.pt | s 是精度和速度的平衡点,显存不够可换 yolov8n |
| epochs | 150 | 10000 张图的量级 100~150 轮足够 |
| batch | 16 | 6GB 显存建议 8,12GB 以上可到 32 |
| imgsz | 640 | 默认输入尺寸,小目标多可以提到 960 |
| device | 0 | 指定第一块 GPU,CPU 训练写 cpu |
用yolov8s.pt作为起点是迁移学习,模型会从公开权重继承通用视觉特征,比如边缘、纹理、颜色分布,这让垃圾分类模型在几十轮内就能收敛到不错的效果。如果从零开始训练,同样的数据量可能需要三倍以上的轮次才能达到接近的精度。
训练过程中盯住两个东西:box_loss和cls_loss。前者反映定位精度,后者反映分类精度。如果cls_loss稳定下降但box_loss在某个值附近震荡,大概率是标注框边界不准确。这份数据集的框质量高,一般不会出现严重的 box_loss 震荡。
4.3.2 数据增强的隐性参数
经验上,垃圾检测很容易遇到过拟合。原因是垃圾分类的拍摄场景高度集中,背景重复度高,模型容易记住背景而不是目标本身。处理方式是让默认的数据增强策略发挥作用。ultralytics 的默认增强里mosaic=1.0和mixup=0.0是关键项。mosaic 会把四张图拼成一张训练图,这个策略对垃圾检测效果显著,因为它强制模型在复杂背景下区分目标。
如果显存不足导致 mosaic 拼图时报错,关闭它:
yolo detect train data=waste.yaml model=yolov8s.pt epochs=150 batch=8 imgsz=640 mosaic=0.5mosaic=0.5表示一半训练样本使用拼图,另一半保持原始图。对垃圾这类尺度变化大的目标,不建议完全关闭 mosaic。
训练结束后,模型权重保存在runs/detect/train/weights/目录下,best.pt是验证集表现最好的一轮,last.pt是最后一轮。日常使用和部署都优先选best.pt。
5. 垃圾检测落地技巧:类别不均衡、小目标与 mAP 验证
训练完成后的第一步不是直接看精度,而是跑验证集,把输出的混淆矩阵调出来。这能直观地看出哪些类别互相混淆。如果发现瓶子和易拉罐经常被误判,说明这两类在像素层面过于接近,需要在类别定义或数据层面拆开处理。可视化这一阶段在垃圾检测里尤其重要,因为许多垃圾类别边界本来就模糊,比如纸盒和塑料袋都呈现蓬松质感。
验证命令如下:
yolo detect val model=runs/detect/train/weights/best.pt data=waste.yaml结果目录下会生成confusion_matrix.png和results.png。results.csv里有每个类别的mAP50和mAP50-95。前者衡量框和类别都准确的占比,后者对框位置更苛刻。垃圾检测场景中mAP50已经能反映业务表现,mAP50-95更多用来做模型选型对比。
资源数据的类别分布如果存在少数类,比如电池、灯泡这类样本量少的垃圾,在评估中会出现单类 AP 明显低于其他类别的情况。先用一条命令查看各分片里的类别频次,确定是哪一类在拖后腿。对这类数据,最直接的方式是让少数类参与过采样——把包含该类别的图片在 train 目录里多复制几份,同时保留它原来那份。复制不会改变标签文件内容,模型相当于多看到了几次这类样本,对缓解类别不均衡比调损失函数更直观。
小目标场景在垃圾检测里非常普遍,碎纸屑、烟蒂在画面上可能只占 30×30 像素。这类目标在 640 输入尺寸下特征极弱,训练时建议把imgsz提到 960,验证和推理时也保持同样尺寸。实际上提升输入分辨率对 mAP50-95 的改善通常最直接,代价是显存占用和推理时间上升。部署端如果对延迟敏感,可以在训练时用 960 输入,推理时保持 640,精度损失可以接受。
推理落地时给几个实用参数:
yolo predict model=best.pt source=test_phone.jpg conf=0.35 iou=0.45conf=0.35将置信度阈值从默认的 0.25 提高,垃圾检测场景建议保留略高的阈值,因为垃圾种类多、外观杂,低置信度输出里噪声比例偏高。iou=0.45控制 NMS 的合并严格度,值越小越容易合并重叠框。如果同一目标在预测结果里出现两个重叠框,适当降低iou;如果两个靠得很近的不同目标被错误合并成一个框,把这个值调大。调完这两个参数后再跑一遍同一张测试图,对比两次预测结果的框数量和类别,就能找到当前数据下最合适的组合。
本文还有配套的精品资源,点击获取