简介面向图像分类与目标检测场景的12种生活垃圾分类数据集包含衣服、塑料、废纸等常见生活垃圾类别可直接用于图像分类模型训练也适合作为YOLOv5分类任务的数据源。数据按文件夹保存train目录下有12,415张训练图片test目录下有3,100张验证图片经测试可直接用ImageFolder读取无需额外预处理。压缩包为7z格式共2000个文件其中jpg图片1998个、json分类字典1个、可视化py脚本1个总大小约231.04MB。json文件提供12种类别的字典映射py脚本支持随机抽取4张图片展示并保存无需修改即可运行便于快速检查数据质量与类别平衡。目前已有1370人学习下载数据类别划分清晰目录结构直观结合附带的工具脚本上手门槛很低适合需要规范垃圾分类图像数据及配套工具的开发者、学生和研究者。1. 12类生活垃圾分类数据集训练集和验证集拿到手先别急着训12 类生活垃圾分类数据集是图像分类里很常见也很接地气的一类资源。它不像 CIFAR、ImageNet 那样类别边界分明纸板、塑料瓶、玻璃瓶在不同光照和角度下长得非常像模型最终面对的往往是手机随手拍的画面。所以这份资源的重点不是“有多少张图”而是训练集和验证集的划分是否规范、标签是否一致这两点直接决定后面所有工作是不是白做。刚入门分类的新手可以用它直接开箱训练被脏数据折腾过的老手也能把它当标准样本重新验证自己的加载和评估流程。做毕业设计、智能桶 demo、环保小程序后端都可以拿它当起点。但拿到手第一件事不是训练而是先做三样检查目录结构、标签映射、图片完整性。这三样里任何一样有问题后面调参调得再勤都是无效劳动这也是下面所有内容围绕的核心。2. 先看透 12 类数据集目录结构、标签映射与完整性检查这类图像分类数据集下载下来通常是一个根目录内部按train/和val/两个大目录分开每个大目录下面再挂 12 个类别子目录。如果你用 torchvision 的ImageFolder加载目录名就是类别名子目录的排序顺序决定标签的数值索引。所以第一步永远是搞清楚目录里到底有什么而不是直接双击打开图片看热闹。2.1 目录结构与类别目录比对一个规范的分类数据集长这样train/下有 12 个类别目录val/下也有同样的 12 个类别目录两边目录名完全一致。拿到手先用两条命令把目录结构看透# 列出训练集的全部类别目录 ls train/ # 两行比对 train 和 val 的类别目录名是否完全一致 diff (ls train/) (ls val/) echo 类别一致逻辑说明ls train/只输出目录名不展开子目录diff (ls train/) (ls val/)用进程替换把两侧输出当作临时文件对比没有差异就往屏幕打“类别一致”有差异会直接列出两侧不一致的目录名。这是判断训练集和验证集标签体系是否对齐的最快方法比打开文件管理器肉眼核对靠谱得多。参数说明( )进程替换在 bash 和 zsh 下都可用macOS 默认终端和 Windows 下的 Git Bash 都支持。如果你用的是 Windows 命令提示符就换成先ls train/ a.txt、ls val/ b.txt再fc a.txt b.txt对比。不同版本的数据集目录名会有差异但生活垃圾基本围绕下面这些类别常见目录名对应物品分类难点glass玻璃瓶、玻璃碎片光照下反光容易误判成塑料plastic塑料瓶、塑料盒形态多变瓶盖和瓶身颜色差异大metal易拉罐、金属罐表面反光严重和玻璃件容易混paper纸箱、纸板折叠变形后轮廓不规整battery干电池体积小、样本少常被漏检lamp灯管、灯泡细长形旋转图中尤其难分medicine过期药品包装颜色丰富类内差异大food_waste果皮、菜叶背景复杂腐烂后颜色变化leftover剩菜剩饭和其他厨余高度相似clothes旧衣物折叠状态差异巨大shoes旧鞋视角敏感ceramics陶瓷碗碟反光且边缘不清晰实际目录名以你下载到的版本为准比如有的版本把纸类叫cardboard分类逻辑不变只是标签字符串不同。目录名不一致的问题会在第四章的避坑清单里单独讲这里先记住一个结论train 和 val 的目录名必须逐字一致。2.2 类间数量统计与不平衡判断目录名确认完了接着统计每个类别到底有多少张图。垃圾数据集的普遍现象是电池、灯管、药品这类有害垃圾样本数远少于塑料和纸板少的只有几十张多的上千张这种不平衡会在训练阶段带来很多隐性麻烦。for d in train/*/; do echo $(basename $d): $(ls $d | wc -l) done逻辑说明循环遍历train/下的每个类别目录basename $d只取目录名ls $d | wc -l统计该目录下文件数量输出形如battery: 124的逐类样本数。参数说明wc -l是按行数统计正常数据集文件名不含换行符统计值就是文件个数。如果某个类低于 100 张后面训练就必须考虑类别权重否则模型会对少数类彻底忽略这在第三章会给出具体做法。2.3 全量扫描损坏图片目录名和数量都没问题还不能开训。垃圾数据集里的图很多来自网页抓取和手机拍摄扩展名造假、传输中断、文件半截的情况非常常见。这种坏图片在 DataLoader 取数时才真正解码训练到一半突然崩掉定位成本远比现在扫一遍高。from PIL import Image import os root train bad_files [] for cls in sorted(os.listdir(root)): cls_path os.path.join(root, cls) if not os.path.isdir(cls_path): continue for f in sorted(os.listdir(cls_path)): fp os.path.join(cls_path, f) try: img Image.open(fp) img.verify() # 只解析文件头不完整解码 except Exception: bad_files.append(fp) print(损坏文件数:, len(bad_files)) for fp in bad_files[:10]: print(fp)逻辑说明Image.open是惰性打开的异常通常要等读取像素时才暴露verify()会强制解析文件头能把扩展名造假、半截下载、写入中断产生的坏文件筛出来。注意verify()之后这个文件句柄不能再用于读取所以这个脚本只做扫描不做后续加载。参数说明如果想顺带把 RGBA、灰度图也标记出来把img.verify()换成img.load()再检查img.mode遇到RGBA或L模式单独记录。我一般会把坏文件路径输出到bad.txt先人工看一眼是不是集中在某一类再决定是删还是补。3. 训练配置的参数怎么设ImageFolder、归一化与数据增强目录检查做完接下来就是把这套数据接进 PyTorch 的标准训练流程。这一章用的都是被反复验证过的常见做法ImageFolder自动生成标签、归一化参数直接复用 ImageNet 的均值方差、微调一个 resnet18 做基线。先把流程跑通再谈效果。3.1 用 ImageFolder 加载训练集和验证集from torchvision import datasets, transforms from torch.utils.data import DataLoader train_tf transforms.Compose([ transforms.RandomResizedCrop(224, scale(0.6, 1.0)), transforms.RandomHorizontalFlip(), transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) val_tf transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) train_ds datasets.ImageFolder(roottrain, transformtrain_tf) val_ds datasets.ImageFolder(rootval, transformval_tf) train_loader DataLoader(train_ds, batch_size32, shuffleTrue, num_workers4, pin_memoryTrue) val_loader DataLoader(val_ds, batch_size32, shuffleFalse, num_workers4, pin_memoryTrue) print(类别数:, len(train_ds.classes)) print(标签映射:, train_ds.class_to_idx)逻辑说明ImageFolder会按目录名字典序生成class_to_idx训练集和验证集只要目录名相同映射就是同一套这也是第二章反复强调先比对目录名的原因。训练侧做随机裁剪、水平翻转、颜色抖动验证侧只做等比缩放加中心裁剪保证评估时的输入稳定、可复现。参数说明RandomResizedCrop(224, scale(0.6, 1.0))的 scale 控制裁剪面积比例生活垃圾图片背景杂乱用 0.6 起步比较稳如果发现过拟合把ColorJitter的强度降到 0.1。batch_size要根据显存选参考下面这张表显存建议 batch_size备注6G16输入尺寸 224 时比较稳12G32最常见配置24G 以上64显存够也要先试 32 对比收敛num_workers在 Linux 上可以设成 CPU 核数减一Windows 上多进程加载经常报错直接设 0 最省事等全部流程跑通再调。把批大小从小到大试几轮再定下来这事情有点玄学但先跑通比先跑快重要。3.2 为类别不平衡加权重12 类垃圾数据几乎没有哪一版是完全平衡的电池、灯泡、药品这类有害垃圾数量明显偏少。常见的做法是给CrossEntropyLoss传class_weight让少数类样本在 loss 里获得更大的权重从而拿到更大的梯度。import torch from collections import Counter counts Counter([y for _, y in train_ds.samples]) num_classes len(train_ds.classes) total sum(counts.values()) weights [] for cls_idx in range(num_classes): weights.append(total / (num_classes * counts[cls_idx])) class_weights torch.tensor(weights, dtypetorch.float32) criterion torch.nn.CrossEntropyLoss(weightclass_weights) print(class_weights)逻辑说明权重公式是总数 / (类别数 × 该类样本数)样本多的类权重小于 1样本少的类权重大于 1。这样 loss 不会因为少数类样本量少而被多数类淹没训练过程中少数类也能保持存在感。参数说明这个权重只用于训练时的 loss验证阶段计算 accuracy 不要带权重否则指标会虚高。如果加了权重后多数类反而明显掉点可以做一下平滑比如(1 - alpha) alpha * walpha 取 0.5 左右能缓解多数类被过度压制的现象。3.3 微调一个图像分类模型做基线12 类分辨任务用 resnet18 已经足够强行上 resnet50 只会增加过拟合风险。加载 ImageNet 预训练权重后做全量微调比从头训练收敛快得多。import torchvision.models as models import torch.nn as nn model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) model.fc nn.Linear(model.fc.in_features, 12) optimizer torch.optim.SGD(model.parameters(), lr0.001, momentum0.9, weight_decay5e-4)逻辑说明把最后一层全连接改成 12 输出其余层复用预训练权重。垃圾图像属于细粒度分类细节差异集中在纹理和边缘weight_decay不能开太大否则特征学习会被压制。参数说明lr0.001是全量微调的常用起点。如果显存紧张或者数据量特别少可以只微调最后两层把前面层的requires_grad置为False学习率可以放到 0.01。weight_decay保持 5e-4 附近不要随手加到 1e-2那会让收敛速度明显变慢。4. 训练集与验证集的避坑清单五个翻车现场与补救方法下面五条是在这类垃圾图像分类数据集上踩过的坑每条按现象、原因、解决三步整理。新手照着排查能省下半天调试时间老手可以重点看后三条因为它们最容易被误判成模型结构问题实际上是数据和指标口径的问题。4.1 训练和验证的类别目录对不上现象训练 loss 正常下降验证 accuracy 却一直卡在 20% 左右打印train_ds.classes和val_ds.classes发现两边目录名不一致。原因数据集作者拼接了不同来源的图片比如“果皮”在 train 里叫fruit_peel在 val 里叫peel或者整理过程中手工改过一部分目录名。解决先跑diff (ls train/) (ls val/)不一致就统一目录名再重新生成验证集。如果两边类别语义本来就不同别强行合并只保留两边共有的类重新划分。这个错位最坑的地方在于程序不会报错只是验证指标莫名地差很多人会误以为模型没调好其实问题在数据目录本身。我习惯在执行训练脚本前再跑一句python -c from torchvision import datasets; adatasets.ImageFolder(train); bdatasets.ImageFolder(val); print(a.classesb.classes)返回True才继续往下走。4.2 坏图让训练中途崩溃现象训练到某个 epoch 突然抛PIL.UnidentifiedImageError或OSError: broken data stream而且报错文件路径每次固定不变调整随机种子也没用。原因部分图片是爬虫抓来的假扩展名文件或者传输中断留下半截文件ImageFolder在 DataLoader 取数时才真正解码坏图到训练中段才暴露。解决训练前用第二章的verify()脚本全量扫一遍把坏文件移出数据集目录跑第一个 epoch 前再打印一次加载成功数量确认和ls | wc -l统计值一致。这类坏图通常集中在少数类里比如电池类大量来自旧网页抓取坏图比例能超过 5%。把坏图路径输出到文件后顺手看一眼是不是集中在某一类是的话那类还需要额外补样本只删不掉不是终点。4.3 验证集和训练集重叠指标虚高现象验证 accuracy 高得异常比如 99%但换到真实拍摄的照片上识别率掉一半类别越少越明显。原因划分时用了同源图片比如按文件名排序后切前 80% 当 train同一物体的不同帧被分到两边有些数据集本身存在重复采样。解决按文件内容做哈希去重保证任何一张图只出现在一侧划分时用StratifiedKFold按类别比例切不要用纯随机切。# 按 MD5 找出 train 和 val 里的重复图片 find train val -type f \( -name *.jpg -o -name *.png \) \ -exec md5sum {} | sort -k1,1 | uniq -w 32 -d逻辑说明md5sum按文件内容生成哈希值文件名不同不影响判断sort -k1,1按哈希排序uniq -w 32 -d只输出重复出现的内容指纹。如果这条命令有输出说明两边存在同内容图片必须进一步处理。参数说明-w 32表示只比较哈希值前 32 个字符正好是 md5 的长度。垃圾数据集常见的是几十张到几百张重复处理完后再跑一次确认输出为空才算干净。4.4 类别不平衡让单值 accuracy 失真现象报告显示整体 accuracy 90%但电池、灯泡每类 recall 只有 30%模型几乎把这些类全判成塑料或纸板。原因多数类样本量占优模型只要猜多数类就能拿高分单值 accuracy 完全掩盖少数类失效。解决训练时加class_weight或对少数类做复采样评估时打印classification_report看 macro F1 和每类 recall不看单值 accuracy。这不是训练 bug是评估指标选错了。分类报告里的 macro avg 是把每类指标平均少数类表现差会直接被拉低比单值 accuracy 诚实得多。后面第五章的混淆矩阵代码就是干这件事的。4.5 验证集图像尺寸和通道不一致现象val 上指标波动大换台机器或者换个 seed 结果都不一样训练集上却正常。原因数据集里混入 RGBA 图、灰度图或者带 EXIF 旋转信息的图Resize后通道数和方向不一致模型推理时行为不稳定。解决预处理最前面统一Image.open(fp).convert(RGB)ToTensor之后加一句断言确认张量是(batch, 3, H, W)不是 4 通道也不是 1 通道。RGBA 图在ToTensor后是 4 通道如果模型第一层是 3 通道卷积要等到真正 forward 时才报错而且报错信息不指向具体文件排查特别费劲。所以convert(RGB)一定要放在预处理管线的最前面而不是等出错再补。提示以上五条里前两条会直接让训练崩溃或指标失真后三条会让模型“看起来能用、实际不能打”。我的习惯是整理成一份prepare_data.py每次拿到新数据集先跑一遍检查再进训练。5. 调优的最后一公里混淆矩阵、类别权重与误分类检查训练跑完别急着写“准确率 92%”的结论。垃圾图像分类这类细粒度任务验收标准应该是具体的错判对不是单值 accuracy。分类模型最怕的就是不知道自己错在哪混淆矩阵就是把这块黑匣子打开的工具。from sklearn.metrics import confusion_matrix, classification_report import torch y_true, y_pred [], [] model.eval() with torch.no_grad(): for x, y in val_loader: out model(x) y_true.extend(y.tolist()) y_pred.extend(out.argmax(dim1).tolist()) report classification_report(y_true, y_pred, target_namestrain_ds.classes) print(report) cm confusion_matrix(y_true, y_pred)逻辑说明classification_report给出每类的 precision、recall、F1confusion_matrix给出具体的错判对分布。对垃圾数据集我最关心的不是整体 accuracy而是塑料、玻璃、纸板这组相互错判的数量因为线下使用时分不清的主要就是这类反光物体。参数说明target_namestrain_ds.classes保证输出标签和目录名对应如果类别顺序对不上先打印train_ds.class_to_idx对齐。分类数量不大直接用 sklearn 就可以不需要额外做可视化。拿到混淆矩阵后只看两个地方哪两类互相错判最多针对它们去补数据或者加后处理少数类 recall 偏低的结合第三章的类别权重再做一轮微调。这是我从一堆分类项目里总结出的血泪经验单值 accuracy 上涨 1 个点不一定说明模型变好了可能只是多数类多猜对了几张而一对具体的错判被修掉才是真正能落地的进步。我在调完最后一轮后还会做一次“单手举手机”测试随便找几张白天室内实拍的塑料瓶、玻璃瓶照片过一遍模型。验证集图片再规范也不等于真实拍摄条件这个测试花不了五分钟但能提前暴露很多评估报告看不到的问题。从那以后我每次拿到这类图像分类数据集都会强制把目录比对、坏图扫描、混淆矩阵这三件事走一遍才开始训练数据检查的时间从不省。希望帮到你。本文还有配套的精品资源点击获取