简介这份资源面向计算机相关专业的毕业设计学生与深度学习入门者提供一套基于Python与卷积神经网络CNN实现六类别垃圾分类的完整项目方案类别涵盖glass、cardboard、metal、paper、plastic与trash。内容围绕模型搭建、参数调优、学习曲线绘制与分析、不同学习率等超参数对比实验展开帮助读者理解CNN在图像分类任务中的完整流程。资源包共28个文件包含5个py脚本、1个ipynb笔记本、14张png图表、3个md说明文档以及h5模型权重、docx报告等压缩包约16.71MB代码、数据与文档结构清晰便于按模块查阅与复现。目前已有4456人学习下载。读者可据此获得可直接运行的训练与推理代码、已训练模型文件、网络结构图与结果可视化图表并参考README与实验记录完成模型调试、结果分析与论文写作适合作为毕业设计或课程项目的实践参考。1. 从一堆垃圾照片到能跑的 CNN这套毕设资源到底值不值得拆如果你手头正压着一个「基于 Python CNN 卷积神经网络实现 6 类别垃圾分类」的毕业设计大概率会遇到三种情况要么只有论文没有代码要么代码跑起来就报维度错误要么数据集里混着重复图和脏标注。这套资源解决的正是这个断层——它给出一套完整的 Python CNN 垃圾分类工程覆盖数据组织、模型搭建、训练、评估到单张图片推理的闭环类别固定为 6 类适合计算机、电子信息、自动化方向的本科毕设也适合刚入门深度学习、想找一个能跑通全流程项目练手的同学。我拆过不少毕设包很多是「论文漂亮、代码跑不动」这套的价值在于结构清晰、依赖常规用一台带普通显卡的笔记本就能复现。下面按「资源是什么 → 怎么用 → 坑在哪」的顺序把关键参数和踩坑点讲透。2. 数据管线与目录结构6 类别怎么组织、怎么切分才不翻车2.1 先看清数据长什么样再决定怎么读垃圾分类这类图像任务数据集质量直接决定模型上限。常见做法是按类别建文件夹每个文件夹放对应图片目录结构大致如下dataset/ ├── train/ │ ├── cardboard/ # 纸板 │ ├── glass/ # 玻璃 │ ├── metal/ # 金属 │ ├── paper/ # 纸类 │ ├── plastic/ # 塑料 │ └── trash/ # 其他垃圾 └── val/ ├── cardboard/ ├── glass/ ├── metal/ ├── paper/ ├── plastic/ └── trash/这种ImageFolder友好的结构是 PyTorch 里最省事的组织方式。6 个类别名要和代码里的class_names严格一致顺序错了评估结果会张冠李戴。我一般会先跑一段统计脚本确认每类样本量避免某类只有几十张导致严重不均衡。import os data_dir dataset/train class_names sorted(os.listdir(data_dir)) for cls in class_names: cls_path os.path.join(data_dir, cls) count len([f for f in os.listdir(cls_path) if f.lower().endswith((.jpg, .jpeg, .png))]) print(f{cls}: {count} 张)这段脚本做两件事一是拿到排序后的类别名二是统计每类有效图片数量。参数上注意endswith里把常见后缀都列上很多数据集混着.JPG大写后缀不处理会被静默漏掉。如果发现某类样本明显偏少训练时就要考虑加权采样或数据增强否则模型会偏向多数类。2.2 训练集与验证集的切分逻辑资源里通常已经切好train和val但如果你拿到的是原始未切分数据需要自己按比例划分。常见做法是 8:2 或 7:3且要保证同一张图不会同时出现在两边。下面是一个可复现的切分脚本import os import random import shutil src_dir dataset/raw dst_train dataset/train dst_val dataset/val split_ratio 0.8 random.seed(42) for cls in os.listdir(src_dir): cls_dir os.path.join(src_dir, cls) imgs [f for f in os.listdir(cls_dir) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(imgs) n_train int(len(imgs) * split_ratio) for i, img in enumerate(imgs): dst dst_train if i n_train else dst_val target_dir os.path.join(dst, cls) os.makedirs(target_dir, exist_okTrue) shutil.copy(os.path.join(cls_dir, img), os.path.join(target_dir, img))逻辑说明random.seed(42)保证每次切分结果一致方便复现split_ratio控制训练集占比样本少时可调到 0.7。参数上要留意shutil.copy是复制不是移动原始数据保留一份切错了还能重来。这一步的坑在于如果原始数据里已经有重复图切分后可能一张在训练集、一张在验证集验证准确率会虚高后面排查章节会细说。3. CNN 模型搭建与训练从卷积层参数到训练循环3.1 一个够用的 6 分类 CNN 结构毕设场景不需要上 ResNet 那么重一个 3 到 4 层卷积的轻量网络就能跑到不错的准确率而且训练快、好解释。下面是一个典型结构import torch import torch.nn as nn class GarbageCNN(nn.Module): def __init__(self, num_classes6): super().__init__() self.features nn.Sequential( nn.Conv2d(3, 32, kernel_size3, padding1), nn.BatchNorm2d(32), nn.ReLU(inplaceTrue), nn.MaxPool2d(2), # 224 - 112 nn.Conv2d(32, 64, kernel_size3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.MaxPool2d(2), # 112 - 56 nn.Conv2d(64, 128, kernel_size3, padding1), nn.BatchNorm2d(128), nn.ReLU(inplaceTrue), nn.MaxPool2d(2), # 56 - 28 ) self.classifier nn.Sequential( nn.AdaptiveAvgPool2d(1), # 任意输入尺寸 - 1x1 nn.Flatten(), nn.Linear(128, 64), nn.ReLU(inplaceTrue), nn.Dropout(0.5), nn.Linear(64, num_classes), ) def forward(self, x): x self.features(x) return self.classifier(x)参数说明kernel_size3, padding1保证卷积后空间尺寸不变尺寸缩小全靠MaxPool2dBatchNorm2d放在卷积和激活之间能明显稳住训练AdaptiveAvgPool2d(1)是这套结构的关键它让模型对输入尺寸不敏感推理时传 224 或 256 都不会崩。Dropout(0.5)在全连接前降过拟合样本少时尤其有用。常见误用是把padding设成 0结果每层都在缩几层之后特征图就没了。3.2 数据增强与 DataLoader 配置垃圾分类图片往往背景杂乱、角度不一增强能显著提升泛化。训练集用随机裁剪、翻转、颜色抖动验证集只做缩放和归一化from torchvision import transforms, datasets from torch.utils.data import DataLoader train_tf transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomResizedCrop(224, scale(0.7, 1.0)), transforms.RandomHorizontalFlip(), transforms.ColorJitter(0.2, 0.2, 0.2), 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, transformtrain_tf) val_ds datasets.ImageFolder(dataset/val, transformval_tf) train_loader DataLoader(train_ds, batch_size32, shuffleTrue, num_workers2) val_loader DataLoader(val_ds, batch_size32, shuffleFalse, num_workers2)逻辑说明Normalize里的均值方差是 ImageNet 的统计值用预训练权重时必须一致从头训练也建议沿用。batch_size32是显存和稳定性的折中显存不够就降到 16。num_workers在 Windows 上设太大会报错一般 2 到 4 即可。注意ImageFolder会按文件夹名排序生成类别索引训练和推理必须用同一套映射否则预测结果会错位。3.3 训练循环与关键超参数训练循环本身不复杂关键是损失函数、优化器和学习率的搭配device torch.device(cuda if torch.cuda.is_available() else cpu) model GarbageCNN(num_classes6).to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr1e-3) scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size10, gamma0.5) for epoch in range(30): model.train() for imgs, labels in train_loader: imgs, labels imgs.to(device), labels.to(device) optimizer.zero_grad() outputs model(imgs) loss criterion(outputs, labels) loss.backward() optimizer.step() scheduler.step() # 每个 epoch 后在验证集上评估记录 acc 和 loss参数说明CrossEntropyLoss内部带 softmax模型输出不要再加 softmaxAdam的lr1e-3是常用起点收敛慢可降到 5e-4StepLR每 10 个 epoch 把学习率减半帮助后期收敛。训练轮数 30 是经验值样本多可以加到 50。这里最容易翻车的是忘了optimizer.zero_grad()梯度会累加loss 直接飞掉。4. 评估、推理与可视化怎么确认模型真的学到了东西4.1 混淆矩阵比单一准确率更有说服力毕设答辩时光报一个准确率容易被追问。用混淆矩阵能看出哪两类容易混比如纸类和纸板经常分不清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) outputs model(imgs) preds outputs.argmax(dim1).cpu().numpy() all_preds.extend(preds) all_labels.extend(labels.numpy()) print(confusion_matrix(all_labels, all_preds)) print(classification_report(all_labels, all_preds, target_namestrain_ds.classes))逻辑说明model.eval()关闭 dropout 和 BN 的训练行为torch.no_grad()省显存。classification_report会给出每类的 precision、recall、f1比总准确率更能说明问题。如果某类 recall 特别低基本就是样本太少或标注有问题。4.2 单张图片推理脚本答辩现场经常要演示「传一张图输出类别」这段脚本可以直接用from PIL import Image import torch.nn.functional as F def predict(image_path, model, class_names, device): model.eval() img Image.open(image_path).convert(RGB) tensor val_tf(img).unsqueeze(0).to(device) with torch.no_grad(): logits model(tensor) probs F.softmax(logits, dim1)[0] idx probs.argmax().item() return class_names[idx], probs[idx].item() label, score predict(test.jpg, model, train_ds.classes, device) print(f预测{label}置信度{score:.4f})参数说明convert(RGB)防止灰度图或带 alpha 通道的图报错unsqueeze(0)补上 batch 维度val_tf必须和验证集一致用训练集的增强变换会导致结果不稳定。置信度低于 0.6 时实际演示中最好说明「模型不确定」别硬报类别。5. 避坑与排查这几处翻车点我几乎每次都遇到5.1 现象训练 loss 不降反升准确率卡在 1/6原因学习率过大或者标签和输出维度对不上。6 分类如果num_classes写成别的数CrossEntropyLoss不会报错但结果全乱。解决先确认model.classifier[-1].out_features 6再把学习率降到 1e-4 试跑几个 batch观察 loss 是否稳定下降。5.2 现象验证准确率异常高接近 99%原因训练集和验证集存在重复图片或者验证集图片被增强污染。解决用图片哈希去重确认val_tf里没有RandomXXX类变换。我一般会写个 md5 去重脚本跑一遍再训练。5.3 现象Windows 上 DataLoader 报BrokenPipeError原因num_workers大于 0 时多进程在 Windows 下的兼容问题。解决把num_workers设为 0或者把训练代码放进if __name__ __main__:保护块里。5.4 现象推理时输入尺寸和训练不一致导致维度报错原因模型里用了固定尺寸的全连接层。解决采用AdaptiveAvgPool2d(1)结构或在推理前严格Resize到训练尺寸。这也是我在 3.1 里强调自适应池化的原因。5.5 现象某类识别率极低混淆矩阵集中在一列原因该类样本量过少或标注错误。解决统计每类数量对少样本类做过采样或增强抽查该类的图片确认没有放错文件夹。6. 把模型推到能答辩的水平两个提分技巧和验证习惯第一个技巧是用迁移学习替换从头训练。如果资源里是自建 CNN你可以把features换成预训练的 ResNet18 或 MobileNetV2只训练分类头再整体微调。常见做法是冻结主干先训 5 个 epoch再解冻用 1e-4 学习率微调准确率通常能涨 5 到 10 个百分点。参数上注意预训练权重的输入归一化必须和 ImageNet 一致也就是 3.2 里那组均值和方差。第二个技巧是加一个简单的错误样本分析环节。训练完后把验证集里预测错的图片单独复制到一个文件夹人工看一遍。十有八九能发现标注错误、模糊图或者类别边界模糊的样本。这一步不写代码也能做但对答辩时解释「模型为什么错」特别有用。验证方法上我习惯固定随机种子后跑三次训练看准确率波动范围。如果三次结果差超过 5 个百分点说明数据或超参数不稳定答辩时被问到复现性会很难受。表格里是我常用的检查项检查项合格标准不达标时的动作每类样本量每类不少于 200 张过采样或收集补充训练/验证重复图0 张重复md5 去重后重新切分验证准确率波动三次差异小于 5%固定种子、检查增强单张推理置信度正确样本普遍高于 0.7检查归一化和尺寸从那以后我每次交付这类毕设项目都会强制走一遍「去重 → 统计类别 → 固定种子训练 → 混淆矩阵 → 错误样本抽查」的流程少一步后面都可能被追问到哑口。希望帮到你。本文还有配套的精品资源点击获取
