简介:这份资源面向计算机视觉入门与进阶学习者、课程设计及科研人员,提供一套可直接用于YOLO系列目标检测训练的垃圾分类数据集。数据均为真实场景采集,覆盖多种复杂环境,使用labelimg精细标注,标注框质量较高,并同步提供voc(xml)、coco(json)与yolo(txt)三种格式标签,分别存放于独立文件夹,便于直接接入不同训练框架。压缩包共约2000个文件,以1985个xml标注文件为主,另含少量txt、html与py脚本,整体约410MB,目录结构清晰。资源还附赠数据集划分脚本,可按需生成训练集、验证集与测试集,并配套Windows与Linux环境搭建及训练案例教程,帮助读者快速跑通从环境配置到模型训练的全流程。目前已有1346人学习下载,适合需要快速验证算法、完成课程作业或开展垃圾分类检测实验的读者参考使用。
1. 一万张垃圾图 + 三格式标签:这套 YOLO 数据集到底能不能直接开训
手上接到一个垃圾分类检测的活儿,第一反应往往不是选模型,而是找数据。自己拍、自己标、自己转格式,一万张图走完这套流程,两周就没了。这套资源的核心价值就在这儿:10000 张真实场景垃圾图片,labelImg 标注,voc(xml)、coco(json)、yolo(txt) 三种标签格式分文件夹放好,外加划分脚本和 Windows/Linux 双版本环境搭建与训练教程。它解决的是「数据从哪来、格式怎么统一、训练怎么起步」这三个最耗时的环节。适合刚接触 YOLO 目标检测、想跑通自己第一个垃圾分类模型的工程师,也适合手上有算法但缺数据的团队直接拿来做 baseline。下面我按「数据长什么样 → 怎么划分 → 怎么配环境 → 怎么训 → 坑在哪」的顺序拆一遍。
2. 三格式标签与目录结构:先搞清楚手里到底有什么
2.1 voc、coco、yolo 三种标签的差异与选用
这套数据集最省事的地方,是同一批标注同时给了三种格式。很多人拿到手第一反应是「我该用哪个」,答案取决于你走哪条训练链路。
voc 格式是每张图对应一个 xml 文件,里面用<object>节点记录类别名和xmin/ymin/xmax/ymax四个角点坐标,坐标是绝对像素值。coco 格式是一个大的 json,用images、annotations、categories三个数组组织,bbox 是[x, y, width, height]且为绝对像素。yolo 格式是每张图一个 txt,每行类别索引 cx cy w h,全部归一化到 0~1。
选型上,如果你用 ultralytics 系的 YOLOv5/v8,直接吃 yolo 格式最省事,不用转。如果你要用 mmdetection 或者做 COCO 指标评测,coco json 更顺。voc 更多是历史遗留和 labelImg 的原生输出,适合做格式转换的中间态。三种格式并存的好处是:你不需要为了换框架重新标一遍。
| 格式 | 文件形态 | 坐标类型 | 典型用途 |
|---|---|---|---|
| voc | 每图一个 xml | 绝对像素 | labelImg 原生、转换中间态 |
| coco | 单个 json | 绝对像素 | mmdetection、COCO 评测 |
| yolo | 每图一个 txt | 归一化 0~1 | YOLOv5/v8 直接训练 |
2.2 目录组织与类别索引对齐
拿到压缩包解压后,常见做法是 images 和 labels 平行放,labels 下再按格式分。这里有个血泪经验:yolo 的类别索引是纯数字,0 0.53 0.41 0.22 0.18这种,它本身不带类别名。类别名和索引的映射关系通常写在classes.txt或者data.yaml里。如果你自己重新排了类别顺序,而 txt 里的索引没跟着改,训练时模型学到的就是错位的类别,loss 能降但预测全是乱的。
所以第一步不是急着训,是先确认三件事:类别总数是多少、classes.txt里的顺序是什么、yolo txt 里出现的最大索引有没有超过类别数减一。用一段脚本几秒钟就能查完:
import os label_dir = "labels/yolo" classes_file = "classes.txt" with open(classes_file, "r", encoding="utf-8") as f: classes = [line.strip() for line in f if line.strip()] print(f"类别数: {len(classes)}, 类别: {classes}") max_idx = -1 bad_files = [] for name in os.listdir(label_dir): if not name.endswith(".txt"): continue with open(os.path.join(label_dir, name), "r") as f: for line in f: parts = line.strip().split() if not parts: continue idx = int(parts[0]) max_idx = max(max_idx, idx) # 坐标必须在 0~1 之间,越界说明标注或转换有问题 coords = [float(x) for x in parts[1:5]] if any(c < 0 or c > 1 for c in coords): bad_files.append(name) break print(f"最大类别索引: {max_idx}") print(f"坐标越界文件数: {len(bad_files)}") if bad_files[:5]: print("示例:", bad_files[:5])这段脚本干两件事:一是把类别数和索引上限对一下,二是扫一遍所有 yolo txt 的坐标有没有越界。归一化坐标理论上都在 0~1,出现负数或大于 1,要么是标注时框拖出了图外,要么是转换脚本算错了。越界框在训练时会被裁掉或者产生异常梯度,早发现早处理。参数上label_dir指向你的 yolo 标签目录,classes_file指向类别名文件,路径按实际解压位置改。
3. 数据集划分脚本:train/val/test 怎么切才不翻车
3.1 三个划分脚本的分工
资源里给了三个划分脚本,名字就能看出用途:训练集、验证集、测试集划分脚本是三路切分,训练集、验证集划分脚本是两路切分,split_train_val生成ImageSets下txt文件划分脚本是生成 ImageSets 目录下 txt 清单的。前两个是「把图片和标签复制/移动到新文件夹」,第三个是「只生成文件名清单,不动原文件」。
这两种思路差别很大。复制式划分会实实在在产生三份图片副本,磁盘占用翻倍甚至三倍,但好处是每个子集独立、不会互相干扰。清单式划分只写 txt,训练时靠 txt 里的路径去读原图,省空间,但要求你的训练代码支持从清单读。YOLOv5/v8 默认是按目录读的,所以如果你用官方训练脚本,复制式更直接;如果你自己写 DataLoader,清单式更灵活。
我一般会先跑清单式确认划分比例合理,再决定要不要落成物理副本。因为划分这事最怕的是「切完发现某类样本在验证集里几乎没有」,那时候再改就得重来。
3.2 按 8:1:1 切分并保持类别分布
随机切分有个隐蔽的坑:小类别可能被随机切没了。垃圾分类里如果有个类别只有几十张图,纯随机切分很可能验证集里一张都没有,训出来的模型在这个类上没法评估。稳妥做法是按类别分层抽样。下面这段是常见的分层划分写法:
import os import random import shutil from collections import defaultdict random.seed(42) # 固定种子,保证可复现 img_dir = "images" label_dir = "labels/yolo" out_root = "dataset_split" train_ratio, val_ratio = 0.8, 0.1 # 剩下 0.1 给 test # 按类别归组:一张图可能含多个类别,取第一个类别作为分层依据 cls_to_imgs = defaultdict(list) for name in os.listdir(label_dir): if not name.endswith(".txt"): continue stem = os.path.splitext(name)[0] with open(os.path.join(label_dir, name)) as f: lines = [l for l in f if l.strip()] if not lines: continue main_cls = int(lines[0].split()[0]) cls_to_imgs[main_cls].append(stem) for split in ["train", "val", "test"]: os.makedirs(os.path.join(out_root, split, "images"), exist_ok=True) os.makedirs(os.path.join(out_root, split, "labels"), exist_ok=True) for cls, stems in cls_to_imgs.items(): random.shuffle(stems) n = len(stems) n_train = int(n * train_ratio) n_val = int(n * val_ratio) buckets = { "train": stems[:n_train], "val": stems[n_train:n_train + n_val], "test": stems[n_train + n_val:], } for split, items in buckets.items(): for stem in items: shutil.copy(os.path.join(img_dir, stem + ".jpg"), os.path.join(out_root, split, "images", stem + ".jpg")) shutil.copy(os.path.join(label_dir, stem + ".txt"), os.path.join(out_root, split, "labels", stem + ".txt")) print("划分完成")逻辑上先按主类别把图片分组,再在每组内部按比例切,这样每个类别在三个子集里都有代表。random.seed(42)是后悔药,保证你下次跑结果一样,方便复现和排查。train_ratio和val_ratio按需改,剩下自动归 test。图片扩展名这里写死.jpg,如果你的图是.png或.jpeg,得改成对应后缀,或者用os.path.splitext动态取。这一步跑完,dataset_split下就是标准的三份数据,可以直接喂给 YOLO。
提示:划分前先备份原始标签目录。复制式脚本一旦路径写错,可能把源文件覆盖掉,这种翻车我见过不止一次。
4. 环境搭建与训练:Windows 和 Linux 两条路怎么走
4.1 环境搭建的关键依赖与版本对齐
资源里给了 Windows 和 Linux 两套环境搭建教程,还有 Ubuntu 安装教程。核心依赖就那几个:Python、CUDA、cuDNN、PyTorch、ultralytics。真正容易出问题的不是装不上,是版本对不齐。PyTorch 的 CUDA 版本必须和系统驱动支持的 CUDA 版本匹配,否则torch.cuda.is_available()返回 False,训练直接掉到 CPU 上,一万张图能跑到你怀疑人生。
常见做法是先nvidia-smi看驱动支持的最高 CUDA 版本,再去 PyTorch 官网找对应版本的安装命令。比如驱动支持 CUDA 12.1,就装 cu121 的 torch。装完立刻验证:
python -c "import torch; print(torch.__version__, torch.cuda.is_available(), torch.cuda.get_device_name(0))"输出里True和显卡型号都在,才算环境通了。如果显示 False,先别急着训,回去查驱动和 torch 版本。这一步省下来的时间,比后面调参省的多。
4.2 用 data.yaml 接上数据集并启动训练
YOLOv5/v8 训练靠一个data.yaml描述数据位置和类别。按第 3 章切好的目录,写出来大概是这样:
path: ./dataset_split train: train/images val: val/images test: test/images nc: 4 names: ['recyclable', 'kitchen', 'hazardous', 'other']nc是类别数,names顺序必须和 yolo txt 里的索引严格对应,第 0 个名字对应索引 0。path是根目录,下面的 train/val/test 是相对路径。写完直接起训:
yolo detect train data=data.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16model选预训练权重,imgsz是输入尺寸,batch按显存调,显存不够就往下压。训练过程中重点看mAP50和各类的instances数量,如果某个类 instances 一直是 0,说明划分或标签索引有问题,回去查第 2 章那段校验脚本。
5. 避坑与排查:这几处翻车点我替你踩过了
5.1 类别索引错位导致 loss 正常但预测全乱
现象:训练 loss 平稳下降,mAP 却低得离谱,预测框位置对但类别全是错的。 原因:data.yaml里names的顺序和 yolo txt 里的数字索引没对齐,或者你重新排了类别但没改标签。 解决:跑第 2 章的校验脚本,确认最大索引小于nc,再逐行核对names顺序和classes.txt是否一致。改完重新训,别在错位的数据上继续调参。
5.2 坐标越界引发异常框
现象:训练日志里偶尔报坐标异常,或者可视化时框跑到图外。 原因:标注时框拖出边界,或 voc 转 yolo 时归一化除错了宽高。 解决:用第 2 章脚本扫出越界文件,手动重标或裁剪坐标到 0~1。批量处理时把越界值 clamp 到边界,但更稳妥是回源头修标注。
5.3 验证集某类样本为零
现象:训练完发现某个类别的 mAP 是 0 或 nan。 原因:随机划分把小类别全切到训练集了。 解决:改用第 3 章的分层抽样脚本,按类别分组后再切。切完统计每个子集各类的图片数,确认没有空类。
5.4 CUDA 版本不匹配导致训练掉 CPU
现象:torch.cuda.is_available()返回 False,训练速度极慢。 原因:PyTorch 的 CUDA 版本和系统驱动不匹配。 解决:nvidia-smi看驱动支持版本,重装对应 cu 版本的 torch。别用 conda 默认源瞎装,容易装到 CPU 版。
5.5 图片和标签文件名不一致
现象:训练时报找不到标签,或者部分图被跳过。 原因:划分或重命名时图片和 txt 的 stem 没对上,比如图是img_01.jpg标签是img_1.txt。 解决:写个脚本比对两个目录的文件名集合,差集就是问题文件。统一用 stem 匹配,扩展名只影响图片读取。
6. 进阶:用训练好的模型做推理与置信度调优
训完模型只是开始,真正上线前得会调推理参数。YOLO 推理时有两个关键阈值:conf置信度门限和iouNMS 的 IoU 阈值。垃圾分类场景里,如果漏检多就把conf调低,如果同一个垃圾被框了好几次就把iou调低。这两个参数没有万能值,得拿验证集试。
yolo detect predict model=runs/detect/train/weights/best.pt source=test_images conf=0.25 iou=0.45 save=Trueconf=0.25是常见起点,iou=0.45控制重叠框合并。跑完看runs/detect/predict下的可视化结果,重点看小目标(比如烟头、瓶盖)有没有被漏掉。如果漏检集中在某一类,先别急着调参,回去看这一类在训练集里的样本量和标注质量,很多时候是数据问题不是参数问题。
我一般会在验证集上跑一组 conf 从 0.1 到 0.5 的对比,画一条 precision-recall 曲线,选 F1 最高的那个点作为上线门限。这套流程走下来,模型才算真正能用。从那以后我每次拿到新数据集,都强制先跑一遍类别索引校验和划分统计,再动训练脚本——这两步花十分钟,能省掉后面几小时的无效训练。希望帮到你。
本文还有配套的精品资源,点击获取