十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

垃圾分类图像分类数据集实战:从数据清洗到迁移学习模型验证

垃圾分类图像分类数据集实战:从数据清洗到迁移学习模型验证 简介这份深度学习图像分类数据集面向从事计算机视觉入门与垃圾分类识别实践的开发者、学生及算法爱好者围绕塑料瓶、玻璃瓶、金属瓶等可回收物类别构建可用于训练与评估瓶类垃圾自动分拣模型。资源按目录组织同类样本归入同一文件夹并附json类别文件便于直接读取标签。包内共约2000个文件以1998张jpg图像为主体另含1个py脚本与1个json类别文件压缩包约39.65MB体量轻便适合快速加载与本地实验。数据已预先划分为训练集约2200张、验证集约200张、测试集约100张可直接用于模型训练、调参与性能对比省去自行切分与整理的时间。目前已有268人学习下载适合希望快速搭建垃圾分类分类基线、验证网络结构或完成课程设计的读者参考使用。1. 垃圾分类图像分类数据集从「能跑通」到「能落地」差在哪垃圾分类、瓶子垃圾图像分类这类题目很多人第一反应是「不就是个二分类/多分类吗ResNet 拉起来跑一遍就完事」。真上手才发现翻车点几乎全在数据上同一类瓶子在阳台光、厨房灯、闪光灯下颜色完全不一样透明塑料瓶和玻璃瓶在低对比度背景里几乎融为一体标注时「可回收」和「其他垃圾」的边界靠人拍脑袋。模型结构再新喂进去的是脏数据出来的就是玄学准确率。这篇笔记锁定的就是「垃圾分类、瓶子垃圾图像分类」这个深度学习数据集方向它讲的是怎么把一批真实场景下的垃圾/瓶子图片整理成能训练、能评估、能复现的图像分类数据集并跑通一条从数据清洗到模型验证的完整链路。适合两类人一是手里已经有一批手机拍的垃圾图片、想做成可用数据集的从业者二是想拿垃圾分类当图像分类入门实战、但不想停在玩具数据集上的新手。下面按「数据集怎么建 → 怎么训 → 坑在哪 → 怎么验证」推下去。2. 垃圾分类图像分类数据集怎么建采集、清洗与标签体系2.1 先定标签体系再谈采集垃圾分类图像分类最常见的返工不是模型调不出来而是标签体系中途改。今天按「可回收/厨余/有害/其他」四分明天发现瓶子想单独拎出来做细分类整个目录结构、标注文件、训练脚本全要重来。我的习惯是先把标签体系写成一张表锁定层级再动手。层级标签示例用途注意点粗分类可回收、厨余、有害、其他四分类基线类别互斥别留「其他」当垃圾桶细分类PET瓶、玻璃瓶、易拉罐、纸盒瓶子专项只对可回收子集展开属性透明/不透明、干净/脏污难例分析不参与主训练用于切片评估标签体系定完后目录就按类别名/图片组织这是后续所有框架都认的最小结构。这里有个血泪经验别用中文目录名。很多训练脚本、缓存、可视化工具对中文路径处理不一致轻则报编码错重则静默丢样本你还在那纳闷为什么类别数对不上。采集阶段要刻意覆盖三类变量光照自然光、室内灯、闪光灯、背景纯色、杂乱桌面、地面、拍摄距离近景特写、中景带环境。垃圾分类场景里背景杂乱是最大的干扰源模型很容易学到「桌布颜色」而不是「瓶子材质」。如果条件允许同一物体换 3 个背景各拍一张比同一背景拍 30 张有用得多。2.2 用脚本做数据清洗与去重采集回来的原始图第一件事不是标注是清洗。手机连拍会产生大量近似帧直接进训练集会造成数据泄漏——验证集里出现和训练集几乎一样的图准确率虚高上线就崩。下面这段脚本做两件事剔除损坏文件、用感知哈希找近似重复。import os from PIL import Image import imagehash def clean_and_dedup(root_dir, hash_threshold5): seen {} # hash - 保留的文件路径 removed [] for cls in os.listdir(root_dir): cls_dir os.path.join(root_dir, cls) if not os.path.isdir(cls_dir): continue for fname in os.listdir(cls_dir): fpath os.path.join(cls_dir, fname) try: img Image.open(fpath).convert(RGB) except Exception: os.remove(fpath) # 打不开的直接删 removed.append(fpath) continue h imagehash.phash(img) # 感知哈希抗轻微缩放/压缩 dup False for kept_hash, kept_path in seen.items(): if h - kept_hash hash_threshold: dup True os.remove(fpath) # 近似重复删掉后来的 removed.append(fpath) break if not dup: seen[h] fpath return removed if __name__ __main__: gone clean_and_dedup(./raw_dataset) print(f清理 {len(gone)} 张)逻辑说明phash把图片压成一个 64 位指纹两张图指纹的汉明距离越小越像。hash_threshold5是经验值越小越严格。阈值调到 3 以下会漏掉一些真实重复调到 8 以上会把不同角度的同一瓶子误删建议先在小批量上试。注意这段脚本是「保留先出现的、删后出现的」所以跑之前最好把质量高的图排在前面或者改成按文件大小/清晰度择优保留。清洗完还要做一次类别均衡检查。垃圾分类数据集天然不均衡其他垃圾的图片往往远多于有害垃圾。别急着上重采样先统计每类数量差距在 3 倍以内的靠数据增强就能压住超过 5 倍的再考虑对少数类做定向采集或加权采样。2.3 划分训练/验证/测试集的两个硬约束划分不是随机切一刀就完事。垃圾分类图像分类有两个硬约束同一物体的多张图不能跨集同一背景的图尽量不跨集。否则模型学到的是物体身份或背景不是类别特征。实操上如果采集时记录了「物体ID」或「拍摄批次」就按 ID 分组划分没有记录的话用图片的 EXIF 拍摄时间做近似分组同一分钟拍的归到同一集。划分比例常用 7:1.5:1.5小数据集可以 8:1:1。测试集一旦划出就冻结调参阶段只看验证集别手贱去翻测试集结果那是你最后唯一的后悔药。3. 用迁移学习跑通瓶子垃圾图像分类基线3.1 为什么垃圾分类场景优先选迁移学习垃圾分类、瓶子垃圾图像分类的数据集规模个人和小团队通常在一千到一万张量级。这个量级从零训练 CNN基本等于让模型背题训练集准确率能冲到 99%验证集原地踏步。迁移学习把在 ImageNet 上学到的边缘、纹理、材质特征直接搬过来你只需要微调最后的分类头几百张图就能出可用结果。选型上最新的图像分类模型层出不穷但对这个任务我一般从两个方向起步要精度、算力够用 ConvNeXt 或 EfficientNetV2 这类现代骨干要速度、要部署到边缘设备用 MobileNetV3 或轻量 ResNet。别一上来就追最花哨的结构垃圾分类的瓶颈在数据质量不在骨干网络那零点几个点的差距。3.2 最小可复现训练脚本下面用 PyTorch 写一个能直接跑的分类基线骨干换成任意 torchvision 模型都能用。关键是数据增强要针对垃圾场景设计颜色抖动模拟不同光照随机裁剪模拟不同拍摄距离水平翻转安全瓶子左右翻转不改变类别。import torch import torch.nn as nn from torch.utils.data import DataLoader from torchvision import datasets, transforms, models # 训练集增强针对光照和距离变化 train_tf transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomResizedCrop(224, scale(0.7, 1.0)), # 模拟远近 transforms.ColorJitter(0.3, 0.3, 0.3, 0.1), # 模拟光照色温 transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) val_tf transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) train_ds datasets.ImageFolder(./dataset/train, train_tf) val_ds datasets.ImageFolder(./dataset/val, val_tf) train_loader DataLoader(train_ds, batch_size32, shuffleTrue, num_workers4) val_loader DataLoader(val_ds, batch_size32, shuffleFalse, num_workers4) # 迁移学习换掉分类头 model models.efficientnet_v2_s(weightsDEFAULT) num_classes len(train_ds.classes) model.classifier[1] nn.Linear(model.classifier[1].in_features, num_classes) model model.cuda() criterion nn.CrossEntropyLoss(label_smoothing0.1) # 缓解过拟合 optimizer torch.optim.AdamW(model.parameters(), lr3e-4, weight_decay1e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max20) for epoch in range(20): model.train() for x, y in train_loader: x, y x.cuda(), y.cuda() optimizer.zero_grad() loss criterion(model(x), y) loss.backward() optimizer.step() scheduler.step() # 验证 model.eval() correct total 0 with torch.no_grad(): for x, y in val_loader: x, y x.cuda(), y.cuda() pred model(x).argmax(1) correct (pred y).sum().item() total y.size(0) print(fepoch {epoch} val_acc {correct/total:.4f})逻辑说明RandomResizedCrop的scale(0.7,1.0)控制裁剪范围太小会把瓶子裁没太大起不到模拟距离的作用。ColorJitter四个参数分别是亮度、对比度、饱和度、色调垃圾分类里色调别调太大否则会把绿色瓶子染成蓝色制造错误标签。label_smoothing0.1是防过拟合的常用手段标签越脏越有用。参数说明学习率3e-4是微调预训练模型的稳妥起点从零训练才用 1e-3 量级。weight_decay1e-4配合 AdamW。T_max20要和总 epoch 数一致余弦退火才能完整走完一个周期。num_workers在 Windows 上设 0 更稳Linux 上设 4 到 8。3.3 冻结策略与微调层数的取舍迁移学习不是无脑全量微调。数据量小于两千张时先冻结骨干只训分类头 5 个 epoch再解冻最后两个 stage 微调效果通常比一上来全解冻好。原因是随机初始化的分类头一开始梯度很大会把预训练好的骨干特征带偏。判断该解冻多少层看验证集准确率曲线如果冻结阶段验证准确率就卡住不动说明特征不匹配需要解冻更多层如果解冻后训练准确率飙升但验证掉说明过拟合退回去多冻几层并加大增强。这套「先冻后放」的节奏比任何自动调参都靠谱。4. 垃圾分类图像分类的避坑与排查清单4.1 验证准确率虚高上线就崩现象验证集准确率 95% 以上实际拍新图测试惨不忍睹。原因训练集和验证集存在近似重复图或者同一物体跨集模型在「背题」。解决回到 2.2 的去重脚本把哈希阈值调严到 3并检查划分是否按物体ID分组。另外确认验证集的增强是否误用了训练增强验证集只能做 Resize 和 Normalize。4.2 透明瓶子被大量误判现象PET 透明瓶和玻璃瓶互相误判混淆矩阵里这两类互相污染。原因透明物体在杂乱背景下边缘特征弱模型抓不到材质差异。解决采集时给透明瓶补纯色背景样本训练时加一点边缘增强如随机灰度化评估时单独把透明子集切出来看指标别被整体准确率掩盖。4.3 类别不均衡导致少数类全灭现象有害垃圾类召回率接近 0模型把所有样本都预测成多数类。原因交叉熵在极端不均衡下偏向多数类。解决先用WeightedRandomSampler给少数类加权权重设为类别频率的倒数再配合label_smoothing。如果少数类样本少于 50 张优先补采别指望算法变魔术。4.4 训练损失正常但准确率不动现象loss 缓慢下降准确率卡在随机水平。原因多半是标签和图片没对上ImageFolder按目录名排序生成类别索引如果你中途改过目录名索引就错位了。解决打印train_ds.classes和train_ds.class_to_idx抽几张图连同标签可视化确认。这个黑匣子不打开调参调到天亮也没用。4.5 显存溢出与批次大小的取舍现象换了大骨干就 OOM。原因EfficientNetV2 这类模型输入分辨率高、激活值大。解决优先降 batch size 而不是降分辨率垃圾分类的材质细节对分辨率敏感配合梯度累积模拟大 batch。batch_size16加累积 2 步等效 32显存省一半。5. 进阶用混淆矩阵和切片评估验证数据集质量模型训完别只看一个总准确率就收工。垃圾分类图像分类的真正价值在于用评估结果反推数据集哪里有问题。混淆矩阵是最直接的体检报告对角线之外的高值直接告诉你哪两类在数据层面就分不清。import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, classification_report all_preds, all_labels [], [] model.eval() with torch.no_grad(): for x, y in val_loader: x x.cuda() pred model(x).argmax(1).cpu().numpy() all_preds.extend(pred) all_labels.extend(y.numpy()) cm confusion_matrix(all_labels, all_preds) print(classification_report(all_labels, all_preds, target_namesval_ds.classes, digits3)) # 归一化后画图看每类的误判去向 cm_norm cm / cm.sum(axis1, keepdimsTrue) plt.imshow(cm_norm, cmapBlues) plt.xticks(range(len(val_ds.classes)), val_ds.classes, rotation45) plt.yticks(range(len(val_ds.classes)), val_ds.classes) plt.colorbar() plt.tight_layout() plt.savefig(confusion_matrix.png, dpi150)逻辑说明classification_report给出每类的精确率、召回率、F1比总准确率信息量大得多。归一化混淆矩阵按行归一每一行是「真实为某类的样本被预测成各类的比例」能直接看出误判流向。比如玻璃瓶那一行如果大量落到 PET 瓶列说明这两类在数据上就缺乏区分度该去补采而不是调模型。切片评估是更进一步的做法把验证集按「光照条件」「背景类型」「是否透明」打上属性标签分组算准确率。整体 90% 但「暗光杂乱背景」切片只有 60%那这个数据集在真实场景的短板就暴露了。这一步做完你才知道下一批该采什么图而不是盲目堆量。我自己的习惯是每训完一版模型先看混淆矩阵再看切片指标最后才决定是补数据还是改模型。十次里有七次问题出在数据而不是网络。垃圾分类这个方向尤其如此瓶子垃圾图像分类的难点从来不是模型不够新而是你的数据集有没有覆盖真实世界的脏乱差。把评估当数据集的质检工具用比把它当模型排行榜用回报高得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表