☰
基于深度学习的垃圾分类识别系统:从ResNet50到YOLOv5部署全解析
2026/10/20 3:58:42 网站建设 项目流程

1. 为什么毕业设计选了垃圾分类识别:一个被低估的深度学习课题

每年到了毕设开题季,总有同学在"图像分类""目标检测""人脸识别"这些经典题目之间反复横跳。我当年做毕设时也面临同样的选择,最后敲定的方向是基于深度学习的垃圾分类识别系统。说实话,刚开始我也觉得这题目有点"土"——垃圾分类听起来像是个偏工程、偏业务的东西,深度学习含量似乎不够高。但真正把需求拆开之后才发现,这个题目简直是"麻雀虽小、五脏俱全"的典范:它既有标准的图像分类任务作为基线,又有目标检测的进阶空间,还牵扯到数据增强、模型压缩、推理部署、UI交互等一系列完整链路。

换句话说,做这个题目,你不是在"完成一个毕设",而是在走一遍完整的AI落地流程。这对找工作和复试都有实打实的说服力。而且它的门槛相对友好:公开数据集好找、评估指标直观、展示效果好,评委老师一看就懂。相比某些偏门课题,垃圾分类识别属于那种"下限有保障、上限有空间"的安全牌。

这篇文章就围绕我当时做这套系统的完整思路展开,包括数据怎么准备、模型怎么选、训练踩了哪些坑、部署和界面怎么做,以及针对"如何答辩讲清楚"给出一些实操建议。如果你正在纠结毕设选题,或者已经选了类似题目但还没理清技术路线,这篇文章应该比你在网上随便搜到的"源码分享帖"更有参考价值。

先交代一下技术选型结论:分类部分我用了ResNet50 的迁移学习方案,检测部分用YOLOv5s 做二次识别,GUI 基于PySide6实现,最终打包成一个离线可运行的桌面程序。这套组合不是拍脑袋定的,下面我会逐步解释每一层选择背后的理由。

2. 数据集与类别体系:从"四分类还是多分类"这个灵魂问题开始

2.1 分类体系设计的决策逻辑

做垃圾分类识别,第一个绕不开的问题是:究竟分几类?最常见的选项是两种:

  1. 四分类:可回收垃圾、厨余垃圾、有害垃圾、其他垃圾——这是国内社区垃圾桶的经典配置,贴近真实场景,但类间差异其实很大,"其他垃圾"几乎是个垃圾筐,什么都能往里装,模型学起来容易懵。
  2. 多分类(如 40+ 类):按具体物品细分,比如塑料瓶、易拉罐、玻璃、纸板、电池、药片等。训练难度更高,但对系统能力的体现更充分。

我当时的选择是多分类作为主模型、四分类作为辅助映射。也就是说,模型先识别出"这是塑料瓶",再通过预设映射表,把它归类为"可回收垃圾"。这样做有两个直接好处:一是算法的判别能力体现得更充分,答辩时有内容可讲;二是最终呈现在界面上的结果仍然是"可回收垃圾"这种用户能直接理解的类别,不会出现"AI识别出PE塑料"然后用户一头雾水的情况。

2.2 数据获取与清洗的实操经验

数据集方面,公开资源里最常用的是华为云垃圾分类数据集和Kaggle上的垃圾分类相关集合。华为云那版大概有几万张图片,覆盖了常见的生活垃圾。但直接拿过来训练会有一个"看起来没问题、实际很致命"的隐患——大量图片是纯色背景下的商品图,而真实场景中的垃圾往往是皱巴巴的、脏兮兮的、被遮挡的。如果你训练的模型只在干净背景上表现好,确实测起来很准,但换到真实拍摄的照片就立刻原形毕露。

我的做法是这样:

  • 先按类别把数据集拆开,人工筛掉模糊、重复、标注错误明显的图片;
  • 对每一类确保数量不低于 300 张,不足的类通过爬虫抓取后二次清洗补齐;
  • 把大概 10% 的干净背景图片替换成"生活场景图"——比如桌面上的外卖盒、草地上的矿泉水瓶、厨房水槽里的菜叶子。这类图片让模型更容易学到"纹理"而非"背景"。

数据增强方面,我用的组合是:随机水平翻转、随机旋转(±15度)、随机亮度/对比度扰动、随机裁剪缩放(0.8到1.2倍),以及少量高斯噪声。有一件事值得特别注意:不要对垃圾分类任务使用随机垂直翻转。因为瓶子和罐子倒过来放,语义上依然是"塑料瓶",但真实场景中,垃圾很少出现倒挂视角的拍摄。强行增强只会增加模型的学习负担。这个细节很多教程不会提,但影响挺实在的。

3. 模型选型的真实对比:从轻量模型到迁移学习

3.1 为什么没选MobileNetV3作为主模型

在定下 ResNet50 之前,我其实先试过 MobileNetV3。它的优势非常明显:参数量小、推理快、对CPU友好。我在同一批数据上做过对比实验,MobileNetV3 在验证集上的准确率大概在 88% 左右,而 ResNet50 能达到 93% 上下。差距主要出现在那些形态相似的类别上,比如"纸杯"和"纸盒",以及不同颜色的"玻璃瓶"。轻量模型为了压缩计算量,牺牲了部分细粒度特征的表达能力,在类别数超过 20 时,这个差距会被明显放大。

但我也不是完全否定了轻量模型的价值。如果你的毕设要求不高,或者打算部署到树莓派这类边缘设备上,那么 MobileNetV3 依然是一个合理的基座方案。做技术选型时,先明确算力约束和使用场景,再谈模型性能,否则讨论都是在空转。

3.2 ResNet50 迁移学习的完整配置

我的最终方案是加载 ImageNet 预训练权重的 ResNet50,替换全连接层后微调。具体配置如下:

  • 输入尺寸:224×224
  • 优化器:Adam,初始学习率 0.0001
  • 权重衰减:1e-4
  • 批次大小:32
  • 训练轮数:20 轮(先用冻结 backbone 的方式跑 5 轮,再解冻全部层微调 15 轮)
  • 学习率调度:余弦退火,最低降到 0.00001

这里有一个值得展开的点:学习率为什么要这么低?因为预训练模型已经学到了通用的底层特征,比如边缘、纹理、颜色分布。过大的学习率会把已经学好的特征冲掉,通常表现为训练集准确率快速上升,但验证集准确率却停滞不动。我第一次跑的时候用了 0.001,结果验证集一直在 90% 上下徘徊,改成 0.0001 之后第二轮就到了 93%。这类经验只有自己踩过才会印象深刻。

# 核心训练代码片段(PyTorch) import torch import torch.nn as nn import torchvision.models as models model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V2) num_features = model.fc.in_features model.fc = nn.Linear(num_features, num_classes) # 前5轮冻结backbone for param in model.parameters(): param.requires_grad = False for param in model.fc.parameters(): param.requires_grad = True

冻结 backbone 的训练方式,非常适合数据量不太大的场景。它相当于让模型在原有"视觉常识"的基础上,只补学一套"垃圾分类专用分类头",既能防止过拟合,又能显著缩短前期收敛时间。

4. 识别精度与误判处理:YOLOv5 用来解决什么问题

4.1 纯分类模型的软肋

如果只做图像分类,这套系统会存在一个明显短板:模型只能告诉你"图片里大概率是什么",但它压根不知道物体在哪里。当你把一张包含多个物品的照片扔进去,分类模型只会输出一个标签,而这张照片里可能同时有塑料瓶和纸盒。

解决这个问题有两个方向:

  1. 改成目标检测,直接输出多个物体的位置和类别;
  2. 保留分类模型,但增加一个前置的"目标提取"步骤。

我当时选的是第二种思路的加强版:先用 YOLOv5s 做检测,把检测到的每个物体裁剪出来,再分别送入 ResNet50 做精细分类。为什么不是直接用 YOLOv5 输出最终类别?因为 YOLOv5 自带的类别体系不一定覆盖你想要的垃圾细分类,比如"奶茶杯"和"塑料袋"在某些检测数据集里可能属于 A 类或"其他",语义粒度不够。用两级结构,我既保留了检测的定位能力,又拿了分类模型的细粒度判别。

4.2 YOLOv5s 训练与参数细节

YOLOv5s 是这套模型系列里体积最小的版本,参数量约 700 万,GPU 上单卡能跑得动,CPU 推理也不算太慢。我训练的配置如下:

  • 输入分辨率:640×640
  • 批次大小:16
  • epoch:50 轮
  • 优化器:SGD,初始学习率 0.01
  • 数据标注:用 LabelImg 手动框了大概 4000 个目标框

训练 YOLO 时有一个最容易忽视的点:anchor 的自动重聚类。官方代码默认会在训练前自动计算数据集的 anchor 尺寸,但如果你换了数据集之后把 autoanchor 关掉了,模型收敛会变得很慢,甚至 mAP 上不去。我第一次训练时就遇到了这个情况,训练到第 20 轮损失还是下不来,排查后才发现是锚框尺寸和数据严重不匹配。

4.3 误判率最高的几个类别及补救手段

实际跑测试时,误判率最高的几组是:干净的纸盒 vs 脏的纸盒、透明塑料袋 vs 白色塑料瓶、浅色玻璃瓶 vs 白色陶瓷。前两组容易理解,第三组很有意思——分类模型看到的主要是颜色、光泽和形状,玻璃和陶瓷在某些拍摄角度下几乎无法区分。

补救手段我做了两个方向:

  • 采集更多"脏污/褶皱/光线变化"的样本加入训练集,让模型不只靠颜色光滑度做判断;
  • 在系统界面中增加"人工确认"按钮。当模型输出概率低于某个阈值(比如 0.7)时,系统提示用户二次确认或手动选择类别。这不是模型层面的解决方案,但它在现实使用中非常必要,因为垃圾分类识别这个场景本身就存在"人都不一定看得准"的边界案例。

注意:分类模型输出的 softmax 概率并不直接等于真实置信度。Softmax 是相对概率分布,它会强制所有类别相加为 1,即使样本属于未知类别,模型也必须给一个相对最高的类别。所以阈值设置只能作为一个参考信号,不能当作严格的不确定性估计。

5. 界面与工程落地:PySide6 桌面应用是怎么搭起来的

5.1 为什么用 PySide6 而不是 Flask + Web

毕设展示环节,很多同学会选择做一个 Web 页面,因为部署简单、演示灵活。但我的需求里有一条:系统需要在无网络环境下运行。教室、实验室现场的 WiFi 不稳定,如果依赖 Flask 启动一个本地服务,再通过浏览器访问,一旦服务端口被占用或者浏览器缓存异常,展示就会出状况。桌面应用反而更稳妥——双击打开、选择图片、出结果,完了。

PySide6 是 Qt 的 Python 绑定,界面写起来比 Tkinter 舒服,又有成熟的打包工具链。整个过程下来,我觉得最舒服的一点是它的信号槽机制,让界面操作和模型推理逻辑能解耦。

5.2 推理线程的设计:卡UI是最大的坑

如果你直接在按钮的回调函数里跑模型推理,一旦图片比较大,界面就会冻结,拖拽窗口时会变成"无响应"。这个体验对答辩来说是灾难性的。

我的解决方案是用 QThread 单独开一个工作线程,模型加载和推理都放在线程里,主线程只负责接收结果并更新界面。大概的代码框架是这样的:

from PySide6.QtCore import QThread, Signal class InferWorker(QThread): finished = Signal(str, float) # 类别,置信度 def __init__(self, image_path, model, transform): super().__init__() self.image_path = image_path self.model = model self.transform = transform def run(self): result = predict(self.image_path, self.model, self.transform) self.finished.emit(result[0], result[1])

这样处理后,即便推理耗时一两秒,界面也始终能正常响应。实现成本很低,但体验提升非常明显。

我还在界面上加了三样东西:

  1. 置信度进度条:直观展示模型对结果的"自信程度";
  2. 映射表展示:多分类结果映射到四分类后,显示对应颜色标识(绿色=可回收,灰色=其他,红色=有害等);
  3. 批量识别:用户可上传整个文件夹,系统逐个识别并导出一个 CSV 表格。

6. 训练与调参过程中的五个印象深刻的坑

6.1 类别不平衡:某些类别占了50%的训练数据

公开数据集里"易拉罐"和"塑料瓶"这类常见垃圾图片非常多,而"打火机""温度计"这类不常见样本可能只有几十张。直接训练会导致少数类别几乎从来没被正确预测过。处理方式包括:

  • 将大类随机下采样,小类通过复制加轻微扰动的方式过采样;
  • 使用加权采样器(WeightedRandomSampler),让每个 epoch 中各类别抽到样本的期望次数接近相等;
  • 在损失函数中给少数类更高的权重。我当时用的是 Focal Loss 的简化版本,对难样本更聚焦。

6.2 过拟合特征:背景泄漏的经典陷阱

有一类常见错误极具迷惑性——模型不是靠垃圾本身,而是靠背景来分类。比如"树叶"类样本很多是绿地背景,模型学到的特征是"绿色",而不是"树叶纹理"。测试时你会看到准确率不错,但把一张草地上拍的可乐罐扔进去,它可能也报"树叶"。

这个问题怎么自查?把训练集里某几张图片的物体抠出来,贴到纯白背景上再测试。如果模型输出突变很大,说明它高度依赖背景特征。解决思路还是一样:增加背景多样性,或者用目标检测先裁剪物体区域再分类,这两种手段都能有效缓解。

6.3 推理速度比预期慢:CPU 上的优化空间

ResNet50 在 GPU 上推理很快,但很多同学的毕设演示环境根本没有独立显卡,CPU 跑一张图可能需要 800ms 到 1.5 秒。为了优化,我做了这几点:

  • 使用 ONNX Runtime 替代纯 PyTorch 推理,在 CPU 上通常能快 20%~40%;
  • 将输入尺寸从 224 适当缩到 192,准确率几乎不掉,但推理加快;
  • 开启单线程和多线程的平衡调整,Intel CPU 上把 intra-op 线程数设为物理核心数,推理延迟可控。

6.4 显存溢出:小显存卡怎么训练

实验室如果只有 4GB 显存的卡,训练 ResNet50 加 YOLOv5s 会比较紧张。方案是:

  • 开启梯度累积,每 4 个 batch 更新一次参数,等效于扩大 batch size;
  • 混精度训练(AMP),要让 ResNet50 跑到 224 分辨率,混精度之后显存占用能降 30% 左右;
  • 如果还不行,把 ResNet 输入降到 192,或者考虑 ResNet34。

6.5 打包体积膨胀:PyTorch 打包出来的 exe 有 1.5GB 以上

用 PyInstaller 打包 PyTorch 应用,体积会非常夸张。我最终做的是用 ONNX 模型替代 PyTorch 模型文件,再配合精简依赖,打包体积从 1.5GB 降到了大概 400MB。这一步在整个工程化落地里性价比极高。不同版本的 ONNX Runtime 对 CPU 指令集的要求略有差异,建议在目标演示机上先跑一个最小测试程序确认可以正常加载。

7. 如何把毕设讲出亮点:答辩角度的叙事思路

很多同学做完了系统,但答辩时只会说"我用了 ResNet50 和 YOLOv5,准确率 93%"。这远远不够。评委更希望听到的是你面对具体问题时的决策过程。以下是我当年准备的几条叙事主线,供参考:

  1. "我为什么没一上来就用最重的模型?"——先说 MobileNetV3 的尝试与瓶颈,再引出 ResNet50 的选型理由,体现你做过对比实验;
  2. "分类准确率不是唯一指标"——补充说明结果显示和阈值机制的设计,体现你考虑过真实使用场景;
  3. "数据是模型的起点"——多提数据清洗、类别不平衡、背景泄漏问题,说明你理解深度学习项目的工程全貌而非只会调库训练;
  4. "性能优化经历了从 PyTorch 到 ONNX Runtime 的转变"——展示你对部署环节的认识,这在问到"以后还能怎么改进"时尤其加分。

答辩时实测演示一定要提前准备三张图:一张标准场景图、一张多物体混合图、一张"容易误判"的模糊图。前两张展示正常能力,第三张展示置信度阈值控制逻辑,反而比全程准确更能说明你的思考深度。

8. 还可以怎么扩展:从毕设到真正可用的系统

毕设做完了,但不代表这套系统的潜力到头了。它至少还有三个方向的扩展空间:

硬件方向:把模型部署到树莓派加摄像头,做成"拍照识别即分类"的嵌入式设备。由于模型已经是 ONNX 格式,Raspberry Pi 上跑起来不算困难,只需要把主干网络换得更轻量一些;

算法方向:从识别模型升级为"识别+定位拆分"的联动方案,或者针对易混淆类(玻璃瓶 vs 陶瓷、纸盒 vs 纸杯)单独训练一个细粒度分类模型作为第二级校验;

数据方向:设计一个小型的增量学习流程,让用户在界面上"纠正"错误分类结果,系统定期把纠错数据加入训练集重新微调。这个功能一旦做出来,系统就不再是静态固化的模型,而是能随着使用逐步优化的闭环系统。

我在实际做扩展实验时发现,最简单的增量微调方式是:用户每次点击"人工纠正"时,把当前图片和正确标签保存到一个本地文件夹,累积到 200 张后,触发一次低学习率微调。这个流程不复杂,但能让毕设成果在答辩时讲出一个非常漂亮的"持续学习"故事。

做这个毕设时我最有体会的一点是:深度学习项目的核心竞争力往往不在模型选型本身,而在你对数据的理解和对应用场景的把握。垃圾分类识别看起来是个"老旧"的课题,但当它被放在一个完整系统中去思考,你会发现它牵引出的每一个技术节点——数据增强、迁移学习、目标检测、模型压缩、GUI 工程化——都值得深挖两三层。选一个"麻雀虽小五脏俱全"的题目,用心做完,它给你的训练绝不亚于一个表面花哨的大项目。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询