☰
基于YOLOv8的垃圾分类目标检测:从数据集构建到算法改进与部署
2026/9/28 6:44:23 网站建设 项目流程

1. 从一张随手拍的照片说起:这个项目到底在解决什么问题

小区楼下四个垃圾桶并排摆着,绿桶写"厨余"、蓝桶写"可回收"、红桶写"有害"、灰桶写"其他"。我拎着一袋混着外卖盒、香蕉皮、废电池和快递纸箱的垃圾站在那儿,脑子里第一反应是"这电池到底算不算有害",第二反应是"算了,全扔灰桶吧"。这个场景你肯定不陌生。垃圾分类推行了这么多年,真正卡住普通人的不是意愿,而是判断成本——每次扔垃圾都要做一道分类题,做错了还有心理负担。

这个项目要干的事很直接:用摄像头拍一张垃圾的照片,模型自动告诉你这是哪一类,该扔哪个桶。核心关键词就是深度学习、yolov8、目标检测、垃圾分类、图像识别。它不是做一个"整张图属于哪一类"的简单分类器,而是做目标检测——一张图里可能同时有塑料瓶、纸盒、果皮,模型要把每个物体框出来,分别标注类别。这个区别很关键,后面会展开讲。

适合谁看?如果你是刚入门深度学习、想找一个"有真实场景、数据好搞、效果看得见"的练手项目,垃圾分类检测是个非常合适的切入点。如果你已经跑通过yolov8的官方demo,想进一步搞清楚改进算法到底改哪里、为什么改、改了有没有用,这篇也会把改进思路和验证方法讲透。如果你是想做课程设计或毕业设计的同学,这里面的数据集构建、模型改进、对比实验、部署落地整条链路都能直接参考。

我先把结论摆前面:baseline用yolov8n在自建垃圾数据集上跑,mAP@0.5大概能到0.85上下;做针对性改进后能推到0.90左右。但真正决定项目成败的不是模型结构,而是数据集的质量和类别定义。这一点我在后面会用大篇幅讲,因为踩过的坑基本都在这儿。

2. 整体方案设计:为什么选yolov8,为什么做检测而不是分类

2.1 分类、检测、分割,三条路选哪条

垃圾分类这个任务,技术上至少有三条路可走。

第一条是图像分类:输入一张图,输出一个类别标签。比如ResNet、EfficientNet这类模型,最后接一个softmax。这条路最简单,但有个致命问题——一张图只能给一个答案。现实中你拍一张垃圾桶旁边的照片,里面可能有瓶子、纸、果皮,分类器只能告诉你"这张图最像可回收",剩下两个物体就被忽略了。

第二条是目标检测:输入一张图,输出若干个边界框,每个框带类别和置信度。yolov8、Faster R-CNN都属于这类。它能处理"一图多物"的情况,正好匹配垃圾场景。

第三条是语义分割:像素级分类,把每个像素归到某个类别。精度高,但标注成本极高,一张图标注要几分钟,做几千张数据集不现实。

我选目标检测,理由很实在:垃圾场景天然是"多物体、需要定位"的,分类器不够用;分割标注太贵,学生项目和个人研究扛不住。yolov8在检测里又是性价比最高的选择——速度快、精度够、生态好、改进空间大。

2.2 yolov8相比前代到底强在哪

很多人用yolov8但说不清它比yolov5强在哪。我按自己的理解捋一遍,这些点直接决定了你后面改进的方向。

第一,Anchor-Free。yolov5还是基于anchor box的,需要预先聚类出一组先验框尺寸。yolov8改成了anchor-free,直接预测目标中心点和宽高。好处是省掉了调anchor的麻烦,对小目标和形状差异大的目标更友好。垃圾里既有细长的电池,又有扁平的纸盒,anchor-free确实省心。

第二,C2f模块替换C3。这是backbone里的核心变化。C2f(Cross Stage Partial with 2 convolutions and f)在保证梯度分流的同时,增强了特征复用。说人话就是:同样的参数量下,特征提取能力更强。这也是为什么yolov8n这么小的模型精度还能打。

第三,解耦头(Decoupled Head)。分类和回归用两个独立分支,而不是共享一个头。分类关心"是什么",回归关心"在哪",两者关注的特征不一样,解耦之后各干各的,收敛更快、精度更高。

第四,Task-Aligned Assigner。正负样本分配策略改了,不再单纯按IoU,而是综合分类得分和定位质量来分配。这让训练更稳定,尤其是密集小目标场景。

第五,DFL回归损失。Distribution Focal Loss把边界框回归从"预测一个值"变成"预测一个分布",对边界模糊的目标更鲁棒。

这些改进点里,C2f和解耦头是最容易做文章的地方,后面讲改进时会重点说。

2.3 整体技术路线

整个项目的链路我画成文字版:

数据采集 → 数据清洗 → 标注(labelme/Roboflow)→ 格式转换(YOLO txt)→ 数据集划分 → 数据增强 → 模型选型(yolov8n/s)→ 训练 → 评估(mAP、PR曲线)→ 改进实验 → 对比 → 导出ONNX → 部署(本地/边缘设备)

每一环都有坑,我按顺序拆。

3. 数据集构建:决定项目上限的关键环节

3.1 类别怎么定,这是第一个大坑

我见过太多人一上来就定"可回收、厨余、有害、其他"四类,然后发现标注的时候根本没法标。为什么?因为**"可回收"是一个抽象类别,不是一个视觉类别**。一个塑料瓶和一张报纸都属于可回收,但它们在图像上长得完全不一样。你让模型学"可回收"这个概念,它学不明白。

我的做法是先定细粒度子类,再映射到大类。比如:

细粒度子类映射大类视觉特征
塑料瓶可回收透明/半透明,圆柱形
易拉罐可回收金属反光,圆柱形
纸箱可回收棕色,方形,有折痕
报纸可回收灰白色,平面
果皮厨余有机质感,不规则
剩饭厨余混合状,颜色杂
电池有害小,圆柱/方形,有标识
药品有害小,包装特征
烟头其他极小,细长
陶瓷碎片其他不规则,边缘锐利

这样标注的时候,标注员只需要判断"这是塑料瓶还是易拉罐",不用纠结抽象概念。训练完之后,推理时把细粒度类别映射回四大类输出即可。这个设计让标注一致性大幅提升,mAP也明显更高。

3.2 数据从哪来

三个来源,我按推荐度排序。

第一,自采。拿手机在小区垃圾桶、办公室、食堂拍。优势是场景真实、分布匹配你的应用场景。劣势是类别不平衡——塑料瓶到处都是,有害垃圾很难拍到。我的经验是自采至少2000张,覆盖不同光照(白天/夜晚/室内)、不同角度、不同背景。

第二,公开数据集。比较常用的有TrashNet(但它是分类数据集,只有单物体)、TACO(垃圾检测数据集,类别多但标注质量参差)。TACO可以直接用,但要做清洗,去掉模糊和错误标注的图。

第三,合成数据。用CutMix、Copy-Paste把单个物体贴到不同背景上。这个对稀有类别(比如有害垃圾)特别有用。我实测过,用Copy-Paste增强稀有类别后,该类别的AP能提升10个点以上。

3.3 标注工具与规范

标注工具我用过三个:labelImg、labelme、Roboflow。结论是:

  • labelImg:最轻量,画框快,适合纯检测任务。缺点是界面老,协作差。
  • labelme:支持多边形,适合后续想转分割。但画框效率不如labelImg。
  • Roboflow:在线协作,自动格式转换,还能做增强。团队用最舒服,但免费额度有限。

标注规范我定了几条硬规则,直接抄:

  1. 框要贴紧目标边缘,不留多余背景,也不要切掉目标。
  2. 遮挡超过50%的目标不标,标了反而干扰训练。
  3. 同一物体只标一次,不要嵌套框。
  4. 极小目标(小于20x20像素)单独讨论,要么放大图像,要么放弃。
  5. 每标完500张做一次交叉校验,两个人标同一批,算IoU一致性。

提示:标注一致性比标注数量重要得多。1000张高质量标注,胜过5000张乱七八糟的标注。我踩过的最大坑就是前期图快,标注质量差,训练时loss怎么都不降,回头返工重标花了三倍时间。

3.4 数据集划分与格式转换

划分比例一般是训练:验证:测试 = 7:2:1。但垃圾数据集有个特殊点:同一场景拍的多张图要分到同一集合,否则验证集里出现训练集同场景的图,指标虚高。我一般按"拍摄批次"划分,而不是随机划分。

格式转换到YOLO格式,每张图对应一个txt,每行是:

class_id center_x center_y width height

所有坐标归一化到0-1。转换脚本用Python写,核心逻辑就是读标注文件、算归一化坐标、写txt。这个网上模板很多,但要注意类别id要从0开始连续,中间断了训练会报错。

4. 模型训练:参数怎么调,坑怎么避

4.1 环境配置

我用的环境是Ubuntu 20.04 + Python 3.10 + PyTorch 2.0 + CUDA 11.8。显卡是RTX 3060 12G,跑yolov8n绰绰有余。如果你只有CPU,也能跑,但训练时间会从几小时变成几天,建议先用小数据集(500张)验证流程。

安装ultralytics:

pip install ultralytics

验证安装:

from ultralytics import YOLO model = YOLO('yolov8n.pt') print(model.info())

注意:不要用最新版的torch配最新版的ultralytics,有时候会有兼容问题。我一般锁定torch 2.0.x + ultralytics 8.0.x这个组合,实测最稳。

4.2 数据配置文件

新建一个garbage.yaml:

path: /home/user/garbage_dataset train: images/train val: images/val test: images/test nc: 10 names: 0: plastic_bottle 1: can 2: carton 3: newspaper 4: peel 5: leftover 6: battery 7: medicine 8: cigarette 9: ceramic

nc是类别数,names要和标注时的类别id严格对应。这里错一个,训练全废。

4.3 训练参数详解

启动训练:

from ultralytics import YOLO model = YOLO('yolov8n.pt') results = model.train( data='garbage.yaml', epochs=150, imgsz=640, batch=16, lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3, patience=30, device=0, workers=8, project='garbage_runs', name='baseline' )

逐个说这些参数为什么这么设:

  • epochs=150:垃圾数据集一般5000张以内,150轮足够收敛。太多会过拟合,太少欠拟合。看loss曲线,如果验证loss还在降就继续,平了就停。
  • imgsz=640:yolov8默认640,也是精度和速度的平衡点。如果你的目标普遍很小(比如烟头),可以提到1280,但显存翻倍。
  • batch=16:12G显存下640分辨率能跑到16。显存不够就降到8,但batch太小BN层统计不准,建议配合梯度累积。
  • lr0=0.01:初始学习率。yolov8用SGD,这个值是官方推荐。太大震荡,太小收敛慢。
  • lrf=0.01:最终学习率 = lr0 * lrf,即余弦退火到0.0001。
  • warmup_epochs=3:前3轮预热,学习率从0慢慢升到0.01,防止一开始梯度爆炸。
  • patience=30:30轮没提升就早停,省时间。
  • workers=8:数据加载线程数,根据CPU核数调。

4.4 训练过程监控

训练时重点看三个东西:

第一,loss曲线。用results.csv画图:

import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv('garbage_runs/baseline/results.csv') df.columns = df.columns.str.strip() plt.figure(figsize=(12, 4)) plt.subplot(1, 3, 1) plt.plot(df['train/box_loss'], label='train_box') plt.plot(df['val/box_loss'], label='val_box') plt.legend() plt.title('Box Loss') plt.subplot(1, 3, 2) plt.plot(df['train/cls_loss'], label='train_cls') plt.plot(df['val/cls_loss'], label='val_cls') plt.legend() plt.title('Cls Loss') plt.subplot(1, 3, 3) plt.plot(df['metrics/mAP50(B)'], label='mAP50') plt.plot(df['metrics/mAP50-95(B)'], label='mAP50-95') plt.legend() plt.title('mAP') plt.tight_layout() plt.savefig('training_curves.png')

健康的曲线长这样:train loss和val loss同步下降,最后都趋于平缓,两者差距不大。如果train loss一直降但val loss开始上升,就是过拟合,该早停或加数据增强。

第二,mAP曲线。mAP@0.5到0.85以上算及格,0.90以上算好。mAP@0.5:0.95一般比mAP@0.5低15-20个点,正常。

第三,混淆矩阵。训练完会自动生成confusion_matrix.png。重点看哪些类别互相混淆。我实测下来,塑料瓶和易拉罐容易混(都是圆柱形反光),果皮和剩饭容易混(都是有机质)。这两个混淆对是后续改进的重点。

4.5 常见训练问题速查

问题现象可能原因解决办法
loss不下降学习率太小/标注错误检查标注,调大lr
loss震荡剧烈学习率太大/batch太小降lr,增大batch
某类别AP极低样本太少/标注质量差数据增强,重标
验证mAP远低于训练过拟合加增强,加dropout,减模型
显存溢出batch/imgsz太大降batch或imgsz
训练速度极慢workers太少/CPU瓶颈增workers,检查数据加载

实操心得:训练前一定先用model.val()在验证集上跑一遍未训练的模型,确认数据加载和类别映射没问题。我见过太多人训练了8小时才发现类别id对错了,白跑。

5. 算法改进:改哪里,怎么验证有效

5.1 改进思路从哪来

改进不是拍脑袋,要从baseline的失败案例里找方向。我的流程是:

  1. 跑完baseline,导出所有验证集的预测结果。
  2. 找出漏检(FN)和误检(FP)最多的类别。
  3. 分析原因:是小目标?是遮挡?是类别相似?
  4. 针对性设计改进模块。

我baseline跑下来,主要问题有三个:小目标(烟头、电池)漏检多、相似类别混淆(瓶/罐)、密集场景下框重叠。针对这三点,我做了三个改进。

5.2 改进一:加入注意力机制

在backbone的C2f模块后插入CBAM(Convolutional Block Attention Module)。CBAM包含通道注意力和空间注意力两部分,能让模型更关注有判别力的区域。

为什么有效?垃圾图像里背景杂乱(地面、手、其他垃圾),模型容易被背景干扰。CBAM的空间注意力会抑制背景响应,增强目标区域。我实测在yolov8n上加CBAM,mAP@0.5提升约1.5个点,小目标AP提升更明显。

代码上,在ultralytics/nn/modules/block.py里加CBAM类,然后在parse_model里注册。具体实现网上有,但要注意CBAM加太多会拖慢推理,我一般只在P3、P4两个尺度加。

5.3 改进二:替换损失函数

baseline用CIoU loss做框回归。我换成WIoU(Wise-IoU)。WIoU的核心思想是根据锚框质量动态调整损失权重,质量差的框给低权重,避免它们主导梯度。

为什么有效?垃圾数据集里标注质量参差,有些框画得不准。CIoU对这些差框一视同仁,导致模型被带偏。WIoU能缓解这个问题。实测mAP@0.5提升约0.8个点,训练更稳定。

5.4 改进三:多尺度训练与测试

训练时随机resize输入(320到960之间),测试时用TTA(Test Time Augmentation),把原图、翻转图、多尺度图的预测融合。

为什么有效?垃圾目标尺度差异极大,电池可能只占50像素,纸箱占500像素。多尺度训练让模型见过各种尺度,泛化更好。TTA相当于"多问模型几次,投票决定",能提升1-2个点,但推理时间翻3倍。

5.5 改进效果对比

我在同一测试集上跑了消融实验:

模型配置mAP@0.5mAP@0.5:0.95参数量(M)推理时间(ms)
yolov8n baseline0.8520.6713.28.5
+CBAM0.8670.6893.49.2
+WIoU0.8600.6833.28.5
+多尺度训练0.8710.6953.28.5
三者结合0.8910.7123.49.2
+TTA(测试)0.9030.7243.427.6

结论很清楚:三个改进叠加能把mAP@0.5从0.852推到0.891,加TTA到0.903。代价是推理时间从8.5ms涨到27.6ms。如果部署在边缘设备上,TTA可能不划算,前三个改进是性价比最高的。

注意:改进实验一定要做消融,一个一个加,看每个模块的独立贡献。我见过有人一次性加五个模块,涨了2个点,但根本不知道哪个有用哪个没用,写论文都没法写。

6. 部署落地:从模型到能用的系统

6.1 导出ONNX

训练完的.pt文件不能直接部署到很多平台,先导出ONNX:

from ultralytics import YOLO model = YOLO('garbage_runs/baseline/weights/best.pt') model.export(format='onnx', imgsz=640, simplify=True, opset=12)

simplify=True会做图优化,opset=12兼容性最好。导出后用onnxruntime验证一下输出shape对不对。

6.2 本地推理

最简单的部署是Python脚本:

from ultralytics import YOLO import cv2 model = YOLO('best.onnx', task='detect') img = cv2.imread('test.jpg') results = model(img, conf=0.25, iou=0.45) for r in results: for box in r.boxes: cls = int(box.cls[0]) conf = float(box.conf[0]) xyxy = box.xyxy[0].tolist() print(f'{model.names[cls]}: {conf:.2f} at {xyxy}')

conf=0.25是置信度阈值,iou=0.45是NMS的IoU阈值。这两个值要根据实际场景调:宁可漏检不可误检就调高conf,宁可误检不可漏检就调低conf。

6.3 边缘设备部署

如果想部署到RK3588这类边缘板子上,流程是:ONNX → RKNN。用RKNN-Toolkit2转换,然后板端用RKNN Runtime推理。这里坑很多,主要是算子支持问题——yolov8的某些算子RKNN不支持,需要替换或自定义。我建议先用官方提供的yolov8转换脚本,跑通了再改。

如果部署到海思芯片(比如hi3516cv610),流程类似,但工具链不同。核心思路都是先转中间格式,再转目标格式,每步验证输出一致性。

6.4 系统集成

一个完整的垃圾分类识别系统,除了模型还需要:

  • 图像采集:摄像头或手机上传
  • 预处理:resize、归一化
  • 推理:模型前向
  • 后处理:NMS、类别映射(细粒度→四大类)
  • 展示:在原图上画框、标注类别、给出投放建议

我用Gradio快速搭了个demo:

import gradio as gr from ultralytics import YOLO model = YOLO('best.pt') def predict(image): results = model(image, conf=0.25) return results[0].plot() gr.Interface(fn=predict, inputs='image', outputs='image').launch()

这个demo虽然简单,但足够演示。如果要产品化,前端用Vue/React,后端用FastAPI,模型用ONNX Runtime或TensorRT加速。

7. 实操避坑与经验总结

7.1 数据层面的坑

坑一:类别不平衡。塑料瓶可能有2000个样本,电池只有50个。直接训练,模型对电池的AP会很低。解决办法:过采样稀有类别 + Copy-Paste增强 + 类别加权损失。我一般把稀有类别过采样到至少300个。

坑二:标注不一致。同一个人标同一张图,两次结果都可能不一样。解决办法:制定详细标注规范 + 定期交叉校验 + 用标注工具的一致性检查功能。

坑三:场景泄漏。同一场景的图分到了训练集和验证集,导致验证指标虚高。解决办法:按拍摄批次划分,不按图片随机划分。

7.2 训练层面的坑

坑一:学习率没调好。太大loss爆炸,太小不收敛。我的经验是先用官方推荐值跑一遍,看loss曲线再微调。如果loss前几轮就爆炸,lr降10倍;如果loss几乎不动,lr升3倍。

坑二:数据增强过度。yolov8默认开了mosaic、mixup、HSV增强。如果数据集本身就很杂,再开强增强反而有害。我一般前期开强增强,后期关掉mosaic,让模型在真实分布上收敛。

坑三:早停太早。patience设太小,模型还没收敛就停了。垃圾数据集我建议patience至少30,最好50。

7.3 部署层面的坑

坑一:训练和推理的预处理不一致。训练时用了某种归一化,推理时忘了,结果精度暴跌。解决办法:把预处理封装成函数,训练和推理共用。

坑二:ONNX导出后精度下降。一般是算子不支持或精度损失。解决办法:导出后逐层对比输出,找出偏差大的层。

坑三:边缘设备算力不够。yolov8n在RK3588上大概能跑30FPS,但如果用yolov8m就只有10FPS。解决办法:根据设备算力选模型尺寸,必要时做量化(INT8)。

7.4 我的经验清单

最后列几条我踩坑踩出来的经验,直接抄:

  1. 数据集质量 > 模型改进 > 训练技巧。别本末倒置。
  2. 先跑通全流程,再优化细节。用100张图跑通训练-评估-部署,再上全量数据。
  3. 每次实验只改一个变量。改了学习率又改增强,涨了也不知道是谁的功劳。
  4. 保存所有实验配置和结果。用wandb或tensorboard,别靠脑子记。
  5. 验证集指标好不代表实际好用。一定要在真实场景拍图测试,看漏检误检。
  6. 模型不是越大越好。yolov8n在垃圾检测上够用,上大模型收益递减。
  7. 部署前一定做端到端测试。从摄像头到输出,整条链路跑通再交付。

这个项目我从数据采集到部署落地大概花了三周,其中两周在搞数据。如果你也想做,我的建议是:先把数据这一关过了,模型部分反而是最简单的。yolov8的生态太成熟了,训练脚本改改参数就能跑,真正拉开差距的是你对场景的理解和对数据的把控。

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

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

立即咨询