首页/新闻资讯/正文详情

基于CNN的智能垃圾分类系统:从数据到部署的毕业设计实战

发布时间:2026/9/24 18:03:49 来源:云帆数科 栏目:资讯中心
基于CNN的智能垃圾分类系统:从数据到部署的毕业设计实战
简介这份资源是面向计算机、通信、人工智能、自动化等专业学生与从业者的深度学习实战项目以卷积神经网络为核心实现智能垃圾分类可作为毕业设计、课程大作业或期末课程设计的完整参考方案。项目代码经过调试测试答辩评审分达到98分基础较好的学习者还能在此基础上修改调整扩展出不同功能。压缩包共216个文件约17.29MB包含Python源码、TensorFlow检查点与预训练权重文件、Java与XML配置、PNG与JPG图像素材、Gradle与Maven构建脚本以及说明文档等覆盖模型训练、界面实现与工程配置多个环节目录结构清晰便于按模块检索学习。目前已有182人学习下载。对于希望掌握卷积神经网络垃圾分类完整流程的读者可从中获取模型搭建、权重加载、数据组织与项目部署的实践思路适合小白入门与进阶提升。1. 从一张垃圾桶照片说起这套 CNN 垃圾分类系统到底能跑出什么效果实验室楼下四个垃圾桶可回收、有害、厨余、其他每天中午都有人站在前面犹豫三秒然后随手一扔。我拿手机拍了 200 张这样的照片想验证一件事一个不依赖云端、能在本地跑起来的卷积神经网络到底能不能把「塑料瓶」和「一次性纸杯」分开。结论是能但前提是你得把数据、输入尺寸和最后一层改对否则准确率会卡在 60% 上下反复横跳这就是很多人做深度学习毕业设计时最常翻车的地方。这套「基于深度学习卷积神经网络的智能垃圾分类系统」本质上是三件事的组合一个图像分类模型常见做法是 ResNet18 或 MobileNetV3 做迁移学习、一套数据管道把拍照得到的原始图整理成 ImageFolder 能读的目录结构、一个推理入口命令行或一个轻量 Web 界面。它解决的不是「垃圾识别」这个宏大命题而是「给定一张 224×224 的 RGB 图输出它属于哪一类」这个可复现的工程问题。适合谁适合正在做计算机毕业设计、需要一份能跑通、能讲清楚、能写进论文的 Python 深度学习项目的同学也适合想用 CNN 练手但不想从零造轮子的入门者。下面我按「先跑通再优化」的顺序把每一步的参数和坑都摊开讲。2. 数据准备与目录结构把散落照片变成 ImageFolder 能吃的格式2.1 为什么不用现成数据集直接开跑公开的垃圾分类数据集比如 TrashNet、Kaggle 上的垃圾分类竞赛数据质量参差不齐最常见的问题是类别不均衡纸类几千张有害垃圾只有几十张。直接拿来训练模型会把所有输入都预测成样本最多的那一类准确率看着有 70%实际毫无用处。我一般会先做一次类别统计再决定是过采样、欠采样还是加类别权重。另一个坑是图片尺寸和通道不统一有的带 alpha 通道有的是灰度图直接喂给 CNN 会在第一个卷积层报维度错误。所以第一步不是写模型而是把数据整理成torchvision.datasets.ImageFolder要求的格式每个类别一个子文件夹文件夹名就是类别标签。这个约定能省掉你自己写 Dataset 类的大部分工作。2.2 目录结构与数据清洗脚本假设你拍的照片按来源散在raw/下先跑一段脚本做清洗和划分。下面这段代码做三件事过滤掉损坏图片、统一转成 RGB、按 8:1:1 划分训练/验证/测试集。import os import shutil import random from PIL import Image RAW_DIR raw # 原始照片按类别分子目录 OUT_DIR dataset # 输出根目录 SPLIT (0.8, 0.1, 0.1) # 训练/验证/测试比例 SEED 42 random.seed(SEED) def is_valid_image(path): try: with Image.open(path) as im: im.verify() # 校验文件完整性 with Image.open(path) as im: im.convert(RGB) # 统一转 RGB丢弃 alpha return True except Exception: return False for cls in os.listdir(RAW_DIR): cls_dir os.path.join(RAW_DIR, cls) if not os.path.isdir(cls_dir): continue files [f for f in os.listdir(cls_dir) if f.lower().endswith((.jpg, .jpeg, .png, .bmp))] files [f for f in files if is_valid_image(os.path.join(cls_dir, f))] random.shuffle(files) n len(files) n_train int(n * SPLIT[0]) n_val int(n * SPLIT[1]) splits { train: files[:n_train], val: files[n_train:n_train n_val], test: files[n_train n_val:], } for split, names in splits.items(): dst os.path.join(OUT_DIR, split, cls) os.makedirs(dst, exist_okTrue) for name in names: src os.path.join(cls_dir, name) img Image.open(src).convert(RGB) img.save(os.path.join(dst, name)) # 重新保存顺带修正格式 print(f{cls}: total{n}, train{len(splits[train])}, fval{len(splits[val])}, test{len(splits[test])})逻辑说明is_valid_image用两次Image.open第一次verify()只检查文件头第二次才真正解码并转 RGB避免「文件能打开但解码失败」的漏网之鱼。random.seed(42)保证每次划分结果一致论文里写「随机划分」时别人能复现。参数SPLIT我一般设 8:1:1如果某类样本少于 200 张会把验证集比例降到 0.05把更多数据留给训练。跑完后目录长这样dataset/ train/ 可回收/ 有害/ 厨余/ 其他/ val/ 可回收/ 有害/ 厨余/ 其他/ test/ 可回收/ 有害/ 厨余/ 其他/提示类别文件夹名不要用中文以外的特殊字符Windows 和 Linux 下编码不一致会导致 ImageFolder 读不到。如果必须用中文确认 Python 文件系统编码是 UTF-8。2.3 数据增强的边界哪些变换会帮倒忙训练时加数据增强能缓解过拟合但垃圾分类这个场景有几个反直觉的点。随机水平翻转基本安全因为瓶子左右翻转还是瓶子。但随机垂直翻转要慎用倒置的「有害垃圾」标志可能被模型学成另一个类别。颜色抖动ColorJitter幅度别开太大否则「厨余垃圾」的褐色被抖成灰色模型会混淆。我一般用这套组合from torchvision import transforms train_tf transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomResizedCrop(224, scale(0.7, 1.0)), # 随机裁剪 transforms.RandomHorizontalFlip(p0.5), # 只做水平翻转 transforms.ColorJitter(brightness0.2, contrast0.2), # 幅度克制 transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), # ImageNet 统计量 ]) val_tf transforms.Compose([ transforms.Resize((224, 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%太小会把垃圾主体裁掉。Normalize用的均值方差是 ImageNet 的统计量因为后面要用 ImageNet 预训练权重做迁移学习必须对齐。如果你从零训练可以改成自己数据集的统计量但收益不大直接用这套就行。3. 模型选型与迁移学习ResNet18 和 MobileNetV3 怎么选3.1 为什么毕业设计不建议从零搭 CNN热词里经常出现「卷积神经网络结构图」「lenet5 卷积神经网络」很多人第一反应是手写一个 LeNet 或自己堆几层 ConvPool。从学习角度这没错但从项目落地角度从零训练的 CNN 在几千张图上很难超过 75% 准确率而且训练慢、调参玄学。常见做法是用预训练模型做迁移学习把 ImageNet 上学到的特征拿过来只替换最后的全连接层用你的垃圾分类数据微调。这样即使每类只有几百张图也能跑到 90% 以上。选型上ResNet18 参数量约 1100 万MobileNetV3-Small 约 250 万。如果你要在树莓派或手机上部署选 MobileNetV3如果只在 PC 上跑、追求准确率ResNet18 更稳。两者在垃圾分类这种 4 到 6 类的任务上差距不大我一般先用 ResNet18 跑基线再换 MobileNetV3 看能不能在准确率掉 2% 以内的情况下把模型缩小。3.2 替换分类头的两种写法和参数含义import torch.nn as nn from torchvision import models def build_resnet18(num_classes4, freeze_backboneTrue): model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) if freeze_backbone: for p in model.parameters(): p.requires_grad False # 冻结主干 in_features model.fc.in_features # ResNet18 是 512 model.fc nn.Sequential( nn.Dropout(0.3), nn.Linear(in_features, num_classes) # 替换成你的类别数 ) return model def build_mobilenet_v3(num_classes4, freeze_backboneTrue): model models.mobilenet_v3_small( weightsmodels.MobileNet_V3_Small_Weights.IMAGENET1K_V1) if freeze_backbone: for p in model.parameters(): p.requires_grad False in_features model.classifier[0].in_features # 576 model.classifier nn.Sequential( nn.Linear(in_features, 256), nn.Hardswish(), nn.Dropout(0.3), nn.Linear(256, num_classes) ) return model逻辑说明freeze_backboneTrue时只训练新加的分类头适合数据量小于 5000 张的情况训练快且不容易过拟合。如果数据超过 1 万张可以把freeze_backbone设为 False用较小的学习率比如 1e-4整体微调。Dropout(0.3)放在全连接前是防止小数据集过拟合的常规手段别设太大0.5 以上会欠拟合。参数说明num_classes必须和你的类别文件夹数量一致多一个少一个都会在算 loss 时报维度错误。ResNet18 的fc.in_features是 512MobileNetV3-Small 的classifier[0].in_features是 576这两个数字写死也能跑但用属性读取更保险换模型时不用改。3.3 训练循环里必须盯住的三个量训练脚本本身不复杂但有三个量决定你能不能收敛学习率、batch size、以及验证集准确率的波动。我一般用 Adam学习率 1e-3冻结主干时或 1e-4整体微调时batch size 设 32 或 64取决于显存。下面是一个最小训练循环的骨架import torch from torch.utils.data import DataLoader from torchvision.datasets import ImageFolder device torch.device(cuda if torch.cuda.is_available() else cpu) train_ds ImageFolder(dataset/train, transformtrain_tf) val_ds ImageFolder(dataset/val, transformval_tf) train_loader DataLoader(train_ds, batch_size32, shuffleTrue, num_workers4) val_loader DataLoader(val_ds, batch_size32, shuffleFalse, num_workers4) model build_resnet18(num_classeslen(train_ds.classes)).to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam( filter(lambda p: p.requires_grad, model.parameters()), lr1e-3) 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() # 验证 model.eval() correct total 0 with torch.no_grad(): for imgs, labels in val_loader: imgs, labels imgs.to(device), labels.to(device) pred model(imgs).argmax(dim1) correct (pred labels).sum().item() total labels.size(0) print(fepoch {epoch}: val_acc{correct/total:.4f})逻辑说明filter(lambda p: p.requires_grad, ...)只把需要更新的参数交给优化器冻结的主干不会被误更新。验证阶段用model.eval()和torch.no_grad()前者关掉 Dropout 和 BatchNorm 的训练行为后者省显存。如果验证准确率连续 5 个 epoch 不涨就该降学习率或早停别硬跑 100 轮。参数说明num_workers4在 Windows 上有时会卡死改成 0 用主进程加载慢但稳。batch_size如果显存不够就减半同时把学习率也减半这是经验规律。4. 推理、部署与界面把模型变成能演示的系统4.1 单张图片推理的最小命令训练完保存权重后推理入口要能接受一张任意尺寸的图输出类别和置信度。下面这段可以直接当命令行工具用import sys import torch from PIL import Image from torchvision import transforms def predict(img_path, ckpt_pathbest.pth): device torch.device(cuda if torch.cuda.is_available() else cpu) ckpt torch.load(ckpt_path, map_locationdevice) classes ckpt[classes] # 保存时把类别名一起存 model build_resnet18(num_classeslen(classes), freeze_backboneFalse) model.load_state_dict(ckpt[state_dict]) model.to(device).eval() tf transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) img Image.open(img_path).convert(RGB) x tf(img).unsqueeze(0).to(device) # 加 batch 维度 with torch.no_grad(): prob torch.softmax(model(x), dim1)[0] idx prob.argmax().item() return classes[idx], prob[idx].item() if __name__ __main__: cls, conf predict(sys.argv[1]) print(f预测类别: {cls}, 置信度: {conf:.4f})逻辑说明保存 checkpoint 时把classes列表一起存进去推理时才能把索引映射回类别名否则你只知道「第 2 类」却不知道第 2 类是什么。unsqueeze(0)是给单张图补上 batch 维度因为模型期望输入是[N, C, H, W]。softmax把 logits 转成概率方便展示置信度。参数说明Resize((224, 224))必须和验证集一致训练时用了RandomResizedCrop但验证和推理都用直接 Resize这是标准做法。如果推理时用了不同的尺寸准确率会明显下降这个坑很隐蔽。4.2 用 Gradio 搭一个能演示的界面毕业设计答辩时命令行输出不够直观常见做法是用 Gradio 或 Streamlit 套一个上传图片的界面。Gradio 代码量最少import gradio as gr def classify(img): if img is None: return {} cls, conf predict_from_array(img) # 把 PIL 图转成模型输入 return {cls: conf} demo gr.Interface( fnclassify, inputsgr.Image(typepil), outputsgr.Label(num_top_classes4), title智能垃圾分类, ) demo.launch(server_name0.0.0.0, server_port7860)逻辑说明gr.Image(typepil)让 Gradio 把上传的图直接转成 PIL 对象省去自己处理文件流。gr.Label(num_top_classes4)会显示所有类别的概率条答辩时比只显示一个结果更有说服力。server_name0.0.0.0让局域网内其他设备也能访问方便演示。参数说明server_port默认 7860如果被占用就换一个。num_top_classes设成你的类别总数这样能看到模型在哪些类上犹豫。4.3 模型导出与轻量化什么时候该做什么时候别碰如果只是 PC 演示导出 ONNX 或 TorchScript 意义不大反而多一层转换可能引入精度损失。只有当你要部署到边缘设备比如 Jetson Nano、树莓派时才考虑导出 ONNX 再用 ONNX Runtime 推理或者用 Torch 的量化工具把 FP32 转成 INT8。我一般建议毕业设计阶段先把 PyTorch 版本跑稳量化作为「未来工作」写进论文即可别在答辩前一周折腾量化翻车概率很高。5. 避坑与排查训练不收敛、准确率虚高、推理对不上5.1 训练 loss 不降验证准确率卡在 25%现象四个类别验证准确率一直在 25% 左右等于随机猜。原因通常是标签和图片没对上或者ImageFolder读到的类别顺序和你以为的不一致。解决打印train_ds.classes和train_ds.class_to_idx确认类别名和索引的映射再抽几张图连同标签可视化一遍看是不是文件名排序导致的错位。5.2 训练准确率 99%测试准确率 60%现象训练集上几乎全对测试集惨不忍睹。原因是过拟合常见于数据量小又没加增强、或者把测试集混进了训练集。解决检查划分脚本有没有把同一张图分到两个集合加数据增强把freeze_backbone设为 True 只训练分类头加 Dropout 和权重衰减weight_decay1e-4。5.3 推理时置信度全是 0.25 左右现象单张图推理四个类别概率几乎相等。原因是推理时的预处理和训练时不一致最常见的是忘了Normalize或者用了不同的输入尺寸。解决把推理的 transform 和验证集的 transform 写成同一个对象别手抄一遍抄错一个参数就前功尽弃。5.4 CUDA out of memory现象训练几个 batch 后报显存不足。原因是 batch size 太大或图片尺寸太大。解决把 batch size 从 64 降到 32 或 16同时学习率按比例降或者把输入从 256 降到 224。如果还不行检查num_workers是不是设太高导致内存泄漏改成 2 或 0。5.5 中文类别名在 Linux 下乱码现象Windows 上跑得好好的放到 Linux 服务器上ImageFolder报找不到类别。原因是文件系统编码不一致。解决把类别文件夹名改成英文recyclable、hazardous、kitchen、other在代码里用字典映射回中文显示。这个改动越早做越好后期改要动数据目录和所有引用。6. 把准确率从 88% 推到 94% 的三个具体技巧第一个技巧是类别权重。垃圾分类数据几乎不可能完全均衡CrossEntropyLoss支持传weight参数把样本少的类别权重调高。计算方式是weight 1 / count再归一化。我试过在一个 5:1 不均衡的数据集上加权重后少数类召回率从 0.6 提到 0.85整体准确率涨了 3 个点。代码就一行counts [len(os.listdir(fdataset/train/{c})) for c in train_ds.classes] weights torch.tensor([1.0 / c for c in counts], dtypetorch.float).to(device) weights weights / weights.sum() * len(counts) criterion nn.CrossEntropyLoss(weightweights)第二个技巧是测试时增强TTA。推理时把同一张图做几次轻微变换原图、水平翻转、轻微裁剪分别预测后取平均概率。这个技巧不训练、不改模型纯推理端改动通常能涨 1 到 2 个点。代价是推理时间翻几倍演示场景可以接受。第三个技巧是分层学习率。整体微调时主干用 1e-4新加的分类头用 1e-3因为分类头是随机初始化的需要更快收敛。用 PyTorch 的param_groups实现head_params list(model.fc.parameters()) backbone_params [p for n, p in model.named_parameters() if not n.startswith(fc.) and p.requires_grad] optimizer torch.optim.Adam([ {params: backbone_params, lr: 1e-4}, {params: head_params, lr: 1e-3}, ], weight_decay1e-4)这三个技巧我一般按顺序上先加类别权重再看要不要 TTA最后调分层学习率。每加一个都重新跑一次验证集确认涨了再保留别一次性全加上否则出了问题不知道是哪个引起的。最后说个我自己的习惯每次改完参数把验证集准确率和对应的配置写进一个experiments.md格式就是「日期 改动 准确率」。做了十几版之后回头看能清楚知道哪个改动真正有用哪个只是玄学波动。毕业设计写「实验对比」那一章时这份记录直接就是素材。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

PTP设备同步互通测试解决方案
PTP设备同步互通测试解决方案

引言高精度时间同步网络是现代通信网络稳定运行的核心基础支撑,整套系统主要由提供标准时间源的核心时间同步设备、承担时间信号传输的传送与接入网络、各类末端业务应用设备三大核心部分组成。时间同步互通覆盖全链路设备适配测试,涵盖时间同步设备、分… · 2026/9/24 18:03:42

广东知名的建造师培训公司推荐,靠谱机构团队实力测评
广东知名的建造师培训公司推荐,靠谱机构团队实力测评

重庆仕仕通教育咨询有限公司,是深耕职业教育咨询领域、聚焦建筑工程行业人才职业成长的专业服务机构,精准定位为建筑行业全链条职业成长一站式服务提供商,核心围绕在职人员考证晋升的实际需求,打造职业资格培训、职称评审咨询两大… · 2026/9/24 18:03:35

电商评论情感分析实战:规则+词典+TinyBERT轻量级落地方案
电商评论情感分析实战:规则+词典+TinyBERT轻量级落地方案

简介:这是一份面向Python初学者与数据分析进阶学习者的实战型情感分析项目资源,聚焦电商平台商品评论文本的情感倾向判别,可直接用于课程设计、毕设选题或工程实训。资源压缩包共4个文件,包含核心分析脚本(.py&#xf… · 2026/9/24 18:03:35

从2比10到25比23:中国女排用23天完成一场漂亮的翻身仗
从2比10到25比23:中国女排用23天完成一场漂亮的翻身仗

2比10落后,还能赢吗? 9月22日晚,2026年爱知名古屋亚运会女排决赛,中国女排在第三局开局落后8分的情况下,将比分追至19平,最终以25比23完成逆转。随着日本队最后一次接发球出界,中国女排以3比0击… · 2026/9/24 18:43:57

TransUnet眼底血管分割实战:拆解Transformer与U-Net缝合细节
TransUnet眼底血管分割实战:拆解Transformer与U-Net缝合细节

简介:本资源是一套基于TransUnet架构实现眼底血管DRIVE数据集分割的完整实战方案,面向医学图像分割初学者与深度学习实践者,解决视网膜血管结构精准分割这一典型生物医学图像分析任务。压缩包共76个文件,含40张标注图像&#xff0… · 2026/9/24 18:43:57

Java Spring Boot搭建智慧养老平台:从设备接入到告警落地
Java Spring Boot搭建智慧养老平台:从设备接入到告警落地

简介:一套基于SpringBoot的智慧养老平台Java源码,面向计算机、电子信息工程等专业的学习者,可作为毕业设计、课程设计或期末大作业使用。项目采用B/S架构与MVC分层设计,后端整合SpringBoot、Mybatis与MySQL,前端结合Vu… · 2026/9/24 18:43:57

Flutter For OpenHarmony开发:用Liquid模板引擎优雅处理动态文本
Flutter For OpenHarmony开发:用Liquid模板引擎优雅处理动态文本

做 Flutter For OpenHarmony 开发,我把文本拼接这块硬骨头啃下来了做 Flutter For OpenHarmony 开发有一阵子了,要我说,最容易被低估的坑不在 UI,不在状态管理,反而在"文本处理"这种不起眼的地方。尤其那种&… · 2026/9/24 18:43:57

Flutter for OpenHarmony实战:扫雷游戏数字显示与适配解析
Flutter for OpenHarmony实战:扫雷游戏数字显示与适配解析

最近在折腾Flutter for OpenHarmony的游戏合集类App,踩了不少坑,也积累了一些可复现的经验。这个项目本身不复杂,就是做一个包含多个小游戏的App,先落地的是扫雷模块,重点难点在棋盘数字的生成与显示。但越是不复杂的项… · 2026/9/24 18:43:57

Unity编辑器深度定制:UI Toolkit、CustomPropertyDrawer与性能优化全解析
Unity编辑器深度定制:UI Toolkit、CustomPropertyDrawer与性能优化全解析

第3章做完时留言区问得最多的一句话是:能不能把工具栏也做成自己想要的写第3章的时候,我分享过怎么用MenuItem把自定义功能塞进菜单栏,怎么用EditorWindow创建独立工具面板,也提过CustomEditor重写 Inspector 的基本套路。当时评论… · 2026/9/24 18:43:50

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码