news 2026/9/28 2:15:42

真实废弃物九分类数据集实战:从4800张图到可训练管线

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
真实废弃物九分类数据集实战:从4800张图到可训练管线

简介:本资源为面向计算机视觉初学者与图像分类实践者的真实废弃物图像分类数据集,覆盖纸板、食品有机物、玻璃、金属、杂项垃圾、纸张、塑料、纺织品垃圾和植被共9个类别,适合用于分类网络训练、迁移学习验证及垃圾分类相关课程设计。数据已完成预处理,可直接作为分类网络输入,并已划分训练集与测试集,各类别图片分目录存放,便于快速构建实验流程。压缩包共约2000个文件,以1998张jpg图像为主,另含1个json标注文件与1个Python可视化脚本,整体约155.99MB,运行show脚本即可直观查看样本分布与图像内容。目前已有65人学习下载,配套内容还涉及图像分类与分割网络改进思路,可帮助读者在真实场景数据上完成模型训练、效果对比与调参排错,积累从数据读取到结果可视化的完整实践经验。

1. 真实废弃物九分类数据集:从 4800 张图到能跑通的训练管线

手里拿到一份标注好的废弃物图像分类数据集,第一反应往往不是兴奋,而是先确认三件事:类别定义清不清楚、划分有没有泄漏、预处理到底做到哪一步。这份数据集给的是约 4800 张生活中真实拍摄的废弃物图片,分 9 类——纸板、食品有机物、玻璃、金属、杂项垃圾、纸张、塑料、纺织品垃圾和植被,训练集与测试集已经按同一类别分目录存放,还附带一个可视化脚本。它解决的是「我不想从零爬图、清洗、标注,只想把精力放在模型结构和调参上」这个诉求,适合做图像分类课程设计、毕业项目、分类网络改进对比,或者拿它当 backbone 预训练的小规模验证集。文件名像 Vegetation_110.jpg、Vegetation_109.jpg 这种,说明每张图带类别前缀,肉眼就能对上标签,省掉一轮核对成本。

2. 数据集结构与标签体系:先看清 9 类怎么分、json 里存了什么

2.1 目录组织与类别映射

这份资源的核心不是图片本身,而是「图片 + 划分 + 标签」三件套是否自洽。常见做法是根目录下放 train 和 test 两个文件夹,每个文件夹里再按类别名建子目录,图片直接躺在对应类别目录下。这种结构对 PyTorch 的 ImageFolder 和 TensorFlow 的 image_dataset_from_directory 都是开箱即用,不需要自己写解析逻辑。

类别一共 9 个,中文和英文的对应关系建议在代码里显式写死,别依赖目录名自动推断,否则换台机器、换个解压工具,中文目录名编码一变就翻车。我一般会建一个 class_names 列表,顺序固定,后面混淆矩阵、分类报告都按这个顺序来。

import os import json # 固定类别顺序,避免依赖目录遍历顺序 class_names = [ "cardboard", # 纸板 "food_organic", # 食品有机物 "glass", # 玻璃 "metal", # 金属 "misc_trash", # 杂项垃圾 "paper", # 纸张 "plastic", # 塑料 "textile", # 纺织品垃圾 "vegetation", # 植被 ] data_root = "./waste_dataset" for split in ["train", "test"]: split_dir = os.path.join(data_root, split) print(f"--- {split} ---") for cls in class_names: cls_dir = os.path.join(split_dir, cls) if os.path.isdir(cls_dir): n = len([f for f in os.listdir(cls_dir) if f.lower().endswith((".jpg", ".jpeg", ".png"))]) print(f"{cls:15s}: {n}") else: print(f"{cls:15s}: 目录缺失")

这段代码做的是逐类计数,逻辑很直白:遍历 train/test 下每个类别目录,统计图片扩展名匹配的文件数。参数上唯一要注意的是扩展名集合,有些数据集混了 .JPG 大写后缀,用 lower() 统一处理。跑完如果某一类数量明显偏少(比如个位数),先别急着训练,大概率是解压不完整或者类别目录名和 class_names 对不上。

json 文件里通常存的是类别索引到类别名的映射,以及可能的划分清单。建议先把它读出来打印一遍,确认索引顺序和你代码里的 class_names 一致。索引错位是分类任务里最隐蔽的坑之一,训练 loss 正常下降,但验证准确率永远上不去,因为标签全错位了。

2.2 可视化脚本怎么用、看什么

资源里带了 show 脚本,这类脚本一般做两件事:随机抽样展示每个类别的图片,或者把整个 batch 拼成网格。它的价值不在于好看,而在于让你在训练前用眼睛过一遍数据质量——有没有标错的、有没有几乎全黑的、有没有同一张图重复出现在 train 和 test 里。

import os import random import matplotlib.pyplot as plt from PIL import Image def show_samples(data_root, class_names, split="train", n_per_class=4): fig, axes = plt.subplots(len(class_names), n_per_class, figsize=(n_per_class * 2.5, len(class_names) * 2.5)) for i, cls in enumerate(class_names): cls_dir = os.path.join(data_root, split, cls) if not os.path.isdir(cls_dir): continue imgs = [f for f in os.listdir(cls_dir) if f.lower().endswith((".jpg", ".jpeg", ".png"))] picked = random.sample(imgs, min(n_per_class, len(imgs))) for j in range(n_per_class): ax = axes[i][j] ax.axis("off") if j < len(picked): img = Image.open(os.path.join(cls_dir, picked[j])) ax.imshow(img) ax.set_title(cls, fontsize=8) plt.tight_layout() plt.show() show_samples("./waste_dataset", class_names, split="train", n_per_class=4)

逻辑是按类别逐行铺图,每类随机抽 n_per_class 张。random.sample 保证不重复抽样,min() 防止某类图片不足时报错。看的时候重点盯三样:类别边界模糊的(纸张和纸板、塑料和杂项垃圾最容易混)、背景干扰大的、以及明显不属于该类却被标进去的。这一步花十分钟,后面能省几小时排查。

提示:如果 show 脚本依赖的库没装全,先 pip install matplotlib pillow,别直接改脚本逻辑。

3. 把数据喂进分类网络:预处理、增强与 DataLoader 参数怎么定

3.1 预处理对齐:别让「已预处理」变成想当然

摘要里说数据经过预处理、可直接作为分类网络输入,这句话要拆开理解。常见做法是图片已经统一到某个尺寸(比如 224×224 或 256×256),但归一化用的均值和方差未必和你选的预训练权重匹配。如果你用 ImageNet 预训练 backbone,就该用 ImageNet 的 mean=[0.485,0.456,0.406]、std=[0.229,0.224,0.225];如果数据本身已经做过零均值化,再套一层反而把分布搞乱。

我的习惯是先抽一张图,打印它的像素范围,判断到底有没有归一化过。

import numpy as np from PIL import Image img = Image.open("./waste_dataset/train/plastic/Plastic_12.jpg").convert("RGB") arr = np.array(img) print("shape:", arr.shape) print("min/max:", arr.min(), arr.max()) print("mean/std per channel:", arr.mean(axis=(0, 1)), arr.std(axis=(0, 1)))

如果 min/max 在 0~255 之间,说明还是原始像素,需要自己做归一化;如果已经在 0~1 或接近零均值,就按实际情况调整 transform。参数上,shape 还能告诉你图片是否已经 resize 过——如果全是统一尺寸,说明预处理做了缩放,你只需要补归一化和增强。

3.2 训练/验证 transform 与增强策略

废弃物图像的特点是类内差异大:同一个塑料瓶,捏扁的和没捏扁的、干净的和脏的,视觉差异可能比塑料和玻璃之间还大。所以增强不能太保守,但也不能上那些会改变类别语义的操作(比如大角度旋转对方向敏感的类别就不合适)。

from torchvision import transforms train_tf = transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomResizedCrop(224, scale=(0.7, 1.0)), transforms.RandomHorizontalFlip(p=0.5), transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.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, 256)), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ])

逐项说参数:RandomResizedCrop 的 scale=(0.7,1.0) 表示随机裁原图 70%~100% 的区域再缩放,模拟拍摄距离变化;水平翻转对废弃物类别安全,因为左右镜像不改变类别;ColorJitter 三个系数控制在 0.2,是为了模拟不同光照和相机白平衡,再大就可能把浅色塑料和纸张的色差抹掉。验证集只做 resize + centercrop,保证评估可复现。

3.3 DataLoader 与类别不均衡处理

约 4800 张分 9 类,平均每类 500 多张,但真实数据集很少完全均衡。先统计每类数量,再决定要不要加权采样。

from torch.utils.data import DataLoader from torchvision.datasets import ImageFolder train_ds = ImageFolder("./waste_dataset/train", transform=train_tf) val_ds = ImageFolder("./waste_dataset/test", transform=val_tf) # 统计训练集类别分布 from collections import Counter targets = [s[1] for s in train_ds.samples] cnt = Counter(targets) print("类别分布:", {train_ds.classes[k]: v for k, v in sorted(cnt.items())}) train_loader = DataLoader(train_ds, batch_size=32, shuffle=True, num_workers=4, pin_memory=True) val_loader = DataLoader(val_ds, batch_size=32, shuffle=False, num_workers=4, pin_memory=True)

ImageFolder 会自动按目录名排序生成 classes,所以务必确认它的顺序和你的 class_names 一致,不一致就手动传 class_to_idx 或训练后重映射。batch_size=32 在 224 分辨率下对 8G 显存比较稳,显存紧就降到 16 并配合梯度累积。num_workers 在 Windows 上如果报错就设 0,这是老问题了。如果某类样本数不到最多的 1/3,建议用 WeightedRandomSampler 做加权采样,比直接复制图片干净。

4. 训练与评估:从 baseline 到混淆矩阵,把 9 类问题定位清楚

4.1 一个能跑通的 baseline 训练循环

别一上来就上 Transformer 或改结构,先用 ResNet18 或 EfficientNet-B0 跑一个 baseline,确认数据管线没问题。baseline 准确率就是你的下限参照。

import torch import torch.nn as nn from torchvision import models device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1) model.fc = nn.Linear(model.fc.in_features, 9) # 9 类 model = model.to(device) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=20) for epoch in range(20): model.train() for imgs, labels in train_loader: imgs, labels = imgs.to(device), labels.to(device) optimizer.zero_grad() loss = criterion(model(imgs), labels) loss.backward() optimizer.step() scheduler.step() print(f"epoch {epoch+1} done")

关键参数:lr=3e-4 配 AdamW 是微调预训练模型的常用起点,weight_decay=1e-4 抑制过拟合;CosineAnnealingLR 让学习率平滑衰减,T_max 设成总 epoch 数。如果 loss 前几个 epoch 不降,先查标签错位和归一化,而不是急着调 lr。

4.2 混淆矩阵与分类报告:定位到底哪两类在混

准确率是个笼统指标,9 类任务里真正有价值的是混淆矩阵。纸张和纸板、塑料和杂项垃圾这两组是最容易互相误判的。

from sklearn.metrics import confusion_matrix, classification_report import numpy as np model.eval() all_preds, all_labels = [], [] with torch.no_grad(): for imgs, labels in val_loader: imgs = imgs.to(device) preds = model(imgs).argmax(dim=1).cpu().numpy() all_preds.extend(preds) all_labels.extend(labels.numpy()) print(classification_report(all_labels, all_preds, target_names=train_ds.classes, digits=4)) cm = confusion_matrix(all_labels, all_preds) print(cm)

classification_report 给出每类的 precision/recall/f1,混淆矩阵则直接暴露「A 被预测成 B」的次数。如果纸张和纸板互相误判严重,说明模型没学到材质和纹理差异,可以考虑加更强的颜色增强或换更高分辨率输入;如果杂项垃圾 recall 特别低,多半是这一类本身定义就杂,样本之间缺乏共性,属于数据集层面的问题,调模型收益有限。

注意:评估时一定要用 test 集,别拿 train 集算指标自欺欺人。如果 test 准确率远低于 train,先怀疑划分泄漏——同一张图或高度相似的连拍图同时出现在两边。

5. 避坑与排查:这份数据集最容易翻车的五个地方

5.1 现象:训练 loss 正常降,验证准确率卡在 11% 左右

原因:9 类随机猜的准确率就是约 11%,说明模型没学到任何东西。最常见的是标签索引错位——ImageFolder 按目录名字母序生成索引,和你代码里的 class_names 顺序不一致,导致标签和预测对不上。

解决:训练前打印 train_ds.class_to_idx,和你的 class_names 逐项核对。不一致就显式构造 ImageFolder 的 class_to_idx 参数,或者在算指标前做一次索引重映射。

5.2 现象:某一类 recall 接近 0,其他类都正常

原因:这一类样本数太少,或者图片格式损坏导致加载时被跳过。也有可能是该类目录名有隐藏字符(比如末尾空格),ImageFolder 识别成了一个独立类别。

解决:逐类计数,确认没有异常小的类;用 PIL 批量打开一遍捕获异常文件;检查目录名是否有多余空格或不可见字符。

5.3 现象:Windows 上 num_workers>0 直接报错或卡死

原因:Windows 下多进程 DataLoader 需要 ifname== "main" 保护,且对某些环境兼容性差。

解决:把 num_workers 设为 0 先跑通,确认管线无误后再尝试 2 或 4。训练脚本入口加 main 保护。

5.4 现象:验证集准确率虚高,换一批图就崩

原因:train 和 test 里存在重复图或高度相似图,模型记住了而不是学会了。

解决:对 train 和 test 做一次感知哈希去重,或者至少用文件名和图片尺寸粗筛。发现重复就重新划分,别心疼。

5.5 现象:显存够但训练速度异常慢

原因:图片没被缓存,每个 epoch 都在反复解码大图;或者 num_workers 设太小,GPU 一直在等数据。

解决:确认图片是否已 resize 到合理尺寸(224~256 足够),必要时预先把所有图转成统一尺寸的 lmdb 或 npy 缓存;num_workers 调到 CPU 核数的 1/2 左右,pin_memory=True。

6. 进阶技巧:用分层采样和 TTA 把 9 类准确率再抬一截

baseline 跑通之后,想再往上抬点准确率,不一定非要换大模型。两个成本低、见效稳的技巧值得试:分层划分验证集和测试时增强(TTA)。

先说分层采样。如果 test 集本身类别不均衡,单次评估的波动会很大,今天 82% 明天 79%,你根本分不清是模型变了还是评估噪声。用 StratifiedKFold 从 train 里切出一份分层验证集,保证每类比例一致,评估才稳定。

from sklearn.model_selection import StratifiedKFold import numpy as np targets = np.array([s[1] for s in train_ds.samples]) skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) for fold, (tr_idx, va_idx) in enumerate(skf.split(np.zeros(len(targets)), targets)): print(f"fold {fold}: train {len(tr_idx)}, val {len(va_idx)}") # 用 Subset 构造 train/val 子集,再包 DataLoader

逻辑是用标签做分层,每折里各类比例和整体一致。random_state 固定保证可复现。实际训练时取 5 折平均指标,比单次划分可信得多。

再说 TTA。推理时对同一张图做几次轻微变换(原图、水平翻转、小尺寸缩放),把 softmax 概率平均后再取 argmax。对废弃物这种类内差异大的数据,TTA 通常能带来 1~3 个点的提升,代价只是推理时间翻几倍。

def predict_tta(model, img_pil, tf_list, device): model.eval() probs = [] with torch.no_grad(): for tf in tf_list: x = tf(img_pil).unsqueeze(0).to(device) p = torch.softmax(model(x), dim=1).cpu().numpy()[0] probs.append(p) return np.mean(probs, axis=0).argmax() # tf_list 里放 val_tf、水平翻转版、轻微缩放版

参数上,TTA 的变换要和训练增强同分布,别用训练时没见过的强变换,否则概率平均反而引入噪声。我一般只用原图 + 水平翻转两种,性价比最高。

最后说个习惯。这份数据集类别边界天然模糊,纸张和纸板、塑料和杂项垃圾的混淆很难完全消除。与其死磕准确率,不如把混淆矩阵里误判最多的那几对单独拎出来,看看是不是标注本身就有歧义。从那以后我每次拿到分类数据集,都强制先跑一遍逐类计数加混淆矩阵,再决定要不要动模型——数据层面的问题,模型再深也救不回来。希望这份拆解帮到你,把 4800 张图真正跑成能写进项目里的结果。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 2:15:30

【PyQt】PyQt5基础组件:表格视图

表格视图作为应用程序中处理和展示数据的核心组件,尤其在处理大规模数据时,发挥着不可或缺的作用。在PyQt框架中,QTableView 提供了一个高效、灵活的方式来显示表格数据。通过结合模型-视图框架,可以将数据从模型中提取并呈现出来,确保仅加载当前可见的部分,提升了处理大…

作者头像 李华
网站建设 2026/9/28 2:15:14

【PyQt】PyQt5基础组件:窗口

在图形用户界面(GUI)开发中,PyQt作为Python语言中的一个重要工具包,提供了丰富的功能和灵活的用户界面定制能力。基于Qt框架,PyQt简化了开发者创建跨平台应用程序的过程。在实际开发过程中,创建窗口是每个PyQt应用程序的核心组成部分,它是用户与程序进行交互的起点。 通…

作者头像 李华
网站建设 2026/9/28 2:14:42

yolov8-pose 特征点推理流程

目录 一、关键点预测 二、图像预处理 二、推理 三、后处理与可视化 3.1、后处理 3.2、特征点可视化 四、完整pytorch代码 yolov8-pose tensorrt一、关键点预测 注&#xff1a;本篇只是阐述推理流程&#xff0c;tensorrt实现后续跟进。 yolov8-pose的tensorrt部署代码稍…

作者头像 李华
网站建设 2026/9/28 2:14:07

真实废弃物图像分类:4800张标注数据实战与避坑指南

简介&#xff1a;这份生活中真实废弃物图像分类数据集面向计算机视觉初学者与图像分类、分割方向的算法实践者&#xff0c;用于解决垃圾分类场景下真实样本获取难、标注成本高的问题。数据已完成预处理&#xff0c;可直接作为分类网络输入&#xff0c;覆盖纸板、食品有机物、玻…

作者头像 李华
网站建设 2026/9/28 2:12:52

Java+JSP+MySQL学校教材管理系统:从征订到库存的完整实现与避坑指南

简介&#xff1a;这份资源是面向高校计算机专业学生与Java Web初学者的一套完整学校教材管理系统源码&#xff0c;基于Java、JSP与MySQL技术栈构建&#xff0c;运行于Tomcat环境&#xff0c;适合用作课程设计、毕业设计或Web开发练手项目。压缩包共81个文件&#xff0c;约3.91M…

作者头像 李华
网站建设 2026/9/28 2:12:44

Cadence Allegro 3D封装实战:从嘉立创下载STEP模型并导入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华