☰
基于YOLOv8改进的垃圾分类识别目标检测系统实战
2026/9/29 12:23:35 网站建设 项目流程

垃圾分类识别这个方向,我从最早用传统图像特征(HOG加SVM)做到后来全面转向YOLOv8改进方案,前后迭代了差不多三版才算真正落地。今天这篇文章,就把这个“基于深度学习的垃圾分类识别目标检测系统”从数据、模型改进、训练、部署到踩坑的完整过程讲清楚。项目核心是基于YOLOv8做生活垃圾图像识别,重点解决小目标漏检和相似类别混淆这两类老大难问题。

文章会比较长,但每一步都尽量按实操来写,参数、命令、改进策略都是我在真实训练中验证过的方案。适合正在做目标检测课题的学生、打算把垃圾分类识别做成产品的团队,以及想系统了解YOLOv8改进套路的朋友。

1. 项目整体思路拆解:垃圾分类识别到底难在哪

1.1 这个场景不是简单的“目标检测”问题

刚接触垃圾分类识别的人,容易把它当成一个常规的通用目标检测任务来处理。其实生活垃圾场景有两个很明显的特殊性,导致直接套用预训练模型效果很差。

第一个特殊点是目标尺寸跨度极大。摄像头下面,一张废纸箱可能铺满大半个画面,而一个烟头、一节电池、一片药丸可能只有二三十个像素。YOLOv8默认的检测层是从P3开始的,也就是原图缩小到八分之一之后才提取特征,小目标的特征在这个尺度下基本被“磨平”了。我一开始用yolov8s默认配置训练,烟头这一类别的AP值只有不到20%,几乎等于瞎猜。

第二个特殊点是类别之间视觉相似度太高。塑料瓶和玻璃瓶、纸盒和牛奶盒、果皮和菜叶,颜色和纹理都非常接近。不同城市甚至不同小区的垃圾收集标准还不一样,有的地方按“可回收、有害、厨余、其他”四分类,有的地方细分到十类以上。这对模型的细粒度特征提取能力提出了很高要求,单纯加大模型容量效果有限,必须有针对性的结构改进。

1.2 为什么基座选YOLOv8而不是其他

在做模型选型的时候,我把当时主流的几套方案都跑了一遍对比。Faster R-CNN系列虽然精度上限高,但推理速度实在感人,一张640的图在GTX 1660 Ti上跑一次要200毫秒左右,做实时视频流识别完全不现实。SSD的检测头对小目标不友好,标注工具里经常出现“地面纸巾没框全”的问题。YOLOv5在训练稳定性上没得说,但它用的是Anchor-Based的耦合头,对垃圾这种形状不规则的物体适应力差一些。

YOLOv8做得比较聪明的地方有三处。第一,它全面转向Anchor-Free,直接在特征图上预测每个位置的目标中心与宽高,不需要预设一堆锚框尺寸,对垃圾这种尺度跨度大的目标反而更灵活。第二,它把检测头拆成分类和回归两个分支,互不干扰,这一点在处理“塑料瓶和玻璃瓶长得像”这种细分类别时帮助很大。第三,它的C2f结构在Backbone里融合了不同层的特征,比V5的C3模块多了梯度流分支,信息传递更充分。

再加上Ultralytics社区的生态确实做得好,配置文件、预训练权重、导出工具链都很完善,拿过来改网络结构非常方便。所以最终基座就定了yolov8s和yolov8m两个规格,实际训练时以yolov8s为主,m版本用于对比验证。

1.3 改进方向是怎么定下来的

我针对垃圾分类识别的实际需求,把改进方向拆成三个维度:小目标召回、细粒度分类、骨干网络的信息利用效率。这三个问题对应到网络结构上,分别是检测层、注意力机制和特征融合模块。

一开始我尝试过很多“论文里很好看”的改进,比如把Backbone换成Swin Transformer、引入可变形卷积,训练出来的模型参数量暴涨,推理速度掉了一半,精度提升却不到1个点。后来我把思路收敛回来,只做以下几点改动:在Neck部分增加一条P2小目标检测层;在Backbone的深层特征前引入坐标注意力模块;检测头改成轻量化解耦结构;损失函数加上难例挖掘机制。每个改动都做了一次消融实验,确保有效才保留。这种做法虽然不够“炫”,但每一步都能说明白为什么改,最终效果也更可控。

2. 数据集构建与预处理:没有好数据,模型再强也白搭

2.1 数据集来源与类别体系设计

垃圾分类识别的数据集构建,是整个项目里最花时间也最容易被低估的环节。我先用公开的垃圾分类数据集(TrashNet和华为垃圾分类数据集)做了一轮预训练,确认基线能跑通,再开始自己标注真实场景数据。

公开数据集的问题在于场景太“干净”。TrashNet里的图片都是纯色背景、单个物体居中,模型在这种数据上表现不错,但一放到实际垃圾桶旁、光线杂乱的环境下,掉点非常严重。所以我的数据策略是:公开数据集负责“打底”,自建数据负责“适应真实场景”。

在类别体系设计上,我建议不要一上来就套“四分法”,因为可回收垃圾里有一本书和有一个纸箱,模型要学的东西完全不一样。最终我设计了14个类别,包括塑料瓶、玻璃瓶、易拉罐、纸板、纸张、果皮、蔬菜叶、剩饭、电池、灯泡、烟头、塑料餐盒、一次性餐具、布料。这样既保留了足够粒度,又没把训练难度抬到不可控。

2.2 标注规范与数据清洗

标注环节我踩过一个很典型的坑:前500张图让三个同学分头标,结果同一类物体,有人框得很紧,有人留了大量空白边,导致模型训练时回归分支经常抖动。后来我定了三条硬性规范。

  • 标注框必须贴着目标可见边缘,压住遮挡部分不算无效,但必须保证目标主体有超过70%区域在框内。
  • 半遮挡目标要标,能认出类别就标,这样模型在遮挡场景下才有泛化能力。
  • 一个目标被另一个目标挡掉大半,且人眼看不清类别时,不标,算难例交给后续负样本处理。

数据清洗方面,我把裁出来的目标图按类别做了一个“目视审查”。一个人一小时大概能过3000到5000个目标实例,重点剔除三类数据:严重模糊的、目标占比小于1%且完全看不出纹理的、标注类别明显标错的。这一步很枯燥,但对最终精度的贡献不亚于模型改进。我带的一个实习生花了两个周末干完这件事后,模型在验证集上的mAP直接涨了3个百分点。

2.3 数据增强策略与训练集划分

数据增强方面,基础操作我都开了,包括上下左右翻转、小角度旋转、HSV色调扰动、随机仿射变换和Mosaic。这里要说一下Mosaic的具体坑:YOLOv8自带的Mosaic是把四张图拼在一起训练,好处是变相增加batch多样性,坏处是垃圾目标本身尺寸就小,再被四分之一缩放,很多目标直接变成了小于10像素的“点”,模型根本学不到有效特征。

我的做法是把Mosaic保留,但在增强参数里把scale和translate的幅度调低一点,避免目标缩小得太离谱。另外我加了Random Erase,也就是随机擦除图片中的一块区域,强迫模型不依赖局部特征做判断。这个操作对“烟头和碎纸屑混淆”这种问题很有效,因为模型不能只靠颜色猜类别了。

数据划分我用的是7:2:1的比例,训练集、验证集、测试集。这里特别提醒一句:划分时一定要按视频片段或场景分组,不能随机打乱图片。否则同一个垃圾桶、同一次连续拍摄中非常相似的帧会同时出现在训练集和测试集里,测试结果虚高得厉害。第一版我就犯了这个错误,测试mAP到0.93,实际现场跑只有0.7出头。

3. 基于YOLOv8的改进方案设计与实现

3.1 先看清YOLOv8的网络结构再动手

很多朋友拿到YOLOv8第一件事就是去改代码,改了半天不知道自己动的东西在整个网络里是什么角色。我的建议是先把网络结构图吃透,Ultralytics仓库里通过model.yaml就能看到整体结构,配合Netron可视化一下,基本能搞清楚每个模块在干什么。

YOLOv8整体分三段。Backbone负责从原始图像提取特征,主干是Conv加C2f结构,C2f可以理解成增强版的残差模块,把输入特征拆成两条路,一条直通另一条经过多个Bottleneck,最后拼接在一起,优点是梯度和特征都能在深层和浅层之间更充分地流动。Neck部分用FPN和PAN的组合,把高层语义信息传到浅层,同时把浅层位置信息传回深层,让每一层检测头都能拿到“既懂内容又懂位置”的特征。Head部分就是解耦检测头,分类分支输出目标类别概率,回归分支输出边界框坐标,两边的通道是分开的。

我在动手之前,先把配置文件里每个module的输入输出通道数写了一遍,确保后续改动特征图尺寸不会对不上。这个习惯帮我省了很多调试时间。

3.2 引入坐标注意力,让模型“懂得找位置”

垃圾分类场景里,目标位置往往和类别有隐含关联。电池这种小物件大概率在垃圾堆表面或者散落在地面,而餐盒往往是堆叠的。普通的通道注意力机制(例如SE模块)只关注“哪些通道重要”,不关心“目标在哪个位置”,对空间位置敏感的垃圾检测帮助有限。

我最终选择在Backbone最后一层输出之前插入Coordinate Attention。这个模块的思路很简单:把传统SE里的全局平均池化分解成水平和垂直两个方向的一维池化,分别提取行方向和列方向的依赖关系,再把两个方向的特征拼接、卷积、归一化,最后生成注意力权重。这样模型在关注“什么类别”的同时,也能知道“大致在哪一行、哪一列”。实测下来,加了CA模块之后,烟头和小纸屑这两类的召回率各涨了约2个百分点,而且推理速度几乎没受影响,参数量增加可以接受。

需要注意的是,CA模块的插入位置很讲究。我试过插在Backbone中间,效果不明显;插在最后一层输出的C2f之前,效果最好。原因也好理解:深层特征图空间分辨率低,注意力机制能“指点”的区域更明确,更有利于把高频特征和位置信息结合起来。

3.3 针对小目标:增加P2检测层

小目标是垃圾分类场景的头号敌人,P2检测层是应对这个问题最直接的手段。YOLOv8默认的输出特征图三条尺度分别是原图的八分之一、十六分之一、三十二分之一。P2层把最低层特征图的分辨率提升到原图的四分之一,也就是让模型在一个更“大”的图上做检测,每个目标占用的像素更多,特征信息更完整。

实现P2层,需要在Neck部分增加相应的上采样节点,把原图四分之一分辨率的Backbone浅层特征直接引入FPN金字塔。我这里补充一句:增加P2层后训练速度会明显变慢,因为浅层特征图尺寸大,计算量成倍上涨。我的做法是只对包含小目标类别含量高的数据集开启P2,非小目标类别的场景跑默认配置,两者做成可配置项,切换非常方便。

3.4 检测头与损失函数的细节改进

检测头方面,YOLOv8的Decoupled Head本身已经不错,我做的是轻量化改造,把分类分支中的卷积结构调整为分组卷积加逐点卷积的组合,参数量下降约15%,精度基本持平。这个改动主要为了让最终模型更容易部署到边缘设备上,毕竟垃圾分类识别在不少场景里要跑在嵌入式设备上。

损失函数这里有一个很值得说的经验。YOLOv8默认用的是BCEWithLogitsLoss做分类损失,CIoU做回归损失,在绝大多任务上没问题,但我发现两个具体问题。一个是垃圾桶背后场景复杂,困难负样本很多,模型容易把背景误判成垃圾;另一个是烟头和碎纸屑这种高频混淆对,默认的交叉熵损失对它们的梯度激励不足。

我采用的方案是给分类损失加上Focal Loss,就是让模型集中注意力去学习困难样本。同时把回归损失从CIoU换成SIoU,它对边界框的方向匹配更敏感一些,最后的收敛精度上有一点点提升。这里要强调:任何损失函数改动都要做消融对比,我见过有人把Focal Loss的全套参数都打开之后,正常样本反而学不好,损失震荡得很厉害,问题就出在alpha和gamma没调好,需要结合训练损失曲线一起看。

4. 环境配置与训练实操记录

4.1 深度学习环境搭建:从零开始跑通YOLOv8

环境配置是整个项目第一个劝退点,但也是体系化最成熟的部分。我当时的机器配置是Ryzen 5600X加GTX 1660 Ti 6GB,放在现在看性能已经比较落伍,但只要显存规划合理,训练yolov8s级别模型完全够用。

先列一份我验证过没问题的环境清单:

  • 系统:Ubuntu 20.04,Windows 10也可以跑但优先推荐Linux
  • Python 3.9,别用3.6,版本太老装不上新版PyTorch
  • PyTorch 1.13.1 + CUDA 11.7 + cuDNN 8.5
  • Ultralytics库,也就是YOLOv8的官方包,直接pip安装

安装命令很简单:

pip install ultralytics

安装完成后验证GPU是否可用:

python -c "import torch; print(torch.cuda.is_available())"

如果这条命令返回True,说明CUDA环境是通的。如果返回False,我建议先到PyTorch官网选对应CUDA版本的安装命令重装torch,而不是先去折腾系统里的显卡驱动。

6GB显存是我反复测试过的瓶颈,训练时的batch-size开到16,输入尺寸640x640,可以稳定训练不爆显存。如果显存只有4GB,我的建议是把imgsz降到480,或者改用yolov8n这个nano版本,精度会损失一点但至少能跑。

4.2 训练参数逐项深度解读

YOLOv8的Ultralytics命令行我几乎每天都在用,但很多朋友只记住了“训练完看mAP”这一件事,对参数理解不透,出了问题不知道往哪里调。我把最重要的几个参数展开说一下。

epochs是训练轮数,垃圾分类数据集规模不算大,我一般设150轮左右,配合早停机制也就是patience参数,如果连续30轮验证集指标没有提升就自动停掉,避免过拟合。

batch-size俗称批大小,决定每次更新权重时“喂”给模型多少张图。显存允许的话尽量开大,因为大batch能让梯度估计更稳定,训练曲线也更平滑。显存小就把batch调小,但学习率也要相应调低。

imgsz是输入图片尺寸。640是YOLOv8默认值,对大多数场景够用。我发现把训练尺寸从640提到768,在自建垃圾分类数据集上小目标的mAP提升了约两个点,代价是训练和推理都变慢。如果目标是实时视频流,建议保持640。

配置文件的字段也很关键,data参数指向一个YAML文件,里面写明train路径、val路径和类别名称列表。这里有一个我踩过的坑:类别名称顺序必须和标注文件中的类别ID一一对应,一旦写错了顺序,模型训练出来的分类结果全是错位的,而且训练过程中loss还表现得很正常,很难排查。

4.3 训练过程的损失函数曲线分析

训练不只看最终指标,还要学会看损失曲线。YOLOv8训练时会在run目录下生成一系列结果图,其中最关键的就是train/box_loss、train/cls_loss、val/box_loss和val/cls_loss这几条曲线。

如果训练损失在下降,但验证损失在前几十轮就开始回升,说明模型开始过拟合,这时候即使训练集准确率再高也没有意义,垃圾分类识别最终要面对的是没见过的真实场景。我的处理办法是增加数据增强强度、加入早停,或者把模型缩小一档。如果训练损失和验证损失都在高位震荡,就要优先检查学习率是不是过大了。

当模型的分类损失出现周期性突刺,比如每隔几个batch突然冲高一次,往往是因为数据中存在标注错误或类别严重不均衡。我一般会用这部分输出去定位具体是哪些样本引起的,把它们从训练集中临时抽走单独检查,比盲目调参高效得多。

5. 模型评估与系统落地实践

5.1 评价指标怎么解读:只看mAP不够

很多人训练完只看一个mAP数字,但这个数字会骗人。垃圾分类识别必须分别看mAP50、mAP50-95、Precision和Recall,还要结合PR曲线和混淆矩阵来分析。

mAP50表示IoU阈值50%时候的平均精度,它比较宽容,主要反映“大概框到了”的能力。mAP50-95则是把IoU从50%到95%分多个档位求平均,这个指标更严格,对小目标、形状不规则目标非常不友好,但对实际部署更有参考价值。垃圾分类场景里物体形状差异大,mAP50-95比mAP50重要。

还要养成看混淆矩阵的习惯。我第一版模型在验证集上mAP有0.87,看混淆矩阵才发现“烟头”和“小纸屑”之间互相错的概率很高,这两个类别对系统用户来说又恰恰是非常需要区分的,于是在后续训练中针对性地增加这两类样本,并给分类损失加了类别权重,把这个问题压下去了。

5.2 模型轻量化部署与推理加速

课题研究和真实落地最大的区别在于部署。实验室里跑640的模型一张图200毫秒无所谓,但现场如果要求实时识别,就必须考虑模型大小、显存占用和推理速度。

我用的第一步是知识蒸馏。用yolov8m模型担任“老师”,指导yolov8n“学生”训练。很多人的蒸馏经验是直接拿学生模型使劲训,效果不好,是因为单靠标签信号学生很难赶超老师。比较好的做法是双重蒸馏:输出特征对齐加分类逻辑的软标签对齐,蒸馏后的yolov8n在自建测试集上的mAP只比yolov8m低0.6个点,体量却只有四分之一左右。

第二步是导出ONNX格式并转成TensorRT做加速。如果目标平台是瑞芯微RK3588这样的边缘盒子,导出后的模型还能进一步量化为FP16或INT8,精度会小幅下降,但速度能提升一倍以上。实测下来,在同一块RK3588上,FP16精度的YOLOv8s推理一帧耗时能稳定控制在30到40毫秒之间,满足实时性要求。

5.3 交互界面设计与系统集成

做成一个没人能直接看的模型文件没有意义,系统集成阶段我做了一个轻量级界面,用PyQt5把摄像头画面、检测框、分类结果和置信度实时显示出来,同时支持上传图片单张识别。功能不复杂,但做的时候要特别注意两个问题。

第一个是线程模型。检测推理耗时不可忽略,如果放在UI主线程里执行,摄像头画面会卡死,用户体验极差。比较合理的做法是把视频帧采集、模型推理、结果显示分到三个不同线程,通过队列传递数据。第二个是每帧的置信度阈值要统一设置,不同场景下同一个阈值表现差异很大,需要提供一个滑杆让使用者可以按实际情况调整。

我还把最终识别结果接了一层逻辑规则,比如对连续帧的检测结果做时序平滑处理,只有连续三帧检测到同一类别才输出“确认丢弃”的提示。这个小功能在真实垃圾桶前非常实用,能有效过滤偶发的误检。

6. 常见问题与排查技巧实录

6.1 Loss不收敛或训练发散的排查

训练中loss不降这个问题,我相信每个人都遇到过。如果从头训一个新模型loss一直不降,最先排查的应该是数据路径和类别配置。我之前有一次怎么训都发散,后来发现是data.yaml里的类别顺序和标注文件对不上,模型完全“学反了”。这种情况只看loss曲线根本看不出问题。

如果确认数据无恙,就把学习率调到默认值再试。YOLOv8默认的lr0是0.01,大batch下你可能要降低这个值。还有一种情况是数据集里面存在类别单样本、甚至空标注的图片文件,也会引发loss震荡,我在做数据清洗时强制加了一步“标注文件为空或面积过小的图片直接跳过”,之后训练稳定性好了很多。

6.2 小目标漏检率居高不下怎么办

小目标漏检不是单一原因,需要逐项排查。先确认你的训练标签里小目标占多大比例,如果烟头类别的样本一共只有30个,那加再多注意力模块也没用,得先扩充数据。然后确认训练尺寸,如果只有640,小目标像素占比实在太低,可以试试提升到960,或者用滑窗切图的方式把小图放大再送入模型。

结构层面可以加入P2检测层,也可以用多尺度训练策略,让模型每个epoch看到的目标尺寸不一样,提升对尺度变化的鲁棒性。我建议结构改动和数据处理同步进行,只改结构不改数据很容易过拟合。

6.3 几个容易被忽视的坑

有三件事我特别想提醒。第一是图像色彩空间问题,垃圾分类严重依赖颜色特征,家用摄像头和手机拍摄的图片色彩风格差异很大,直接混在一起训练会互相打架。比较好的做法是给训练数据做一次色彩归一化,或者进行充分的HSV增强。

第二是背景置换的问题。真实垃圾桶附近往往有路面、落叶、墙面,模型容易学到把褐色背景和“易拉罐”联系在一起。我自己的解决方式是加入随机背景替换的数据增强,从训练集中裁出目标贴到纯色背景上,强行打掉模型对背景的依赖。

第三是混淆矩阵除了对角线,其他格子里数值不是零时,不要笼统说“增加数据”,先看具体是哪两个类别在互相混淆。瓶子和罐子经常混,但使用的材质完全不同,这时数据再多都不如给分类分支加个细粒度特征提取来得有效。

我在这里把容易遇到的几个问题整理成速查表,训练时直接对照排查:

现象可能原因排查与解决
val loss反弹过拟合加大数据增强、调小模型、Early Stopping生效
训练loss居高不下学习率不合适或数据标签错乱调低lr0,检查data.yaml类别顺序
小目标AP极低小目标样本太少或没有P2层扩充小目标样本,开启P2检测层
两类目标互相混淆特征相似看混淆矩阵定位类别对,针对性加样本/加权
现场效果好差训练集和测试集同源按场景分组划分数据,别随机划分
模型在RK3588卡顿未量化或模型过大导出INT8,TensorRT推理,蒸馏换小模型

最后聊点实在的

这套基于YOLOv8改进的垃圾分类识别系统,从数据准备到最终部署,我前前后后跑了大概两个月。最大的体会是:目标检测项目里,模型结构改动带来的精度提升往往不如数据清洗和增强来得明显可靠。把标注质量管好、把数据分布理清,再回头做网络层面的改进,每一步提升都看得见摸得着。

如果你也要做类似的项目,我建议第一步先去实地拍几百张真实垃圾桶照片,用手里的基线模型跑到上面看效果,再决定改哪里。比起坐在电脑前研究论文结构,这种“从场景出发”的思路能少走很多弯路。做垃圾分类识别本身不深奥,但它要求你同时具备数据处理能力、模型理解能力和系统集成能力,这三样都扎实了,项目自然能交出让人满意的结果。

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

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

立即咨询