ARTICLE DETAIL

资讯详情

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

生活垃圾图像识别实战:基于YOLOv8改进的目标检测系统

生活垃圾图像识别实战:基于YOLOv8改进的目标检测系统 最近在折腾一套生活垃圾图像识别项目核心是用深度学习目标检测技术把每张图片里的垃圾找出来、圈出来、认出来并且能实时跑起来。整个系统从数据整理、标注到基于YOLOv8改进算法的模型训练再到最后的检测系统原型走了一遍完整链路。这篇博客就是把这次实战的完整过程记录下来包括模型结构怎么改、数据集怎么做、超参数怎么定、踩了哪些坑希望能给正在做垃圾分类识别、目标检测改进方向的朋友一条可以复现的路线。先说结论如果你需要一个精度和速度都比较均衡的目标检测基线YOLOv8确实是最合适的起点但直接拿原版v8在生活垃圾这种复杂场景上跑小目标漏检和类别混淆会比较明显必须针对场景做改进。下面按项目从设计到落地的顺序逐个拆解。1. 项目定位与核心需求拆解项目最初的需求来源很实际社区垃圾投放点也好智能垃圾桶也好光靠人工监督分类效率太低。如果能在投放点装一个摄像头或者让用户拿手机拍一张照片模型自动输出画面中每个垃圾的类别和位置就能给后续分拣或者清理调度提供很大的便利。这个项目要解决的问题就是把深度学习图像识别能力落到生活垃圾目标检测这个具体场景。需求拆解下来有三层约束。第一层输入是普通的RGB图像可能来自摄像头单帧、手机照片也可能是视频流抽帧这要求模型对分辨率变化不敏感。第二层输出是目标的类别和边界框检测类别需要覆盖常见生活垃圾同时要能在画面里同时处理多个物体。第三层运行环境可能是边缘盒子或者普通工作站必须考虑推理速度和模型体积不能直接搬一个超大模型上去。这三层约束直接决定了模型选型和改进方向。目标检测算法里Two-Stage路线的Faster R-CNN精度高但速度太慢One-Stage路线里SSD部署成熟但特征表达能力一般YOLO系列是工程落地最舒服的选择。到YOLOv8这个版本结构已经比较现代化做改进也方便所以基线就定成它。1.1 垃圾分类识别到底难在哪很多人以为垃圾分类识别就是把物体认出来真做起来才发现这个场景处处是坑。第一个问题是物体形态极度不规则瓶瓶罐罐和纸盒好歹有规整轮廓但厨余垃圾里的剩菜、果皮往往是一滩混合体没有清晰边缘检测框很难定塑料袋和保鲜膜半透明特征弱摄像头一拍经常直接漏检。第二个问题是尺度差异。画面里可能同时出现一个大纸箱和一个烟头烟头这种小目标只占几十个像素加上YOLO下采样倍数大特征图上一不小心就丢了。第三个问题是环境干扰垃圾桶旁边的地面背景杂光照差的时候整张图噪点明显玻璃瓶和高光塑料还会产生反光区域模型很容易被反光骗到。这些难点意味着不能直接套用通用目标检测模型。通用模型能识别日常生活中的物体是因为大量公开数据集里的物体特征清晰、尺度相对均匀生活垃圾里一堆半透明塑料袋、反光的饮料瓶特征本身就不够干净所以必须通过在网络结构上加强特征提取在数据层面补充多样性两头一起解决。1.2 为什么选择YOLOv8作为基线YOLOv8是Ultralytics在2023年推出的版本相比YOLOv5做了一堆结构性调整主干网络里的C2f模块用split操作增加梯度流检测头换成Decoupled Head标签分配采用TaskAlignedAssigner策略Anchor-Free机制也让它对不同尺寸目标的适应更好。这些改变带来的直接好处就是训练更好收敛、检测头分工更清晰。对比一下几种常见选择Faster R-CNN精度不俗但在实时场景里要跑视频流帧率根本顶不住SSD虽然轻量但是对小目标一直是老大难YOLOv5是个成熟方案代码资料多但它的Anchor-Based机制和后期训练调参空间稍逊一筹。YOLOv8则在精度和速度的平衡上做得更好而且官方库的代码结构清晰很方便在特定模块上做改进实验所以这个项目把YOLOv8定为基础网络。选择它还有一层实际考虑改进算法的验证成本低。YOLOv8的配置文件是YAML格式改模型结构就是在yaml文件里调整模块组合不需要动底层模型代码这对快速尝试多种改进策略来说太划算了。后面我要做的注意力机制、小目标检测层、损失函数替换都能在这个框架里顺畅完成。2. YOLOv8改进方案的设计与实现改进算法的目标很明确在不大幅增加推理耗时的前提下提高生活垃圾场景的检测精度尤其是小目标和易混淆类别。围绕这个目标我在三个位置做了改进主干网络、特征融合、回归损失。下面分别说。2.1 主干特征提取在C2f里加注意力机制YOLOv8的backbone核心模块是C2f它的设计思路是把输入特征图分成两个分支一路经过若干Bottleneck提取深层语义另一路保留原始信息最后拼接在一起让梯度有更丰富的流动路径。这个结构不错但在垃圾场景里还不够大量低对比度的物体比如浅色塑料袋对着浅色水泥地模型需要非常强的特征表达才能区分边界。我的做法是在C2f模块中引入坐标注意力Coordinate Attention机制。和传统SENet只压缩通道维不同Coordinate Attention在通道注意力之外还编码了水平和垂直方向的位置信息这对空间定位特别有帮助。举个例子一张图片里左边的红色易拉罐和右边的白色纸盒坐标注意力会让模型在空间位置上更清晰地区分它们而不是仅仅靠颜色。改动的落点很明确。在ultralytics/nn/modules.py里注册一个带注意力分支的模块然后在模型配置yaml中把原始的C2f替换成新模块。注意不要动backbone的整体结构只替换C2f内部实现这样预训练权重可以复用大部分参数。注意修改模块后一定要先构造一次模型做forward检查很多错误是在维度上出现的C2f的分支数量一变后面的channel对齐就容易被忽略。2.2 小目标检测层增加P2分支与特征融合生活垃圾里除了大纸箱这种大目标还有烟头、电池、瓶盖这类小目标原版YOLOv8的检测层最小下采样倍数是8倍也就是图像尺寸缩小到1/8当小目标本身就小再缩几倍就基本没有有效特征了。解决办法是在特征金字塔里加一层更大分辨率的特征图参与检测这就是常见的P2层思路。具体操作是在yaml文件的detect部分增加一个来自网络更浅层的分支让下采样4倍的特征图直接参与小目标检测。这样做模型可以在一张640x640的输入图上检测大约十几像素的小物体实测对烟头、瓶盖这类目标的检测效果提升最明显。代价是计算量有所上升但相比精度收益这个开销可以接受。Neck部分我同时参考了BiFPN的思想给不同层级的特征融合加了一个简单的加权机制。原来的PANet是固定加法融合可学习的加权融合允许模型自己决定哪一层特征更重要。垃圾场景里不同尺寸目标的重要性并不一样这个改动是符合直觉的改进。实际修改就是特征融合时对输入做weighted sum并加上可学习的权重参数。2.3 回归损失函数SIoU与WIoU的取舍YOLOv8默认使用CIoU作为边框回归损失它把重叠面积、中心点距离和长宽比一致性都考虑了进去已经是比较完善的版本。但垃圾场景里有一类特殊问题遮挡和粘连导致大量目标框之间有轻微错位单纯加大CIoU的惩罚会让模型在长宽比差异大的目标上比如一根筷子、一根吸管优化速度变慢。我在实验里对比了SIoU和WIoU。SIoU引入了角度代价能让检测框更快地旋转校准方向对细长条状的垃圾有一定帮助。WIoU的思路则是动态聚焦普通质量的锚框减少高质量锚框对损失的主导对标注噪声容忍度更好。考虑到垃圾分类标注中经常出现密集小物体的重叠WIoU的鲁棒性最终打动了我。实际替换不复杂在ultralytics的loss_utils里加上WIoU的实现然后在BboxLoss类中修改iou计算。需要强调的是损失函数这类改动要在训练中观察几个epoch不能只看初始loss值。我实测下来WIoU在验证集上的mAP比CIoU高出约0.8个百分点尤其是密集场景下稳定了不少。注意不要一上来就同时改注意力、检测层、损失函数这样没法定位是哪个改动起效。规范做法是逐个添加每加一个做一次对照实验。3. 数据集构建、标注与增强模型要做得好数据质量占七成以上。这个项目里我把大部分精力花在了数据集构建上。没有干净切合场景的数据集后面改什么都白搭。3.1 数据集类别体系与标注规范类别体系直接取决于应用需求。如果做智能垃圾桶的粗分类用可回收物、厨余垃圾、有害垃圾、其他垃圾四类就够如果要做精细分拣则应该拆成纸板、塑料、玻璃、金属、剩菜、果皮这些细类。我这次按项目需求选择了折中方案以TrashNet公开数据集中的六类为基础纸板、玻璃、金属、纸张、塑料、一般垃圾再额外补充厨余垃圾和烟头电池等小物体图片一共凑了八个类别。标注工具建议用LabelImg配合YOLO格式导出轻量而且操作简单。值得注意的一个细节是标注框的边界框要紧贴物体边缘不要把影子背景包进去一个目标被另一个目标遮挡时也要尽量标出可见部分的最小外接框让模型学习到物体即使被挡住一部分也依然是一个目标的概念。这些细节在训练时直接影响回归损失的计算。数据集规模上八个类别各准备一千到两千张带标注图片基本够用超过两千张边际收益会递减。注意类别间实例数量尽量均衡否则模型天然会偏向样本多的类别这种先验偏差在后面很难用模型结构纠回来。3.2 数据增强与类别不平衡处理Ultralytics在训练阶段默认开启Mosaic增强四张图拼成一张这个增强对提高模型泛化能力帮助很大尤其是让模型看到更多组合场景。不过Mosaic在训练后期需要关闭否则模型会一直面对拼图风格的输入在真实图片上反而效果打折。官方给的close_mosaic10就是让最后10个epoch关闭Mosaic让模型回归到真实分布。针对类别不平衡问题我先统计了每类的实例数量发现烟头这类小物体图片严重偏少导致前期模型经常漏检。处理方法是两管齐下对少量类别做过采样让一批图像中出现的频率更高同时给损失函数加类别权重让模型对少数类错判更加敏感。数据集增强并不是越猛越好。垃圾分类任务需要保留真实的颜色和纹理例如厨余垃圾的油光特征就是重要判别信息如果把颜色抖动参数调得过强垃圾在模型眼里都变成同一副灰蒙蒙的样子反而损失判别力。我最终把hsv_h和hsv_s调得很保守集中用几何增强和噪声注入。3.3 数据划分与防泄漏数据划分比例我采用8:1:1训练、验证、测试分开。这里有一个特别值得警惕的坑同一批次连拍、同一场景不同角度的图片如果同时出现在训练集和验证集里模型相当于见过答案参加考试验证集指标会虚高换到真实场景马上打回原形。所以划分时我先把图片按来源场景分组保证同一个垃圾投放点、同一个拍摄批次的所有图片只出现在一个集合中。这样做之后验证集上的精度下降了一点但真实场景测试时反而更稳定这个取舍非常值得。4. 训练实操环境、超参与过程监控模型结构改完了接下来是训练环节。这部分是实操性最强的环境怎么配、参数怎么设、loss曲线怎么看直接影响最终效果。4.1 环境配置与依赖我的建议是直接创建独立环境。Python版本用3.10PyTorch选2.1.2以上CUDA版本按显卡驱动来。这里有一个经验ultralytics库更新很快不同版本API会有细微变化与其追新版本不如固定一个经过验证的版本组合跑通之后不要随便升级库。安装命令我也放在这里能直接复制使用。conda create -n waste_yolo python3.10 conda activate waste_yolo pip install torch2.1.2 torchvision0.16.2 --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics8.2.10提示如果GPU显存只有8G可以适当减小batch size或者开启AMP混合精度训练。我用的就是8G显存显卡配合AMP训练大几百张图完全没问题。4.2 训练超参数解释与命令很多人看到yolo train命令里一堆参数就头疼实际上有几个参数是核心中的核心。imgsz控制输入分辨率640是速度与精度的平衡点epochs是训练轮数我设了300轮但会配合早停不一定全部跑完batch size受显存限制设16在8G显卡下要开启AMPoptimizer用SGD还是AdamW要掂量官方默认的SGD收敛稳定AdamW前期快但后期容易过拟合。还有一个容易被忽略的weight_decay参数它控制正则化强度我的经验是垃圾数据量小weight_decay设0.0005偏稳妥。学习率初始值用0.01配合warmup预热可以让训练前期不震荡。训练命令如下yolo train datawaste.yaml modelyolov8s.yaml epochs300 imgsz640 batch16 optimizerSGD lr00.01 close_mosaic10 ampTrue cacheTruecacheTrue会把数据集缓存到内存里第一次慢一点之后每个epoch读取速度会快很多。如果你的数据集很大内存不够再改成cacheFalse不用犹豫。4.3 训练过程监控与异常处理训练开始后我一般只看四个指标train loss、val loss、mAP0.5、mAP0.5:0.95。正常情况是train loss稳步下降val loss同步下降mAP逐步爬升。如果train loss下降但val loss上升说明过拟合了早停机制会自己停。如果loss从头到尾不怎么动那大概率是学习率问题或者模型代码有bug需要停下来检查。画损失函数曲线我用库自带的日志也可以用tensorboard可视化。查看results.csv文件的曲线有一个技巧单看训练loss容易忽略验证集表现应该把train_loss和val_loss画在同一张图上对比两者差距开始拉大的位置就是过拟合开始的位置。我在日志里看到loss在250轮附近出现分叉后果断早停最终保存的权重在验证集上表现最好。5. 实验对比与效果分析改进是否有效不能靠感觉要看实验数据。这一节我把基线模型和各个改进版本的指标放在一起对比也分析一下典型错误。5.1 改进前后性能对比整个消融实验按这个顺序进行先在原始YOLOv8s上训练得到第一组基线数据然后单独加入注意力C2f记录效果再加P2小目标检测层最后替换WIoU损失函数。整个过程在自建垃圾数据集上进行用相同训练参数保证公平。我实验中的一组典型对比数据大致如下模型版本参数量(M)GFLOPsmAP0.5mAP0.5:0.95YOLOv8s原始11.228.687.965.4注意力C2f11.829.488.767.1P2检测层13.534.290.268.6WIoU损失13.534.290.969.3可以看出每个改进点都能带来稳步提升幅度虽然不是特别激进但加在一起效果很可观。细看指标会发现mAP0.5:0.95的提升幅度比mAP0.5更明显说明改进后的模型框定得更准而不只是能大致框中位置。5.2 混淆矩阵与误检分析光看平均准确率还不够要检查混淆矩阵。我训练时生成了混淆矩阵热力图直接看哪些类别容易被认错。分析结果发现两个典型错误模式纸质类和纸板类互相混淆因为它们的纹理和颜色本来就接近模型容易把小型纸盒误判成纸张塑料瓶和玻璃瓶在反光强烈的时候也容易互相认错因为它们的外形和透明特性太像了。这两类混淆说明模型学到的主要是形状和颜色特征还不够细腻。应对方式是增加这两类差异明显的数据样本比如特意拍摄高光条件下的玻璃瓶和哑光的塑料瓶让模型学到更本质的材质差异。最终这些数据补充进去后混淆明显缓解。5.3 热力图可视化验证注意力机制为了确认注意力机制是真的让模型关注到了正确位置我用Grad-CAM生成了测试图片的类别激活热力图。在普通的垃圾照片上改进模型的激活区域能准确集中在垃圾物体上背景区域基本没有激活。而在原始模型里注意力容易分散到背景的地砖纹理或光源高光区域这也是误检率高的重要原因。热力图是验证模型内部行为的有效工具比单独看mAP指标更能说明问题。通过热力图还能发现模型的潜在盲区比如一个被塑料袋半遮挡的瓶子热力图只在塑料袋部分激活说明模型没有学习到遮挡物体的结构这为数据集补充提供了方向。6. 系统落地与部署扩展模型训练好了最终要变成能用的检测系统。这一章聊聊模型如何导出、如何部署到边缘设备以及如何快速搭一个演示界面。6.1 模型导出与边缘设备部署在GPU服务器上训练的模型真正在设备端跑还需要导出。YOLOv8原生支持导出多种格式最常用的两种是ONNX和TensorRT引擎。ONNX是中间格式方便跨平台转换TensorRT进一步做层融合和量化推理速度提升明显。导出TensorRT的方式比较简单在GPU环境执行转换命令就能得到engine文件。yolo export modelbest.pt formatengine device0 halfTrue得到的半精度engine文件直接放到部署设备上配合libtorch或者ONNXRuntime的C接口就能跑。半精度部署在RTX系列显卡上效果很好速度几乎是PyTorch原生推理的三倍。如果部署到RK3588这类边缘平台就要走rknn-toolkit转换链先转ONNX再转RKNN格式。这块按官方文档一步步做即可需要留意的点是某些自定义模块算子可能不被模型转换工具支持遇到这种情况优先把不支持的模块简化。6.2 基于Gradio的快速演示系统为了快速验证效果和给别人演示我用Gradio搭了一个简单的Web界面。这个库最大的优势是十几行代码就能生成一个带上传入口、结果展示的后台界面很适合做模型效果验收。核心代码很简单加载训练好的权重定义一个预测函数返回标注后的图片和类别置信度列表即可。import gradio as gr from ultralytics import YOLO model YOLO(best.pt) def predict(image): results model.predict(image, conf0.25, iou0.45) annotated results[0].plot() return annotated gr.Interface(fnpredict, inputsgr.Image(typepil), outputsgr.Image(typenumpy), title生活垃圾识别系统).launch()实际部署时还要考虑并发请求和视频流处理Gradio更适合内部验收演示。如果需要接入摄像头做实时检测OpenCV读取视频帧然后逐帧送入模型也能跑到很稳定的帧率关键是模型推理速度要跟上输入帧率。7. 常见问题与排查速查最后把这次项目里遇到过的典型问题汇总成速查表方便大家训练和部署时对照排查。问题现象可能原因排查建议训练loss不下降学习率过大或过小、数据标签错误先看前10轮loss趋势调低lr0或用warmup预热验证mAP始终很低数据集划分泄漏或类别严重不平衡检查同一场景是否同时出现在多个集合中小目标完全检测不到检测层下采样倍数太大增加P2层或在标注时保证小目标框足够干净显存OOMbatch过大或输入分辨率太高降低batch、开启amp、减小imgsz同一目标出现多个框NMS阈值太低或置信度阈值太低适当提高conf调高nms_iou到0.6左右某类垃圾始终识别差样本数量过少或特征与其他类相似过采样、数据增强、增加类别权重导出ONNX失败自定义模块算子不兼容简化自定义模块用标准卷积和注意力替代7.1 训练阶段典型问题训练阶段最容易遇到的一个坑是加载预训练权重时自定义模块和原网络结构不匹配。我在刚开始加入注意力模块时直接加载yolov8s.pt预训练权重就报了shape不匹配错误。处理办法是先加载官方权重到主干部分再用strictFalse方式跳过新加的模块层这样让原backbone特征提取能力保留新模块从头训练整体收敛速度快很多。另一个高频问题是训练曲线剧烈震荡。这通常是因为batch size太小、学习率偏大造成的。垃圾数据集的图片质量参差个别脏数据会带偏梯度方向所以训练前有必要做一轮数据清洗把模糊、严重过曝、标注明显错误的图片挑出来删掉一组干净的数据对稳定的训练曲线作用远大于调参。7.2 检测效果类问题检测效果不佳时不要急着堆参数。我的排查习惯是先用一组容易的测试图跑推理如果简单场景都检测不准优先怀疑训练过程和数据质量如果简单场景没问题、复杂场景拉胯再去调整conf和NMS参数。牙膏式的参数调整很难解决本质问题回归数据才是硬道理。7.3 部署性能问题部署时最常见的问题是模型框架转换后精度下降。半精度导出时如果发现精度掉太多通常不用改模型回到推理预处理看看图片缩放方式是否和训练时一致、归一化参数是否正确这些细小的差异往往比模型转换本身更影响精度。部署端我建议固定输入尺寸不做动态尺寸推理这样能显著提高在边缘设备上的计算效率。最后分享一个我个人的体会这个项目做到后期我发现模型改进带来的收益反而不如数据治理带来的收益明显。花费一周时间做数据清洗和补充难例比纠结一个注意力变体结构参数的收益来得更快、更稳定。所以如果你的垃圾分类识别系统当前效果不理想先别急着改网络结构把训练集和验证集翻一遍往往答案就在那里。YOLOv8底子很好小目标检测层加注意力机制这组改进在垃圾场景又是出奇地有效以后如果再迭代这个系统我会优先补更多真实场景视频帧然后往流式检测和部署上多花时间整套方案会更完整。
返回列表