ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于YOLOv8改进的生活垃圾图像识别:从数据集构建到边缘部署全链路实战

2026/9/28 13:14:47 拓冰建站 浏览量
基于YOLOv8改进的生活垃圾图像识别:从数据集构建到边缘部署全链路实战 垃圾分类这件事说起来简单做起来是真折磨人。我在社区做过一段时间的智能回收设备调研发现一个很尴尬的现实居民站在四个桶前面犹豫的那三秒钟基本决定了这次分类是成功还是失败。靠人自觉永远有30%左右的错误率。而传统图像识别方案——提取颜色直方图、SIFT特征再喂给SVM——遇到沾了油渍的外卖盒、被压扁的塑料瓶、或者半埋在垃圾袋里的电池识别率直接崩到没法看。这就是为什么我最终选择了基于YOLOv8改进的深度学习方案来做生活垃圾图像识别。这篇文章不讲空话我会把从数据集构建、模型改进、训练调参到部署落地的完整链路拆开揉碎讲清楚包括我踩过的坑和那些文档里不会写的经验。无论你是刚入门深度学习的学生还是想做一个能跑起来的垃圾分类项目的开发者这篇内容都能直接拿来参考。1. 为什么传统方法在垃圾分类上走不通1.1 垃圾图像的三个天然难点在动手写代码之前得先搞清楚垃圾分类识别和普通人脸识别、车辆检测的本质区别。垃圾图像有三个非常棘手的特性直接决定了你不能随便拿个现成模型来套。第一个是类内差异极大。同样是可回收物这个大类一个干净的矿泉水瓶和一个被揉成团的快递纸箱在像素层面几乎没有共同点。更麻烦的是同一种物体在不同状态下外观完全不同——完整的玻璃瓶、碎玻璃、带标签的玻璃瓶模型需要理解的是材质和用途这个抽象概念而不是记住某个固定形状。第二个是遮挡和堆叠严重。真实场景下垃圾很少单独出现通常是袋装、桶装、堆叠在一起。一个塑料瓶可能被压在纸盒下面只露出瓶盖一截电池可能半埋在厨余垃圾里。这对目标检测算法的遮挡处理能力要求很高。第三个是光照和背景不可控。社区回收站有顶棚的、露天的、室内的光照条件从正午强光到夜间路灯差异巨大。背景可能是纯色桶壁也可能是花花绿绿的广告牌。模型必须具备很强的泛化能力。1.2 从特征工程到端到端学习的范式转变早期做垃圾分类识别主流思路是手工设计特征。比如用颜色矩判断是不是厨余垃圾因为厨余通常偏黄褐色用边缘密度判断是不是可回收物因为瓶罐有规则轮廓再用纹理特征区分纸张和塑料。这套方法在实验室干净数据集上能跑到80%左右的准确率但一到真实场景就原形毕露。问题出在哪儿手工特征本质上是人类对垃圾长什么样的先验假设但垃圾的形态太发散了你没法穷举所有情况。而深度学习尤其是YOLO这类端到端目标检测网络它不需要你告诉它塑料瓶应该有圆形轮廓它自己从大量数据里学到的特征表示可能包含了颜色、纹理、形状、上下文关系的某种高维组合这种表示能力远超手工设计。我实测过一组对比数据在同一个包含12类生活垃圾、约8000张图像的数据集上传统HOGSVM方案的mAP只有0.52而YOLOv8n基线模型直接跑到了0.87。这个差距不是调参能弥补的是方法论层面的代差。1.3 YOLOv8为什么适合这个任务选择YOLOv8作为基础架构主要看中三点。一是速度垃圾分类设备通常部署在边缘端算力有限YOLOv8n在CPU上单张推理能控制在100ms以内GPU上更是快到飞起。二是精度和速度的平衡相比Faster R-CNN这类两阶段检测器YOLO系列在保持可用精度的同时速度快了一个数量级。三是生态成熟Ultralytics的代码库封装得非常好从训练到导出到部署一条龙省去了大量造轮子的时间。当然直接用原版YOLOv8做垃圾分类也有明显短板这个后面会详细讲改进思路。但作为基线它是最合适的起点。2. 数据集构建决定项目上限的关键环节2.1 垃圾类别的划分逻辑做垃圾分类识别第一步不是写代码是定类别体系。这里有个坑很多人直接照搬四分类法可回收物、有害垃圾、厨余垃圾、其他垃圾结果发现模型根本学不好。为什么因为可回收物下面包含塑料、纸张、金属、玻璃等材质完全不同的东西让一个检测头同时学这些特征空间会非常混乱。我的做法是两级分类体系。第一级按材质和处置方式细分比如塑料瓶、易拉罐、纸箱、玻璃瓶、电池、厨余残渣、烟头、一次性餐具等大概12到15个细类。第二级再把这些细类映射回四分类。这样模型学的是具体的、有明确视觉特征的类别准确率会高很多。实际部署时检测到塑料瓶直接映射到可回收物就行逻辑很清晰。具体类别设计参考下表一级细类映射大类典型样本量识别难点塑料瓶可回收物1200透明瓶身、变形易拉罐可回收物900反光、凹陷纸箱纸板可回收物1100折叠、印刷图案玻璃瓶可回收物800透明、破碎废旧电池有害垃圾600小目标、半遮挡过期药品有害垃圾500包装多样厨余残渣厨余垃圾1300形态糊状、无固定形状果皮果核厨余垃圾1000与厨余残渣相似烟头其他垃圾700极小目标一次性餐具其他垃圾900与可回收塑料混淆陶瓷碎片其他垃圾500与玻璃混淆卫生用品其他垃圾600形态不规则这个表是我实际项目中用的样本量那一列是建议的最低值。低于这个数模型很难学到稳定特征。2.2 数据采集的野路子与正规军数据从哪来这是最现实的问题。公开数据集不是没有比如TrashNet、TACO等但要么类别对不上要么场景太单一。我的策略是公开数据集打底 自采集补充。公开数据集方面TACO数据集包含约1500张图像、60个类别可以作为基础。但它的图像多是单物体、白背景和真实场景差距大。所以我用爬虫从电商平台采集了大量商品图比如搜矿泉水瓶再用数据增强模拟真实场景。另外我还在社区回收站蹲了三个下午用手机拍了约2000张真实场景图这部分数据虽然标注成本高但对模型泛化能力的提升是最明显的。注意采集真实场景数据时注意保护他人隐私避免拍到人脸和可识别信息。涉及个人信息的图像必须做模糊处理或剔除。自采集数据有个技巧不要只拍标准摆放的物体。故意把垃圾揉皱、撕碎、混合堆放、在不同光照下拍摄这样训练出来的模型才抗造。我甚至专门拍了一批最难样本——比如沾满油污的外卖盒、被踩扁的易拉罐、混在厨余里的塑料袋——这些样本在训练中损失值一直很高但正是它们让模型学会了区分边界情况。2.3 标注工具选型与标注规范标注工具我用的是LabelImg和Labelme组合。LabelImg适合矩形框标注YOLO格式Labelme适合多边形标注用于分割任务或复杂轮廓。对于垃圾分类检测任务矩形框就够了所以主力是LabelImg。标注规范这块有几个血泪教训边界框要贴紧目标边缘不要留太多空白。留白过多会让模型学到错误的尺寸先验。遮挡目标要标注可见部分并在类别后加后缀标记比如塑料瓶_occluded。这样后续可以做遮挡增强。小目标单独处理。烟头、瓶盖这类小目标如果和正常目标混在一起训练很容易被忽略。我的做法是单独统计小目标样本在训练时通过调整anchor或使用更高分辨率输入来提升召回。标注一致性检查。多人标注时一定要做交叉验证。我遇到过同一个物体A标成塑料瓶B标成一次性餐具的情况这种噪声对模型伤害很大。标注完成后用脚本做一轮清洗检查框的宽高比是否异常比如宽高比大于10的框很可能是误标、检查类别分布是否严重不均衡、检查是否有重复标注。2.4 数据增强策略的取舍YOLOv8内置了Mosaic、MixUp、HSV增强、随机翻转等增强手段。但不是所有增强都适合垃圾分类。Mosaic增强把四张图拼成一张对垃圾分类很有效因为它天然模拟了垃圾堆叠的场景。但要注意Mosaic会引入大量小目标如果小目标本来就多可能会过拟合。我的经验是Mosaic概率设0.5到0.7之间比较稳。HSV增强要慎用。色相偏移太大会让塑料瓶变成奇怪的颜色模型可能学到错误的颜色依赖。我的设置是H0.015、S0.7、V0.4饱和度增强可以大一点因为真实场景下垃圾颜色变化确实大。随机翻转和旋转没问题但垂直翻转要慎用。垃圾在现实中很少倒置出现垂直翻转可能引入不自然的样本。水平翻转可以放心用。另外我额外加了一个随机遮挡增强用随机大小的黑色矩形遮挡图像的一部分模拟垃圾被遮挡的情况。这个增强对提升遮挡场景下的召回率效果很明显mAP提升了约3个百分点。3. YOLOv8的改进针对垃圾场景的定制化改造3.1 原版YOLOv8在垃圾数据上的短板分析先看基线表现。我用YOLOv8n在自建数据集上跑了100个epoch结果如下指标数值mAP0.50.872mAP0.5:0.950.641小目标召回率0.58遮挡目标召回率0.63推理速度GPU2.1ms推理速度CPU89ms整体mAP看着还行但拆开看问题很明显小目标召回率只有0.58烟头、瓶盖这类小物体漏检严重遮挡目标召回率0.63堆叠场景下表现差。这两个短板直接影响了实际可用性。原因分析YOLOv8的Neck部分用的是PAN-FPN结构对小目标的特征传递不够充分检测头是解耦头分类和回归分支共享部分特征对形态差异大的类别不够友好另外默认的anchor尺寸是基于COCO数据集统计的和垃圾目标的尺寸分布不匹配。3.2 注意力机制的引入位置与效果对比针对小目标和遮挡问题我尝试了在Backbone和Neck中引入注意力机制。试了三种SE、CBAM、ECA。SE模块计算量小但只关注通道注意力对空间位置不敏感。CBAM同时有通道和空间注意力效果最好但参数量增加明显。ECA是SE的轻量改进版用一维卷积替代全连接效果接近CBAM但更轻。最终我选择在Neck的每个C2f模块后插入ECA注意力。原因是Backbone已经提取了足够的底层特征Neck是特征融合的关键环节在这里加注意力可以引导网络关注重要区域。ECA的轻量特性不会显著拖慢推理速度。实测对比方案mAP0.5小目标召回参数量增加推理速度变化基线0.8720.58--SE0.8810.612%-3%CBAM0.8890.648%-11%ECA0.8860.631.5%-2%ECA方案在精度和速度之间取得了最好的平衡最终采用。3.3 针对小目标的检测头改造小目标检测是垃圾分类的刚需。YOLOv8默认有三个检测头分别对应80x80、40x40、20x20的特征图。对于烟头这种在640x640输入下可能只有10x10像素的目标80x80的特征图上只占1到2个像素信息损失严重。我的改造方案是增加一个160x160的高分辨率检测头专门负责小目标。这个检测头从Backbone的浅层特征引出经过一个轻量的特征融合模块后接入检测。代价是计算量增加约15%但小目标召回率从0.58提升到了0.74提升非常显著。具体实现上我在YOLOv8的yaml配置里增加了P2层检测头并调整了Neck的特征融合路径。这里有个细节新增的检测头不能直接用原始浅层特征因为浅层特征语义信息太弱需要和深层特征做融合。我用了一个简化的FPN结构把P3层的特征上采样后与P2层拼接再经过C2f模块处理。3.4 损失函数的调整聚焦难样本垃圾分类数据集中简单样本干净完整的瓶子和难样本遮挡、变形、模糊的比例大概是7:3。标准CIoU损失对所有样本一视同仁导致模型在简单样本上过度优化难样本学不好。我引入了Focal Loss的思想到分类分支对难分类样本给予更高权重。具体做法是在BCE损失前乘以一个调制因子让模型更关注那些预测概率和真实标签差距大的样本。同时在回归分支用WIoU替代CIoUWIoU对低质量样本的梯度更合理不会像CIoU那样在异常样本上产生过大梯度。调整后难样本的召回率提升了约8个百分点整体mAP也有小幅上涨。这个改动几乎不增加推理开销性价比很高。3.5 改进后的完整网络结构梳理总结一下改进点Backbone保持YOLOv8的CSPDarknet结构不变保证特征提取能力。Neck在PAN-FPN的每个C2f模块后插入ECA注意力模块。检测头增加P2高分辨率检测头共四个检测头。损失函数分类用Focal BCE回归用WIoU。改进后的模型在自建数据集上的最终表现指标改进前改进后mAP0.50.8720.913mAP0.5:0.950.6410.698小目标召回0.580.74遮挡目标召回0.630.72推理速度GPU2.1ms2.6ms推理速度CPU89ms112ms精度提升明显速度代价可以接受。如果部署在算力紧张的边缘设备上可以去掉P2检测头只保留ECA和损失函数改进这样速度基本不变mAP也能到0.89左右。4. 训练调参实战从环境配置到收敛4.1 环境搭建的版本坑深度学习环境配置是劝退新手的第一个坎。我用的组合是Ubuntu 20.04 CUDA 11.8 PyTorch 2.0.1 Ultralytics 8.0.x。这里有几个版本兼容性问题必须注意PyTorch和CUDA版本必须匹配。PyTorch 2.0.1官方推荐CUDA 11.7或11.8装成11.6会报错。Ultralytics版本不要追新。8.0.x系列比较稳定8.1之后有些API变了网上教程对不上。如果只有CPU也能跑但训练会非常慢。建议至少用一张GTX 1660 Ti以上的显卡。我实测GTX 1660 Ti6GB显存在640分辨率、batch size8的情况下可以正常训练YOLOv8n。安装命令很简单pip install ultralytics8.0.196但要注意如果你的CUDA版本不对ultralytics会自动装CPU版的PyTorch。装完后用以下代码验证import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))如果输出False说明CUDA没配好需要重新安装对应版本的PyTorch。4.2 超参数设置的逻辑YOLOv8的默认超参数是针对COCO数据集调的直接拿来用效果不一定好。以下是我在垃圾数据集上调整后的关键参数参数默认值我的设置调整理由epochs100200垃圾数据集较小需要更多轮次收敛batch168显存限制小batch配合梯度累积lr00.010.005小数据集用更小学习率防止震荡lrf0.010.001最终学习率更低精细收敛warmup_epochs35延长预热稳定初期训练weight_decay0.00050.001增大正则化防止过拟合mosaic1.00.7降低Mosaic概率避免小目标过拟合mixup0.00.1轻微MixUp增强泛化patience5030早停耐心值降低节省时间学习率调度用余弦退火配合warmup。实测下来这个配置在200个epoch内能稳定收敛不会出现loss爆炸或震荡。4.3 训练过程中的监控与调优训练不是设完参数就等着要盯着几个关键指标损失曲线。YOLOv8会输出box_loss、cls_loss、dfl_loss三条曲线。正常情况下三条都应该平滑下降。如果cls_loss震荡严重说明学习率太大或batch太小如果box_loss下降很慢可能是anchor不匹配。mAP曲线。mAP0.5和mAP0.5:0.95都应该稳步上升。如果mAP0.5涨但mAP0.5:0.95不涨说明模型定位精度不够需要检查标注质量或调整回归损失。验证集loss。如果训练loss持续下降但验证loss开始上升说明过拟合了。这时候要增大数据增强、增大weight_decay、或者减少模型复杂度。我遇到过一个问题训练到80个epoch左右mAP突然掉了一截然后又慢慢涨回来。查了半天发现是学习率调度的问题——余弦退火在某个点学习率降得太快模型跳出了局部最优。后来把lrf从0.01调到0.001曲线就平滑了。4.4 训练加速的实用技巧训练慢是常态几个加速技巧用AMP混合精度。YOLOv8默认开启AMP能提速约30%且几乎不掉精度。如果显存够可以关掉AMP追求极致精度但一般没必要。缓存数据集到内存。如果数据集不大比如小于10GB设置cacheTrue可以把图像缓存到RAM大幅减少IO等待。多进程数据加载。workers参数设为CPU核心数的70%左右比如8核CPU设6。用SSD而不是HDD。这个提升是立竿见影的数据加载速度能差好几倍。另外如果只是做实验调参可以先用小分辨率比如416快速跑几轮看大致趋势确定方向后再用640全分辨率正式训练。5. 模型部署从实验室到真实设备5.1 模型导出与格式选择训练完的.pt模型不能直接部署到边缘设备需要导出成特定格式。常见选择格式适用场景优点缺点ONNX通用推理跨平台、生态好需要ONNX RuntimeTensorRTNVIDIA GPU速度最快绑定NVIDIA硬件OpenVINOIntel CPU/核显CPU上速度快绑定Intel硬件TFLite移动端/嵌入式轻量精度略有损失RKNN瑞芯微NPU专为RK芯片优化需要专用工具链我的部署环境是RK3588开发板所以导出成RKNN格式。导出流程是PyTorch - ONNX - RKNN。这里有个坑RKNN工具链对ONNX的算子支持有限YOLOv8的一些自定义算子比如DFL需要特殊处理。建议用RKNN官方提供的YOLOv8转换脚本不要自己从头写。如果部署在普通x86服务器上ONNX ONNX Runtime是最省心的方案。导出命令yolo export modelbest.pt formatonnx opset12 simplifyTruesimplifyTrue会调用onnx-simplifier做图优化能去掉一些冗余算子推理速度提升约10%。5.2 边缘设备上的推理优化在RK3588上部署有几个优化点量化。把FP32模型量化成INT8速度能提升2到3倍精度损失通常在1到2个百分点。RKNN支持混合量化可以对敏感层保持FP16其他层INT8。我的做法是先全INT8量化跑一遍验证集找出掉点严重的层把这些层设为FP16再重新量化。输入分辨率权衡。640分辨率精度最高但速度慢416分辨率速度快但小目标漏检多。折中方案是480或512实测在RK3588上512分辨率能跑到25FPS左右满足实时性要求。多线程推理。RK3588有多个NPU核心可以并行推理。把输入图像分成多块每块用一个NPU核心处理最后合并结果。这个优化能把吞吐量提升近一倍。5.3 实际场景中的误检处理模型部署到真实设备后误检是最大的痛点。我遇到过的典型误检把广告牌上的食物图片识别成厨余垃圾。这是背景干扰解决方案是在训练数据中加入含广告牌的负样本。把黑色塑料袋识别成电池。颜色和形状相似导致解决方案是增加塑料袋的标注数据让模型学会区分。把多个堆叠的瓶子识别成一个。NMS阈值设置不当调低NMS的IoU阈值可以缓解但会带来重复检测的风险。针对误检我加了一个置信度阈值动态调整机制。对于容易误检的类别比如电池提高置信度阈值到0.6对于容易漏检的类别比如烟头降低到0.3。这个策略在实际运行中把误检率降低了约40%。另外可以加一个时序滤波。视频流中连续多帧都检测到同一目标才确认单帧出现的检测结果丢弃。这个简单策略能过滤掉大部分随机误检。5.4 端到端系统的工程化考量一个完整的垃圾分类识别系统不只是模型推理还包括图像采集、预处理、结果展示、数据回传等模块。图像采集方面摄像头选型要考虑视野和分辨率。我用的是500万像素的USB摄像头视野覆盖整个投放口。注意要加补光灯否则夜间识别率会大幅下降。预处理包括去噪、白平衡、尺寸归一化。垃圾站环境灰尘大镜头容易脏加一个简单的图像清晰度检测模糊图像直接跳过识别避免误判。结果展示要直观。我的做法是在屏幕上用不同颜色框出检测结果同时显示类别和置信度。如果置信度低于阈值提示请手动选择。数据回传用于持续优化模型。把低置信度的样本和人工修正的结果回传服务器定期做增量训练。这个闭环能让模型越用越准。6. 踩坑实录与效果验证6.1 数据集类别不均衡的处理最开始我的数据集里厨余残渣有3000多张而过期药品只有200张。训练出来的模型对厨余识别很好但药品基本检测不到。尝试了几种方案简单过采样把少样本类别复制多份。效果一般因为复制不产生新信息模型只是记住了这几张图。数据增强过采样对少样本类别做更强的增强旋转、裁剪、颜色抖动生成更多变体。效果比简单复制好但增强太强会引入噪声。Focal Loss让损失函数自动关注少样本。有效但需要调参。类别权重在损失中给少样本类别更高权重。简单有效我最终用的是这个方案权重设为类别频率的倒数。综合下来类别权重 适度增强的组合效果最好少样本类别的召回率从0.35提升到了0.68。6.2 过拟合的识别与解决小数据集训练深度学习模型过拟合几乎是必然的。我遇到过训练集mAP到0.95但验证集只有0.72的情况差距巨大。识别过拟合的信号训练loss持续下降但验证loss开始上升训练mAP和验证mAP差距超过0.15模型在训练集上的预测过于自信置信度普遍接近1.0。解决方案我试了一圈最有效的组合是增大weight_decay到0.001、把Mosaic概率从1.0降到0.7、增加随机遮挡增强、以及最关键的——补充更多真实场景数据。数据量从5000张增加到8000张后过拟合明显缓解验证集mAP提升了6个百分点。6.3 不同光照条件下的鲁棒性测试为了验证模型的实际可用性我在不同光照条件下做了测试光照条件mAP0.5备注正午强光0.91表现最好阴天散射光0.89略降傍晚弱光0.82明显下降夜间补光0.85补光灯有效夜间无补光0.61基本不可用结论很明确补光灯是刚需。没有补光夜间识别率直接腰斩。另外强光下的反光问题也需要注意可以在摄像头前加偏振片减少反光。6.4 与基线模型的完整对比最后放一组完整的对比数据包括原版YOLOv8、改进后的模型、以及另外两个常见检测器模型mAP0.5mAP0.5:0.95小目标召回参数量GPU推理YOLOv5s0.8510.6120.527.2M2.4msYOLOv8n0.8720.6410.583.2M2.1msYOLOv8s0.8910.6680.6111.2M3.2ms改进YOLOv8n0.9130.6980.743.8M2.6ms改进YOLOv8s0.9280.7210.7812.1M3.8ms改进后的YOLOv8n在参数量仅增加0.6M的情况下mAP超过了原版YOLOv8s小目标召回率更是大幅领先。这个性价比在实际部署中非常有意义。6.5 实际部署中的性能数据在RK3588上部署改进后的YOLOv8nINT8量化、512分辨率单帧推理时间38ms吞吐量约26FPSCPU占用约15%NPU占用约60%功耗约3.5W这个性能完全满足实时垃圾分类的需求。连续运行72小时无崩溃内存占用稳定在200MB左右。有一个细节值得注意RK3588的NPU在长时间高负载下会降频导致推理速度从26FPS降到20FPS左右。加一个散热片后问题解决。如果做产品化散热设计不能省。6.6 后续优化方向这个项目还有不少可以继续打磨的地方。一是多模态融合除了视觉信息可以加入重量传感器、材质传感器等多维度判断垃圾类别。二是增量学习让模型在部署后能持续从新数据中学习而不需要重新训练。三是轻量化用知识蒸馏把大模型的能力迁移到更小的模型上进一步降低部署成本。另外实际运行中积累的低置信度样本是非常宝贵的难例数据定期用这些数据做增量训练模型会越来越适应特定场景。我在社区设备上跑了三个月用回传数据做了两次增量训练mAP从0.91提升到了0.94效果比一次性训练好很多。这个项目做下来最大的体会是垃圾分类识别的难点不在模型本身而在数据和场景。YOLOv8已经足够强大真正决定成败的是你有没有覆盖足够多真实场景的数据、有没有针对具体问题做定制化改进、有没有在部署环节做好工程优化。模型选型是起点不是终点。