
1. 项目缘起与整体设计思路垃圾分类这件事说起来简单做起来是真磨人。我在社区做过一段时间的分类督导志愿者亲眼见过督导员扯着嗓子喊“纸巾是干垃圾、电池是有害垃圾”结果居民该扔错还是扔错。人工督导成本高、效率低而且没法全天候覆盖。后来我就琢磨能不能用视觉识别的方式让摄像头自动判断垃圾类别把结果实时显示在屏幕上甚至联动分拣装置。这就是我做这个项目的出发点——基于YOLOv8改进算法的生活垃圾图像识别系统。这个系统的核心任务很明确输入一张生活垃圾图片或者一段实时视频流输出图中每个垃圾目标的类别标签和边界框位置。类别通常按四分类标准来可回收物、有害垃圾、厨余垃圾、其他垃圾。听起来像是一个标准的目标检测任务但生活垃圾这个场景有它的特殊性——目标形态极度不规则、类间差异小比如用过的纸巾和干净的纸盒一个属于其他垃圾一个属于可回收物、遮挡严重、光照条件复杂。直接用通用检测模型效果并不理想所以我在YOLOv8的基础上做了一些针对性改进。适合谁来参考这篇内容如果你已经跑通过YOLOv8的官方demo想把它落地到一个具体场景里那这篇东西对你会有帮助。如果你是完全零基础建议先把YOLOv8的环境配置和基础训练流程过一遍再回来看改进部分不然容易卡在细节里。我会尽量把每个设计决策背后的“为什么”讲清楚包括我踩过的坑和试错过程让你少走弯路。整个项目的技术路线可以概括为数据采集与标注 → 基线模型训练 → 针对垃圾场景的改进 → 模型评估与调优 → 部署推理。下面我按这个顺序把每个环节的关键细节拆开来讲。2. 数据集构建与预处理的关键细节2.1 垃圾数据集的采集策略与类别定义数据集是目标检测的地基地基没打好后面模型改出花来也没用。我一开始想偷懒直接用公开数据集但找了一圈发现现成的垃圾检测数据集要么类别定义和国内四分类标准对不上要么场景太干净——都是白底摆拍图跟实际垃圾桶里的情况差太远。所以最后决定自己采集。采集渠道有三个一是用手机在社区垃圾桶旁边拍不同时间段、不同天气都拍一些二是从公开数据集中筛选可用图片重新按四分类标准标注三是用数据增强的方式扩充少数类。这里有个经验有害垃圾的样本极度稀缺因为日常生活中电池、药品、灯管这些东西出现频率低如果不刻意补充模型对有害垃圾的识别率会惨不忍睹。我的做法是单独去搜集这类物品的图片甚至买了一些实物回来摆拍。类别定义上我最终确定了四个一级类别但在标注时细化了二十多个二级标签训练时再映射回一级类别。这样做的好处是标注阶段可以保留更细的语义信息后续如果想做更精细的分类不用重新标注。比如“塑料瓶”和“易拉罐”都映射到可回收物但标注时分开标模型学到的特征更具体。2.2 标注规范与质量控制标注工具我用的是LabelImg后来换成了Labelme因为Labelme支持多边形标注对不规则形状的垃圾更友好。但这里有个取舍多边形标注精度高但标注成本也高而且转成YOLO格式的矩形框时会损失信息。我的折中方案是对形状规则的垃圾瓶子、盒子用矩形框对形状极不规则的比如揉成一团的塑料袋用多边形导出时统一转成外接矩形。标注质量控制这块我吃了不少亏。一开始找了两个人标结果发现同一张图一个人标了“纸巾”作为其他垃圾另一个人标了“纸盒”作为可回收物。标注不一致是目标检测里最隐蔽的杀手模型会学得稀里糊涂。后来我定了一份标注手册把每个类别的判定标准写清楚比如“被油污污染的纸盒归为其他垃圾干净的归为可回收物”并且每标完一批就抽检10%发现不一致就返工。还有一个细节边界框的松紧度要统一。有的人标框喜欢贴紧目标边缘有的人喜欢留一点余量。这个不一致会导致模型学到的边界回归目标不稳定。我的要求是框的边缘距离目标轮廓大约2到3个像素所有标注人员统一标准。2.3 数据增强与类别平衡处理垃圾数据集的类别不平衡问题非常突出。可回收物和其他垃圾的样本量可能是有害垃圾的十几倍。直接训练的话模型会倾向于把大多数目标预测成多数类。我用了三种手段来缓解第一种是在线数据增强在训练时实时做随机翻转、旋转、色彩抖动、马赛克增强。YOLOv8内置了这些增强策略我重点调了mosaic和mixup的概率。马赛克增强对小目标检测特别有效因为它把四张图拼成一张变相增加了小目标的出现频率。第二种是离线过采样对有害垃圾和厨余垃圾的图片进行复制并施加不同的增强变换让每个类别的样本量大致均衡。但要注意过采样不能简单复制否则容易过拟合。我的做法是对少数类图片做更强的增强比如随机裁剪、添加噪声、调整亮度对比度。第三种是Focal Loss的引入这个在后面改进部分会详细讲。简单说就是让模型在训练时更关注难分类的样本而不是被大量易分类的多数类样本主导。类别原始样本数增强后样本数占比可回收物3200480030%有害垃圾680420026%厨余垃圾2100450028%其他垃圾3800460029%注意数据增强不是越多越好。我试过把增强倍数拉到很高结果验证集损失震荡严重模型学到的更多是增强后的伪特征而不是真实特征。建议增强后的总样本量控制在原始样本量的1.5到2倍之间。3. YOLOv8基线模型训练与参数调优3.1 环境配置与训练参数含义解析环境配置这块我用的是一台带RTX 3060的台式机CUDA 11.8PyTorch 2.0。YOLOv8的安装很直接pip install ultralytics就搞定了。但有个坑要注意ultralytics库更新很频繁不同版本的默认参数和API可能有差异。我建议锁定一个稳定版本比如8.0.x系列不要盲目追新。训练参数是很多人容易迷糊的地方我挑几个关键的说清楚imgsz输入图像尺寸。YOLOv8默认640我试过用1280小目标检测效果确实有提升但显存占用翻倍训练速度慢了一倍多。最后折中用了800在精度和速度之间取了个平衡。batch批次大小。这个要根据显存来调。RTX 3060 12G显存imgsz800时batch8比较稳再大就容易OOM。epochs训练轮数。我设了300轮但实际在220轮左右就收敛了。YOLOv8有早停机制patience50验证集损失50轮不下降就自动停。lr0初始学习率。默认0.01我调到了0.005因为垃圾数据集不算特别大学习率太大会导致损失震荡。lrf最终学习率因子。默认0.01意思是最终学习率是初始学习率的1%。我用余弦退火策略让学习率从0.005平滑降到0.00005。weight_decay权重衰减防止过拟合。默认0.0005我加到了0.001因为垃圾场景的过拟合风险比较高。还有一个参数叫close_mosaic意思是最后多少轮关闭马赛克增强。默认是10我设成了20。因为马赛克增强会让目标变得不自然最后阶段关掉它让模型在真实分布上微调一下对最终精度有好处。3.2 基线模型训练过程与损失曲线解读第一次训练我用的完全是默认参数结果mAP50只有0.72而且有害垃圾的召回率不到0.5。训练损失曲线倒是降得很漂亮但验证损失在第80轮之后开始抬头典型的过拟合。我当时的判断是模型容量够但数据不够而且类别不平衡导致模型对少数类不敏感。第二次训练我加了数据增强和类别平衡mAP50提到了0.79有害垃圾召回率到了0.68。但还是不够。看混淆矩阵发现厨余垃圾和其他垃圾之间的混淆特别严重比如剩饭剩菜和用过的纸巾模型经常搞混。这其实也合理因为这两类在视觉上确实有重叠——都是软塌塌的、颜色偏暗的团状物。第三次训练我做了两个改动一是把输入尺寸从640提到800二是引入了注意力机制后面会细讲。mAP50到了0.85厨余和其他垃圾的混淆率下降了大约15个百分点。损失曲线也健康多了验证损失和训练损失同步下降没有明显的过拟合迹象。实操心得看损失曲线不要只看总损失要分项看。YOLOv8的损失包括边界框损失、分类损失和DFL损失。如果分类损失降不下去说明类别区分度不够要考虑加注意力或者改损失函数如果边界框损失降不下去说明定位精度有问题可能要检查标注质量或者调整锚框。3.3 学习率调度与 warmup 策略学习率调度对训练稳定性影响很大。我试过固定学习率、阶梯下降和余弦退火三种。固定学习率最容易震荡阶梯下降还行但需要手动设里程碑余弦退火最省心效果也最好。YOLOv8默认用的就是余弦退火我只需要调好lr0和lrf就行。Warmup策略也值得说一下。YOLOv8默认有3轮warmup学习率从很小的值线性升到初始学习率。这个对防止训练初期梯度爆炸很有用尤其是当batch size比较大的时候。我试过关掉warmup结果前几轮损失直接飙到nan模型完全学不动。所以warmup不要关除非你有特别的理由。还有一个细节warmup_momentum和warmup_bias_lr这两个参数。前者控制warmup阶段的动量默认0.8后者控制warmup阶段的偏置学习率默认0.1。我一般不动这两个除非训练初期就出现严重的梯度问题。4. 针对垃圾场景的YOLOv8改进方案4.1 注意力机制引入与位置选择垃圾图像的特点是目标密集、遮挡严重、类间差异小。标准的卷积操作感受野有限很难捕捉全局上下文信息。比如一个塑料袋被其他垃圾压住了一半只看局部特征很难判断它是可回收物还是其他垃圾。注意力机制可以让模型关注更重要的区域抑制背景噪声。我试了三种注意力SE、CBAM和CoordAttention。SE最简单只做通道注意力提升有限。CBAM同时做通道和空间注意力效果好一些但参数量增加明显。CoordAttention是我最终选的因为它把位置信息嵌入到通道注意力里对目标定位特别有帮助。垃圾检测里位置信息很重要——比如电池通常比较小、形状规则而厨余垃圾通常是大块的、不规则的。注意力模块加在哪里也有讲究。我试过加在Backbone的每个C2f模块后面结果参数量暴涨推理速度掉了一半。后来改成只加在Backbone的最后两个阶段和Neck的上采样路径上精度提升差不多但速度只掉了15%左右。这个取舍很关键因为实际部署时推理速度是硬指标。4.2 损失函数改进与难样本挖掘前面提到类别不平衡的问题Focal Loss是标准解法。YOLOv8默认的分类损失是BCE Loss我换成了Varifocal Loss。为什么不用Focal Loss因为Focal Loss对正负样本一视同仁地降权而Varifocal Loss对正样本的权重是根据IoU来定的——IoU高的正样本权重大IoU低的权重小。这在垃圾检测里特别有用因为有些标注框本身就不太准垃圾形状太不规则了Varifocal Loss能降低这些噪声标注的影响。边界框损失我用了CIoU LossYOLOv8默认也是CIoU但我调了其中的alpha和gamma参数。CIoU考虑了重叠面积、中心点距离和长宽比对垃圾这种形状多变的目标比较友好。我试过换成EIoU理论上更好但实际提升不明显而且训练不稳定最后又换回了CIoU。还有一个改进是难样本挖掘。我在训练后期最后50轮启用了在线难样本挖掘把分类损失最高的那部分样本的权重提高。这个做法有风险因为如果难样本本身就是标注错误的会放大错误。所以我在启用之前先人工检查了一遍高损失样本把明显标错的清理掉了。4.3 网络结构微调与轻量化考量YOLOv8本身有n、s、m、l、x五个尺度。我一开始用的是YOLOv8m精度不错但推理速度在边缘设备上跑不动。后来换成了YOLOv8s精度掉了大约3个百分点但速度提升了一倍多。最终部署在RK3588上YOLOv8s的推理帧率能到25FPS左右基本满足实时性要求。网络结构上我还做了一个小改动把Neck部分的C2f模块换成了C3模块。C2f是YOLOv8的新设计特征融合更充分但计算量也更大。C3是YOLOv5的老设计更轻量。在垃圾检测这个任务上我实测发现C3和C2f的精度差异不到1个百分点但C3的推理速度快了大约20%。这个取舍在边缘部署场景下是值得的。还有一个细节是输入分辨率的动态调整。训练时用800推理时可以根据设备性能动态调整。RK3588上我用的是640精度损失在可接受范围内但帧率能稳定在30FPS以上。改进项mAP50推理速度RK3588参数量YOLOv8s基线0.7918 FPS11.2MCoordAttention0.8315 FPS12.8MVarifocal Loss0.8515 FPS12.8MC3替换C2f0.8419 FPS10.5M最终方案0.8525 FPS10.5M5. 模型评估、部署与常见问题排查5.1 评价指标解读与模型评估目标检测的评价指标比分类任务复杂得多。最常用的是mAP全称是mean Average Precision。简单说就是先算每个类别的AP平均精度再对所有类别取平均。AP本身是PR曲线下的面积综合了精确率和召回率。mAP50指的是IoU阈值为0.5时的mAPmAP50-95则是IoU从0.5到0.95每隔0.05取一个阈值算出来的平均值再平均。后者更严格也更能反映模型的定位精度。我的最终模型在测试集上的表现是mAP50为0.85mAP50-95为0.62。分类来看可回收物的AP最高达到0.91因为它的视觉特征最明显瓶子、罐子、纸盒形状规则。有害垃圾的AP最低只有0.76主要原因是样本太少而且电池、药品、灯管之间的差异很大模型很难用一个统一的特征来表示。厨余垃圾和其他垃圾的AP分别是0.82和0.80混淆主要发生在这两类之间。除了mAP我还看了混淆矩阵和PR曲线。混淆矩阵能直观地看出哪些类别容易搞混PR曲线能看出在不同召回率下的精确率表现。对于垃圾分类这种应用我其实更看重召回率——宁可把可回收物误判成其他垃圾也不要反过来因为误判成其他垃圾只是浪费了回收价值而误判成可回收物会污染整批回收物。5.2 RK3588部署实操与性能优化RK3588是瑞芯微的一款边缘计算芯片带NPU算力不错功耗也低很适合做垃圾分类的边缘部署。部署流程大致是PyTorch模型 → ONNX → RKNN。这里有几个坑要重点说。第一个坑是算子支持。RKNN的NPU不是所有ONNX算子都支持比如我用的CoordAttention里的某些操作RKNN就不认。解决办法是用RKNN Toolkit的模型转换工具它会列出不支持的算子然后我把这些算子替换成等效的支持算子。这个过程比较繁琐但没办法边缘部署就是这样。第二个坑是量化精度损失。RKNN支持INT8量化能大幅提升推理速度但精度会掉。我实测发现量化后mAP50从0.85掉到了0.81掉了4个百分点。为了弥补我用了混合量化——对精度敏感的层保持FP16其他层用INT8。这样mAP50只掉了1.5个百分点速度比全FP16快了将近一倍。第三个坑是输入预处理。RK3588的NPU对输入格式有要求比如NHWC和NCHW的区别。我一开始没注意直接传了NCHW的图结果推理结果完全不对。后来改成NHWC并且把归一化操作也放到NPU里做才正常。部署后的性能YOLOv8s在RK3588上输入640x640INT8量化推理帧率稳定在25到30FPS功耗大约5W。这个表现对于社区垃圾桶场景来说完全够用了。5.3 常见问题速查与避坑指南在做这个项目的过程中我遇到了不少问题这里整理成速查表方便你遇到类似情况时快速定位。问题现象可能原因排查方法解决方案训练损失震荡严重学习率太大或batch太小看损失曲线是否上下跳动降低lr0增大batch验证损失早早上扬过拟合对比训练和验证损失加数据增强加weight_decay某类别AP极低样本太少或标注质量差看混淆矩阵和该类样本过采样检查标注推理结果框位置偏移输入预处理不一致对比训练和推理的预处理统一归一化和通道顺序RKNN转换失败算子不支持看转换日志替换不支持的算子量化后精度掉太多INT8量化太激进对比量化前后mAP混合量化敏感层用FP16小目标检测效果差输入分辨率太低看小目标的AP提高imgsz加马赛克增强模型在边缘设备上跑不动模型太大看参数量和FLOPs换更小的模型剪枝避坑技巧训练前一定要做一次小规模过拟合测试。拿10张图训练100轮看模型能不能把损失降到接近0。如果降不下去说明模型结构或者数据管道有问题别急着上全量数据训练那样只是浪费时间。还有一个经验不要迷信SOTA。我试过一些最新的检测模型理论上指标更高但在垃圾数据集上表现并不比YOLOv8好多少而且部署更麻烦。YOLOv8的生态成熟、文档齐全、社区活跃遇到问题容易找到答案。对于实际项目来说可落地性比理论指标更重要。最后分享一个我在实际部署中总结的小技巧在摄像头端加一个简单的运动检测只有当画面有变化时才触发推理静止画面直接跳过。这样能大幅降低NPU的负载延长设备寿命。实测下来社区垃圾桶场景下这个策略能减少大约60%的无效推理。