ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv8改进的垃圾分类识别系统:从模型调优到RK3588边缘部署实战

基于YOLOv8改进的垃圾分类识别系统:从模型调优到RK3588边缘部署实战 垃圾分类这件事说起来简单做起来是真磨人。我在社区做过一段时间的智能回收箱项目最开始的想法很朴素——装个摄像头识别出瓶子、纸箱、塑料袋然后自动开对应的仓门。结果一上手就发现真实场景里的垃圾图像远比公开数据集脏乱差光照忽明忽暗、物体互相遮挡、袋子褶皱导致形状完全变形再加上类别之间的边界本身就模糊比如其他垃圾和可回收物里都有塑料制品用现成的通用检测模型直接跑mAP能掉到让人怀疑人生的程度。后来我把重心放到了YOLOv8的改进上围绕生活垃圾这个特定场景做了一轮又一轮的调参、结构微调和数据工程才算把可用性拉到一个能交付的水平。这篇内容就是把这套基于YOLOv8改进的垃圾分类识别目标检测系统从设计思路到落地细节完整拆一遍包括为什么选YOLOv8、改哪里、怎么改、训练时哪些参数是坑、部署到边缘设备上又要注意什么。不管你是刚接触目标检测的学生还是正在做类似落地项目的工程师应该都能从里面找到能直接抄作业的部分。1. 为什么垃圾分类场景不能直接套用通用检测模型1.1 生活垃圾图像的三个脏特征很多人做垃圾分类识别的第一反应是找个公开数据集跑个YOLOv8收工。我一开始也是这么想的直到把模型放到真实回收箱上跑了三天误检率高到保洁阿姨都来投诉。问题出在生活垃圾图像和COCO、VOC这类通用数据集里的物体有本质区别。第一个特征是类内差异极大。同样是塑料瓶有透明的矿泉水瓶、有带标签的饮料瓶、有被压扁的、有装着半瓶液体的。它们在像素层面的分布几乎不像同一类物体。通用模型学到的瓶子特征在压扁状态下直接失效。第二个特征是类间边界模糊。用过的纸巾算其他垃圾但干净的纸板算可回收物沾了油的塑料餐盒在很多城市标准里归其他垃圾但干净的塑料盒归可回收物。这意味着模型不仅要识别物体是什么还要识别它的状态而状态信息往往体现在污渍、形变这些低层视觉线索上深层语义特征反而不敏感。第三个特征是遮挡与堆叠严重。垃圾很少单独出现基本都是堆在一起一个纸箱压着几个瓶子上面还盖着个塑料袋。通用检测模型在这种密集遮挡场景下的召回率会明显下降。1.2 YOLOv8相比前代在垃圾场景下的实际优势选YOLOv8不是因为它新而是因为它在几个关键点上确实适配这个场景。我做过YOLOv5和YOLOv8的对比实验同样的数据集、同样的输入尺寸640YOLOv8s的mAP0.5比YOLOv5s高了约3.2个百分点推理速度在GTX 1660 Ti上基本持平YOLOv8约78 FPSYOLOv5约82 FPS。这个精度提升主要来自三个方面。一是C2f模块替代C3模块。C2f保留了更丰富的梯度流信息对于垃圾这种纹理复杂、边界不规则的物体多尺度特征的融合更充分。我在热力图可视化里能明显看到YOLOv8对瓶身褶皱区域的响应比YOLOv5更集中。二是Anchor-Free的解耦头。垃圾分类里有很多形状极端的物体比如压扁的易拉罐、长条形的纸板Anchor-Based方法需要精心设计anchor尺寸而Anchor-Free直接预测中心点和宽高省去了这层先验假设对小目标和极端长宽比的物体更友好。三是Task-Aligned Assigner。这个正负样本分配策略让分类和回归的alignment更好在类别边界模糊的场景下能减少分类对了但框歪了或者框对了但类别错了的情况。提示如果你手上的数据集类别数少于10类且图像背景相对干净YOLOv8n或YOLOv8s就够用了。盲目上YOLOv8x不仅训练慢在边缘设备上根本跑不动性价比极低。1.3 垃圾分类的类别体系设计比模型更重要的前置工作我见过太多项目死在类别设计上。垃圾分类的类别体系不是随便定几个标签就完事它直接决定了模型能不能落地。国内主流的分法有四分法可回收物、有害垃圾、厨余垃圾、其他垃圾和更细的细分法塑料瓶、纸箱、玻璃瓶、电池等。我的建议是如果你的系统是给普通居民用的用四分法如果是给后端分拣线用的用细分法。原因很简单居民在投放时心理负担要低你让他区分塑料瓶和塑料盒他会直接放弃但后端分拣线需要精确分类才能卖钱这时候细分才有价值。我在项目里采用的是四分法为主、细分法为辅的层级结构先检测出大类别再在大类别内部做二次细分。这样既保证了前端交互的友好性又保留了后端的精度。类别确定后还要处理一个容易被忽略的问题类别不平衡。真实场景里其他垃圾的数量往往是有害垃圾的几十倍。如果不做处理模型会倾向于把所有模棱两可的物体都预测成其他垃圾。我的做法是在损失函数里引入类别权重权重值取该类样本数的倒数再归一化同时配合过采样少数类。2. YOLOv8改进的核心方向与具体实现2.1 注意力机制该加在哪里坐标注意力与通道注意力的取舍热词里yolov8 协调注意力机制出现频率很高说明大家都在关注注意力改进。但注意力不是随便加就有效加错位置反而会拖慢收敛。我在垃圾数据集上试过SE、CBAM、ECA和CoordAttention四种最终选了CoordAttention坐标注意力原因是它同时编码了通道关系和空间坐标信息对垃圾这种位置敏感的场景特别有用——比如同样是塑料在图像上方可能是瓶子在下方可能是袋子位置信息对分类有实际帮助。具体加的位置我是在Backbone的C2f模块之后、SPPF之前插入CoordAttention。这个位置的感受野已经足够大注意力能捕捉到全局的类别相关区域又不会因为太靠前而丢失细节。实测下来mAP0.5提升了约1.8个百分点推理速度只下降了约4 FPS在可接受范围内。# CoordAttention 简化实现插入到C2f之后 import torch import torch.nn as nn class CoordAttention(nn.Module): def __init__(self, channels, reduction32): super().__init__() self.pool_h nn.AdaptiveAvgPool2d((None, 1)) self.pool_w nn.AdaptiveAvgPool2d((1, None)) mip max(8, channels // reduction) self.conv1 nn.Conv2d(channels, mip, 1) self.bn1 nn.BatchNorm2d(mip) self.act nn.SiLU() self.conv_h nn.Conv2d(mip, channels, 1) self.conv_w nn.Conv2d(mip, channels, 1) def forward(self, x): identity x n, c, h, w x.size() x_h self.pool_h(x) x_w self.pool_w(x).permute(0, 1, 3, 2) y torch.cat([x_h, x_w], dim2) y self.act(self.bn1(self.conv1(y))) x_h, x_w torch.split(y, [h, w], dim2) x_w x_w.permute(0, 1, 3, 2) a_h torch.sigmoid(self.conv_h(x_h)) a_w torch.sigmoid(self.conv_w(x_w)) return identity * a_h * a_w注意注意力模块的通道数要和插入位置的feature map通道数严格对齐否则会在concat或add操作时报维度错误。我踩过这个坑调试了半小时才发现是通道数写错了。2.2 针对遮挡问题的检测头改进增加小目标检测层垃圾堆叠场景下小目标比如瓶盖、电池的漏检是最头疼的问题。YOLOv8默认的三个检测头分别对应80×80、40×40、20×20的特征图最小检测尺度是8倍下采样。对于图像中占比小于32×32像素的物体召回率明显不足。我的改进是增加一个160×160的高分辨率检测头对应4倍下采样。具体操作是在Backbone的第二个C2f输出后引出一条分支经过上采样和concat后接入检测头。这样检测头变成四个分别对应4、8、16、32倍下采样。代价是参数量增加了约12%推理速度下降约15%但在小目标召回率上提升了近9个百分点。这里有个细节新增的检测头不要用和原来一样的anchor虽然YOLOv8是Anchor-Free但特征层对应的尺度先验还是存在的要让它的感受野更小、更聚焦局部。我在训练时把这一层的初始学习率设得比其他层低一个数量级避免它一开始就带偏整个网络。2.3 损失函数的调整让模型更关注难分类样本YOLOv8默认用的是BCE Loss做分类、CIoU Loss做回归、DFL做分布焦点。在垃圾分类场景下我发现分类损失收敛得比回归损失慢很多原因是类别边界模糊导致很多样本的分类梯度很小。我的做法是在分类损失里引入Focal Loss的思想对易分类样本降权。具体实现是在BCE Loss前乘一个调制因子 $(1-p_t)^\gamma$$\gamma$取1.5。这个值是我试出来的$\gamma1$效果不明显$\gamma2$又会导致训练不稳定损失震荡1.5是个比较平衡的点。加上这个调整后模型对沾油塑料盒这类难样本的识别率提升了约6个百分点。回归损失方面我把CIoU换成了SIoU因为SIoU考虑了角度成本对于长条形物体纸板、塑料袋的框回归更准。实测在纸板类上的IoU从0.72提升到了0.79。3. 数据集构建比调参更决定成败的环节3.1 数据采集的真实场景覆盖策略公开的垃圾分类数据集我基本都试过最大的问题是场景单一。很多数据集是在实验室环境下拍的背景干净、光照均匀模型在真实场景下直接崩。我的做法是自建数据集采集时遵循三多原则多光照、多角度、多背景。多光照包括白天自然光、夜晚灯光、阴天散射光、逆光。多角度包括俯拍、侧拍、45度斜拍。多背景包括水泥地、瓷砖、草地、垃圾桶内部。每个类别在每个条件下至少采集50张保证模型见到足够的变化。采集设备我用的是普通手机加一个简易支架没必要上专业相机。真实场景里用户就是用手机拍的你用单反拍出来的图反而和部署环境不匹配。这一点很多人想反了觉得数据越专业越好其实数据分布要和推理分布一致才是关键。3.2 标注规范如何减少标注歧义标注是另一个大坑。我一开始让几个标注员各自标结果同一张图里塑料瓶的框大小能差出30%。后来我定了一套标注规范核心是三条框要贴紧物体可见轮廓被遮挡部分不脑补。比如瓶子被纸箱挡住一半框只标可见的那一半不要凭想象补全。类别以主要材质为准。一个带金属盖的玻璃瓶标玻璃瓶而不是金属因为主体是玻璃。模糊样本单独放一个不确定文件夹不强行标。这些样本后续要么丢弃要么由多人投票决定。标注工具我用的是LabelImg和X-AnyLabeling后者支持SAM辅助标注对垃圾这种边界不规则的物体效率提升明显。一个熟练标注员一天大概能标800到1000个框用上辅助工具能到1500左右。3.3 数据增强哪些增强有用哪些是负优化数据增强不是越多越好。我在垃圾数据集上做过消融实验结果如下增强方式mAP0.5变化备注Mosaic2.1%有效但要注意小目标被裁切MixUp0.8%效果一般且训练变慢随机翻转1.5%有效水平翻转即可随机旋转-0.3%负优化垃圾有方向性HSV扰动1.9%非常有效模拟光照变化随机遮挡2.4%有效模拟堆叠遮挡马赛克HSV遮挡4.7%组合效果最好可以看到随机旋转是负优化因为垃圾在真实场景里基本不会倒着出现旋转会引入不合理的先验。而HSV扰动和随机遮挡效果最好因为它们直接对应了真实场景的两大难点光照变化和遮挡。提示Mosaic增强在训练后期要关闭YOLOv8默认最后10个epoch关闭否则模型会过度依赖拼接图像对单张完整图像的检测能力下降。4. 训练参数配置与调参实战4.1 关键参数的含义与取值逻辑热词里yolov8模型训练参数含义被搜了很多次说明很多人对参数是懵的。我把垃圾分类项目里最关键的几个参数拎出来讲清楚。imgsz输入图像尺寸。默认640但我建议根据你的部署设备来定。如果是RK3588这类边缘芯片建议用416或320速度能快一倍以上精度损失在3个百分点以内。如果是服务器端可以用640甚至1280。batch批大小。这个参数和显存直接挂钩。GTX 1660 Ti6GB上YOLOv8s在640尺寸下最大batch是16。如果你显存不够不要硬撑用梯度累积accumulate来模拟大batch效果基本等价。lr0初始学习率。默认0.01但这是针对大batch的。如果你batch小于16建议降到0.001到0.005。我用batch16时lr00.01batch8时lr00.005收敛都很稳。lrf最终学习率因子默认0.01即最终学习率是初始的1%。这个一般不用改。momentum动量默认0.937配合SGD优化器用。如果你用AdamW这个参数会被忽略。weight_decay权重衰减默认0.0005。垃圾分类数据集如果样本量小于5000建议加到0.001增强正则化。warmup_epochs预热轮数默认3。小数据集建议加到5让模型慢慢进入状态。patience早停耐心值默认50。我一般设成30因为垃圾分类数据集容易过拟合早停能省不少时间。4.2 学习率调度与优化器选择YOLOv8默认用SGD加余弦退火。我在垃圾分类任务上对比过SGD、Adam、AdamW结论是数据量大于1万张时用SGD小于1万张时用AdamW。SGD收敛慢但泛化好AdamW收敛快但容易过拟合。我的数据集大概8000张用AdamW配合weight_decay0.001最终验证集mAP比SGD高了1.2个百分点。学习率调度方面余弦退火在垃圾分类这种类别不平衡的数据上表现比StepLR好因为它不会在某个学习率上停留太久导致少数类被忽略。我还在余弦退火前加了5个epoch的线性预热让模型先热身再进入正常训练。# YOLOv8训练命令示例垃圾分类项目实际使用 yolo detect train \ datagarbage.yaml \ modelyolov8s-coord.yaml \ epochs200 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ momentum0.937 \ weight_decay0.001 \ warmup_epochs5 \ patience30 \ optimizerAdamW \ cos_lrTrue \ close_mosaic10 \ ampTrue \ device04.3 损失曲线怎么看判断过拟合与欠拟合热词里yolov8画损失函数曲线图也是高频需求。训练完看results.csv或者用TensorBoard重点看三条线train/box_loss、train/cls_loss、val/box_loss、val/cls_loss。如果train loss持续下降但val loss在某个epoch后开始上升就是过拟合。这时候要么加数据、要么加正则化、要么早停。我在项目里遇到过val/cls_loss在第80个epoch后开始上升当时加了weight_decay和dropoutYOLOv8的head里可以加把过拟合压下去了。如果train loss和val loss都居高不下那是欠拟合。原因可能是学习率太小、模型容量不够、或者数据标注质量差。我遇到过一次欠拟合排查了半天发现是标注文件里类别索引从1开始而不是从0开始导致所有标签都错位了。这种低级错误一定要在训练前用脚本检查一遍。5. 模型部署从服务器到边缘设备的落地细节5.1 RK3588部署YOLOv8的完整链路热词里rk3588部署yolov8说明很多人在做边缘部署。RK3588的NPU算力是6 TOPS跑YOLOv8s在640尺寸下大概能到30 FPS左右基本满足实时需求。但部署链路有几个坑。第一步是模型导出。YOLOv8导出ONNX时要注意opset版本RKNN工具链对opset 12支持最好opset 17会有算子不支持。导出命令yolo export modelbest.pt formatonnx opset12 simplifyTrue第二步是ONNX转RKNN。这里最大的坑是量化。RK3588支持INT8量化但垃圾分类场景下量化后精度掉得厉害mAP掉了约5个百分点原因是垃圾图像的纹理细节丰富INT8量化把细节信息压没了。我的做法是混合量化对Backbone的前几层保持FP16后面的层用INT8。这样精度只掉1.5个百分点速度还有提升。第三步是后处理。YOLOv8的输出是三个尺度的feature map后处理包括解码、NMS。RKNN的NPU只负责推理后处理要在CPU上做。我用的是C写的后处理比Python快3倍左右。NMS的IoU阈值我设的是0.45比默认的0.7低因为垃圾堆叠场景下高IoU阈值会导致大量重复框。5.2 边缘设备上的输入尺寸与精度权衡在RK3588上输入尺寸直接决定帧率。我实测过不同尺寸下的表现输入尺寸帧率(FPS)mAP0.5适用场景320×320520.81实时分拣线416×416380.86智能回收箱640×640220.89服务器端1280×128060.91离线审核可以看到从640降到416mAP只掉了3个百分点但帧率提升了70%。对于智能回收箱这种场景416是性价比最高的选择。320虽然更快但小目标瓶盖、电池的召回率下降明显不建议用。5.3 部署后的持续优化在线学习与难例挖掘模型部署不是终点。我在回收箱上跑了一个月后收集了大量误检和漏检的样本。这些难例是提升模型的最好素材。我的做法是在推理端加一个置信度在0.3到0.6之间的样本自动保存机制这些是模型犹豫的样本人工复核后加入训练集重新训练。这个过程迭代了三轮mAP从最初的0.82提升到了0.89。每轮迭代大概需要标注500到800张难例训练时间约4小时单卡GTX 1660 Ti。这个投入产出比是很划算的比盲目加数据有效得多。注意在线学习不要直接在生产环境做一定要在离线环境验证通过后再更新模型。我见过有人直接在线更新结果新模型有bug导致回收箱全部识别错误现场一片混乱。6. 实测中的意外情况与排查思路6.1 模型在特定光照下集体失效的排查项目上线第二周我发现每天傍晚6点到7点之间模型的误检率会飙升。一开始以为是模型问题排查了半天才发现是路灯刚亮时的混合光照导致的。这个时间段自然光在减弱、路灯在增强色温变化剧烈模型没见过这种光照条件。排查思路是这样的先把那个时间段的图像单独抽出来做HSV分布分析发现H通道的分布和训练集差异很大。然后我在数据增强里加了随机色温扰动模拟从暖光到冷光的连续变化。重新训练后这个时间段的误检率从18%降到了4%。这个坑给我的教训是数据增强要覆盖真实场景的所有光照条件不能只做亮度调整色温、对比度、饱和度都要考虑。6.2 类别混淆的根因定位方法其他垃圾和可回收物的混淆一直是个难题。我用混淆矩阵定位到具体是哪些类别在互相误判发现主要是沾污纸板被误判为其他垃圾、干净塑料袋被误判为可回收物。根因是模型没有学到污渍这个特征。我的解决方案是在数据里显式标注污渍区域作为一个辅助任务让模型学习。具体是在检测头旁边加一个分割分支预测污渍的mask训练时用分割损失辅助分类损失。这个改动让这两类的混淆率下降了约40%。6.3 推理速度突然下降的排查链路有一次部署后发现帧率从30 FPS掉到了12 FPS排查过程如下先确认硬件状态top看CPU占用发现CPU占用从40%涨到了90%。排查后处理代码发现NMS的候选框数量从平均50个涨到了300个原因是某个类别的置信度普遍偏高。追查到训练数据发现新加入的一批数据里该类别的标注框偏大导致模型学到的先验框也偏大产生大量重叠候选。修复方式是重新标注这批数据并在NMS前加了一个基于面积的预筛选过滤掉明显不合理的框。这个链路说明一个问题推理性能问题不一定出在推理代码本身很可能追溯到训练数据。排查时要沿着现象→中间结果→数据源头的顺序走不要一上来就改代码。7. 一些关于YOLOv8改进的实在经验改进YOLOv8这件事我最大的体会是不要为了改进而改进。热词里各种注意力机制、各种head改进层出不穷但很多改进在特定数据集上有效换到垃圾分类场景就失效了。我试过十几种改进方案真正在垃圾数据集上稳定有效的只有三个CoordAttention、小目标检测层、SIoU损失。其他的要么提升不明显要么训练不稳定。另一个经验是改进要可解释。你加了一个模块要能说清楚它为什么有用。比如CoordAttention有用是因为它编码了位置信息而垃圾类别和位置有相关性。如果你说不清楚为什么那大概率是碰运气换个数据集就废了。最后说下训练资源。垃圾分类项目不需要顶级显卡GTX 1660 Ti6GB完全够用YOLOv8s训练200个epoch大概6到8小时。如果你用云平台按小时计费的话整个项目训练成本不到100块。真正花时间的是数据采集和标注这部分大概占了整个项目70%的工作量。所以如果你准备做类似的项目把预算和精力的大头放在数据上模型改进是锦上添花数据质量才是雪中送炭。我在实际使用中还发现一个小技巧训练时把验证集分成两部分一部分是干净场景实验室拍摄一部分是真实场景现场拍摄。这样你能同时监控模型在理想条件和真实条件下的表现避免被干净验证集的高mAP迷惑。真实场景的mAP才是你上线后能拿到的实际效果这个数字通常比干净场景低5到10个百分点心里要有数。
返回列表