
简介生活中真实废弃物图像分类数据集是一份面向计算机视觉入门学习与垃圾分类应用开发的标注数据资源包含约4800张真实场景图片涵盖纸板、食品有机物、玻璃、金属、杂项垃圾、纸张、塑料、纺织品垃圾和植被等9个常见类别适合用于训练图像分类网络或验证模型在不同垃圾材质上的泛化能力。数据已经过预处理并划分好训练集与测试集类别目录清晰图片来自真实生活场景背景与光照较为自然能更真实地反映实际垃圾分类任务中的输入分布。压缩包内含2000个文件其中1998张JPG图像可直接送入分类网络训练或测试1个Python脚本用于快速可视化数据集并检查标注质量1个JSON文件记录类别配置整体大小约156MB。已有65人学习下载上手门槛较低研究者和开发者可基于此快速开展垃圾分类相关实验省去数据采集与标注环节也可作为算法效果对比的基准数据。1. 这个标题真正解决的问题真实现场照片和“摆拍数据集”之间的落差做垃圾分类识别或废弃物检测的朋友应该都经历过这种翻车网上公开的垃圾数据集照片拍得整整齐齐瓶子规规矩矩立在纯色背景上模型训练完准确率能上 95%一放到小区回收箱或者保洁阿姨手里那台旧手机上直接开始乱报。这背后的差距不在模型而在数据本身。生活中真实废弃物图像分类数据集【已标注约4,800张数据】这样的项目要解决的正是“真实拍摄条件下废弃物图像分类”的落地难题视角混乱、背景复杂、光照不稳定、瓶罐互相遮挡。约 4,800 张的规模不大不小适合做迁移学习微调也适合验证从标注到训练再到部署的完整小闭环。这篇文章会把这类数据集从拆解、清洗到训练和踩坑讲透给准备动手的读者一条能直接走通的路。2. 拆开数据集看门道类目口径、标注格式与验证集策略2.1 先把“类目表”和标注口径对清楚拿到任何一份“已标注”的废弃物图像数据我做的第一件事不是急着训练而是先看类别表。如果是自己采集的常见做法是按回收价值和使用频率分 6 到 12 类塑料瓶、易拉罐、纸箱纸板、玻璃瓶、织物衣物、厨余垃圾、塑料袋膜、有害垃圾电池、灯管等。几十个细分类别对 4,800 张来说太散了分分钟出现某个类只有二三十张的情况后面训练会很难受。我看到真实废弃物数据时最关心的是“标注口径”。同样是“纸”是只框纸箱还是包括报纸、纸杯这类带塑料覆膜的纸制品同样是“瓶子”装着半瓶水的塑料瓶怎么算“已标注”这三个字只说明有人动过标签不说明标签定义和你业务一致。我一般会先打印一张类目表对着实际图片抽查每个类至少 30 张确认边角料和歧义样本的标注方式。这一步省不掉后面所有指标都建立在这个口径之上。如果类目定义不清尽早做合并。比如我有一次把“玻璃瓶”和“碎玻璃”分成两类结果碎玻璃样本只有十几张训练出来完全不可用后来干脆统一成“玻璃制品”指标立刻稳定。对小型数据集来说类目数量控制在 8 类以内比追求细粒度分类可靠得多。2.2 4,800 张的常见组织方式与验证集保留策略这种量级的数据集文件组织方式大多是按类别分文件夹的 ImageFolder 结构极少数会带 CSV 或 JSON 标注文件。如果是按文件夹组织训练代码写起来最简单PyTorch 的torchvision.datasets.ImageFolder直接就能读。组织方式如下这是约定俗成的结构拿到数据后建议先整理成这个样子waste_dataset/ ├── train/ │ ├── plastic_bottle/ │ ├── aluminum_can/ │ ├── paper/ │ ├── glass/ │ └── fabric/ └── val/ ├── plastic_bottle/ ├── aluminum_can/ ├── paper/ ├── glass/ └── fabric/划分比例上我常用 8:1:1也就是约 3,840 张训练、480 张验证、480 张测试。这里有个关键教训如果原始数据是从视频里按帧抽出来的同一个瓶子在连续几帧里会出现很多次直接随机切分会让训练集和验证集里出现“同一物体”验证指标会虚高。正确做法是先按拍摄场景或视频片段分组同一个场景的帧必须全部划到同一个集合里不能跨集合。我还会顺手做一次哈希去重。很多公开的真实场景数据收集时会重复采样通过 dhash 或 md5 去重能砍掉不少冗余图片。实测 4,800 张里去重后可能只剩 4,500 张左右有效数据这种损耗是正常的。验证集数量不足时宁可从训练集里再挤一点过去也不要让验证集低于每类 30 张。2.3 拿到压缩包后我干的第一件事跑一遍资产体检“已标注”不代表没毛病。真实废弃物照片里模糊、过曝、文件损坏、完全空白的垃圾图都很常见。我用一段脚本做资产体检检查三件事每类数量分布、图像尺寸分布、损坏文件数量。import os from PIL import Image from collections import Counter train_dir path/to/waste_dataset/train stats Counter() bad_files [] sizes [] for class_name in os.listdir(train_dir): class_path os.path.join(train_dir, class_name) if not os.path.isdir(class_path): continue stats[class_name] len(os.listdir(class_path)) for fname in os.listdir(class_path): fpath os.path.join(class_path, fname) try: with Image.open(fpath) as im: sizes.append(im.size) except Exception: bad_files.append(fpath) print(每类数量, dict(stats)) print(损坏文件数量, len(bad_files)) if sizes: min_side min(min(w, h) for w, h in sizes) print(最小边小于224像素的图片数量, sum(1 for w, h in sizes if min(w, h) 224))这段脚本的逻辑是按类别目录遍历所有图片统计每类数量并尝试用 PIL 打开图片。打不开的就是损坏文件应直接从数据集中剔除或替换。尺寸统计则用于确认是否有大量过小的图片如果很多图的最小边都小于 224 像素训练时 Resize 到 224 会产生严重形变需要放弃这些图或提前做超分预处理不能直接丢进模型。我做这个体检时还会顺手输出 20 张每类的随机样例拼成一张网格图肉眼快速过一遍。这种“先体检后训练”的习惯能省下后面排错的时间比直接跑 baseline 靠谱得多。3. 用 PyTorch 在真实废弃物数据上跑通分类流程从数据增强到微调3.1 数据增强针对真实场景的关键参数设置真实废弃物照片和公开数据集最大的区别在于拍摄条件不可控。垃圾桶里的瓶子可能是歪的隔着塑料袋拍的纸箱是模糊的夜间的易拉罐颜色偏掉。所以数据增强不能只用 Resize 和归一化要针对场景做三个针对性配置随机缩放裁剪模拟拍摄距离变化、旋转模拟角度变化、颜色抖动模拟光照差异。import torch from torchvision import datasets, transforms, models from torch.utils.data import DataLoader train_tf transforms.Compose([ transforms.RandomResizedCrop(224, scale(0.5, 1.0)), transforms.RandomHorizontalFlip(p0.5), transforms.RandomRotation(degrees20), transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.1), 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_set datasets.ImageFolder(path/to/waste_dataset/train, train_tf) val_set datasets.ImageFolder(path/to/waste_dataset/val, val_tf) train_loader DataLoader(train_set, batch_size32, shuffleTrue, num_workers4) val_loader DataLoader(val_set, batch_size32, shuffleFalse, num_workers4)这里的scale(0.5, 1.0)很关键。公开分类数据集常用的 scale 下限是 0.08但对废弃物场景来说裁剪比例太小会让模型学到“某个局部纹理”而不是“物体整体”所以我把下限收紧到 0.5模拟的是相机靠近和远离物体的距离变化范围。RandomRotation是模拟废弃物随手丢在地上的任意角度。ColorJitter的亮度扰动调到 0.2 是为了覆盖室内外光照差异但饱和度扰动只给 0.1避免把塑料瓶和易拉罐的颜色信息破坏掉。3.2 迁移学习选型为什么从 ResNet 起步4,800 张训练数据对深度学习模型来说只能算“小数据”。从头训练一个 ResNet 或者 Vision Transformer 都会严重过拟合正确路线是加载 ImageNet 预训练权重只替换最后的全连接分类层。基础选型上我建议直接选 ResNet18 或 ResNet34而不是一上来就上大模型。原因很简单废弃物分类的判别特征大多是颜色、纹理、轮廓ResNet18 已经足够模型太大在后期部署到手机或边缘设备时反而被嫌弃。import torch.nn as nn device torch.device(cuda if torch.cuda.is_available() else cpu) num_classes len(train_set.classes) model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) model.fc nn.Linear(model.fc.in_features, num_classes) model.to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.SGD(model.parameters(), lr1e-3, momentum0.9, weight_decay1e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max30)替换model.fc这一行是迁移学习的核心操作。in_features从预训练模型里自动取出倒数第二层的维度num_classes由数据集自动推断。全连接分类层是随机初始化的前面的卷积层保留的是 ImageNet 上学到的通用纹理和形状特征它们对废弃物识别同样有价值。优化器我习惯先用 SGD 加动量而不是 Adam因为在小数据集迁移学习场景下SGD 配合余弦退火的泛化能力通常更好。weight_decay1e-4起正则作用初始化学习率 1e-3 是一个比较稳的起点。3.3 训练循环与评估指标为什么准确率不够用训练循环本身不复杂但有两个细节值得特别注意。第一是每轮训练后必须在验证集上算“宏平均 F1”而不是只看整体准确率。真实废弃物数据普遍存在类别不平衡塑料瓶可能占了三分之一样本如果只看准确率模型只要把所有图都预测成塑料瓶就能拿 60% 以上的准确率看起来“还行”实际毫无用处。第二是学习率调度我用CosineAnnealingLR而不是 StepLR让学习率在训练后期平滑下降对提升小数据集上的收敛稳定性有帮助。import numpy as np from sklearn.metrics import f1_score, confusion_matrix for epoch in range(30): model.train() running_loss 0.0 for images, labels in train_loader: images, labels images.to(device), labels.to(device) outputs model(images) loss criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step() running_loss loss.item() model.eval() all_preds, all_labels [], [] with torch.no_grad(): for images, labels in val_loader: images, labels images.to(device), labels.to(device) outputs model(images) _, preds torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.cpu().numpy()) f1 f1_score(all_labels, all_preds, averagemacro) acc np.mean(np.array(all_preds) np.array(all_labels)) print(fEpoch {epoch1}/30 | Loss: {running_loss/len(train_loader):.4f} | Acc: {acc:.4f} | Macro F1: {f1:.4f})这段代码在每轮 epoch 结束后把验证集所有预测收集起来同时计算整体准确率和宏平均 F1。宏平均 F1 对每个类一视同仁少数类的表现会直接拖低分数所以它是判断这类不平衡数据分类效果比准确率更靠谱的指标。我一般还会在训练结束后打印一份混淆矩阵专门看哪些类互相打架这个信息后面的避坑章节会详细展开。4. 真实废弃物数据的五个典型坑位从标注噪声到类别不平衡的排错笔记4.1 训练集是“干净背景”应用时是垃圾桶模型直接翻车现象训练时验证集准确率 94%把模型部署到真实场景后面对同一种塑料瓶预测结果在几个类别之间反复横跳。原因训练集里相当一部分图片是回收站或桌子上的单物体照片背景是纯色墙面或桌面模型学到了“背景纹理”而不是“瓶子形状”。解决在训练增强里加入RandomErasing随机擦除模拟物体被遮挡的情况同时刻意增加套着垃圾袋、混有其他杂物这类“脏场景”图片。框架自带实现加在ColorJitter之后即可from torchvision.transforms import RandomErasing transforms.RandomErasing(p0.25, scale(0.02, 0.15), ratio(0.3, 3.3))参数p0.25表示四分之一概率对图片做擦除scale控制擦除面积占整张图的比例。真实废弃物场景中物体经常被部分遮挡特别是瓶子被塑料袋半盖住的情况很常见。加上擦除增强后模型被迫关注剩余可见区域比靠完整轮廓识别更接近真实场景。4.2 某类样本太少模型“直接放弃治疗”现象训练结束发现“织物”这一类在混淆矩阵里几乎全被预测成“塑料膜”。原因两类别在纹理上接近而织物样本只有总量的 2%模型发现把它全判成塑料膜能把整体损失降得更低就主动放弃了少数类。解决用WeightedRandomSampler替代默认随机采样让每个 batch 里各类别出现概率均衡。from torch.utils.data.sampler import WeightedRandomSampler class_counts [train_set.targets.count(i) for i in range(num_classes)] weights [1.0 / class_counts[t] for t in train_set.targets] sampler WeightedRandomSampler(weights, num_sampleslen(train_set), replacementTrue) train_loader DataLoader(train_set, batch_size32, samplersampler, num_workers4)这里的weights数组长度等于训练集总样本数每个样本的权重是它所属类别的样本数的倒数。样本量越少的类单个样本被抽中的概率越大。同时要顺手做数据增强翻倍对样本少的类用更激进的增强方式生成变体相当于变相扩充数据量。用加权采样之后宏平均 F1 会有明显提升但要注意训练 epoch 数也要相应增加否则少数类还没学透就结束了。4.3 “已标注”数据里的噪声比想象中严重现象从数据集里随机抽了 50 张图人工复核发现标签错误或“名不副实”的情况有 6 张比如易拉罐被标注成塑料瓶。原因真实废弃物图里经常有多个物体重叠标注时只看到最显眼的一个另一个被漏掉或者标错。解决先用训练好的模型跑一遍全部数据生成置信度分数把置信度低于 0.5 的样本列出来交给人工复核。这一步建议用 CVAT 或 labelimg 这类标注工具打开配合便捷操作逐张确认比直接改文件名要高效得多。这类数据清洗工作量不大却直接影响模型上限。我有一次做完噪声过滤后单纯依靠修正数据没改任何模型结构验证集 F1 涨了约 4 个百分点。真实废弃物数据集的标注质量参差不齐“已标注”只能当作起点不能当作免检证明。4.4 玻璃瓶和透明塑料瓶模型根本“看不见”材质现象玻璃瓶被大量预测为透明塑料瓶且这两类的混淆程度在训练过程中始终无法改善。原因这两类物体在颜色、透明度、形状上高度相似常规 RGB 图像里单靠像素信息很难分辨材质。解决先从数据侧拉差距把瓶盖、标签这些局部区域作为辅助信息透明塑料瓶通常带贴纸压印花纹玻璃瓶多为光滑表面增强时对这两类不做强烈模糊处理。如果业务场景固定常见做法是补充近红外或多光谱数据来区分玻璃和塑料但如果只有 4,800 张普通可见光图片建议直接合并成“透明瓶”一个类在工程上更实惠。4.5 数据量只有 4,800 张深模型容易“死记硬背”现象训练集准确率一路冲到 99%验证集准确率却停滞在 88% 附近且两者差距随训练轮数持续拉大。原因模型容量太大训练数据不足时直接背诵了训练集。解决三个手段同时上第一是提前停止训练只保留验证集最优的 checkpoint第二是加大weight_decay到 1e-3第三是检查增强策略确认验证集上的精度没有因为增强过猛而失真。这类问题的典型特征是训练集和验证集的差距超过 8 个百分点看到就说明过拟合已经发生需要立刻调整而不是继续延长训练。5. 让模型在真实场景真正站稳Grad-CAM 可视化与部署前自检5.1 用 Grad-CAM 检查模型到底看到了什么指标好看只说明统计上不错部署前我习惯用 Grad-CAM 可视化抽查几十张图看模型分类时到底盯着哪里。如果一张易拉罐图片的高响应区域跑到旁边的背景纸箱上说明模型大概率在偷懒靠背景线索做判断。import torch from torchvision import models, transforms from PIL import Image model.eval() img Image.open(sample_can.jpg).convert(RGB) t val_tf(img).unsqueeze(0).to(device) # 获取最后一层卷积特征和预测输出 features [] def hook_fn(module, input, output): features.append(output) handle model.layer4[-1].register_forward_hook(hook_fn) out model(t) handle.remove() _, pred torch.max(out, 1) feature_map features[0][0] grad torch.autograd.grad(out[0, pred], feature_map)[0] weights grad.mean(dim(1, 2), keepdimTrue) cam torch.relu((weights * feature_map).sum(dim0)).cpu().data.numpy()这段代码把最后一层卷积的梯度均值作为通道权重加权求和得到响应热力图。热力图高亮位置应该集中在废弃物主体上而不是背景或桌面。我跑这个过程时通常会发现有一部分图的响应点在瓶盖、标签这类文本区域这其实是好信号说明模型在利用有判别力的细节特征。如果响应点散落到背景则需要回到数据侧继续补充“更脏”的样本或者加强遮挡类增强。5.2 用模型筛选得到更多困难样本形成迭代闭环4,800 张只是起点。实际业务中的数据每天都在新增常见做法是用当前最优模型跑一遍新采集图片按置信度倒序排列只挑置信度最低的 20% 交给标注工具处理。标注完成后增量微调模型下一轮再加入新样本。这个闭环跑上个两三轮模型的真实场景表现会比单纯堆数据快得多也节省大量标注成本。我在部署前还会做一次“真实冒烟测试”拿一部旧手机或普通摄像头在实际投放点位拍摄 10 分钟视频每隔 5 帧抽一张图当作独立的最终测试集。这套测试集绝不参与训练只用来裁决模型能不能上线。最终测试集通过之后再考虑用 TensorRT、ONNX 或量化手段压缩模型、调整推理速度这时候选调batch_size、num_workers才有意义不然纯属本末倒置。我现在的习惯是任何数据集项目都先跑通一版完整 pipeline再回头精细化调参。更新的数据、更复杂的模型结构都要在同一个评估基准上对比避免指标虚高。这套方法在真实废弃物图像分类这一类小规模数据集上跟过不少项目都管用希望帮到你。本文还有配套的精品资源点击获取