简介这份资源是基于YOLOv8的垃圾分类识别设计完整项目包面向深度学习入门者、人工智能课程设计学生及毕业设计开发者帮助解决垃圾自动分类识别这一典型目标检测任务。包内共11个文件以Python脚本、YAML配置、预训练权重pt文件、PNG效果图和Markdown说明文档为主压缩包约10.21MB涵盖数据集重命名、图像标注辅助、模型配置与识别结果展示等环节。项目围绕可回收、厨余、有害及其他垃圾等类别展开涉及样本收集、图像标注、数据增强、归一化预处理与多轮迭代训练最终实现摄像头图像的实时分类。读者可借此获得一套可复用的YOLOv8训练与部署方案理解边界框标注、数据集管理工具的使用方式并参考预测效果图与README说明快速上手调试。目前已有32人学习下载适合作为课程设计或毕业设计的实践参考。1. 垃圾分类识别为什么选 YOLOv8从数据集到落地的完整判断垃圾分类识别这个题目很多人第一反应是「拿个预训练模型跑一下不就行了」。真做过就知道坑不在模型本身而在数据集的类别定义、标注一致性、以及推理时的实际场景差异。YOLOv8 之所以成为这类项目的首选核心原因有三个一是它把检测、分割、分类统一到一套框架里垃圾分类既可以做纯检测框出物体类别也可以做分割精确到像素边缘切换成本低二是 Ultralytics 的工程封装足够成熟从训练到导出 ONNX、TensorRT 再到边缘设备部署链路是通的三是社区资源丰富预训练权重、数据增强策略、损失曲线可视化这些都有现成方案不用从零造轮子。这篇文章面向的是想用 YOLOv8 做垃圾分类识别落地的从业者——不管你是做毕业设计、做嵌入式部署、还是做产线分拣原型核心诉求都一样数据集怎么处理、模型怎么训、参数怎么调、部署到板子上怎么跑通。我会按「数据准备 → 训练调参 → 验证排错 → 部署优化」的顺序把每个环节的可复现步骤和血泪经验讲清楚。如果你手头有一块 RK3588 或者想先在 GTX1660Ti 上把流程跑通这篇的内容可以直接抄作业。2. 数据集处理与 YOLOv8 训练环境搭建从 Labelme 标注到第一轮训练2.1 垃圾分类数据集的类别设计与标注规范垃圾分类的类别定义直接决定模型能不能用。常见做法是分四类可回收物、厨余垃圾、有害垃圾、其他垃圾。但实际标注时会发现「可回收物」下面有塑料瓶、纸箱、易拉罐、玻璃瓶类内差异极大「其他垃圾」又是个筐什么都往里装。我的建议是如果你的应用场景是固定品类分拣比如只分塑料瓶和易拉罐就按具体物品类别标注不要硬套四分类如果是通用场景四分类可以但每个类别至少要有 8001000 张有效标注图否则模型会严重偏向样本多的类。标注工具用 Labelme 还是 LabelImg 都行关键是导出格式。YOLOv8 需要的是 YOLO 格式的 txt 标注每行class_id x_center y_center width height坐标全部归一化到 01。Labelme 默认导出 JSON需要转一道。下面这个脚本是我常用的转换逻辑import json import os from pathlib import Path # 类别映射根据你的实际类别修改 CLASS_MAP { recyclable: 0, kitchen_waste: 1, hazardous: 2, other: 3 } def labelme_to_yolo(json_dir, output_dir, class_map): 将 Labelme JSON 转为 YOLO txt 格式 json_dir: Labelme 标注文件目录 output_dir: 输出 txt 目录 class_map: 类别名到 id 的映射 os.makedirs(output_dir, exist_okTrue) for json_file in Path(json_dir).glob(*.json): with open(json_file, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue # 跳过未定义类别 points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] # 计算归一化中心点和宽高 x_center (min(xs) max(xs)) / 2.0 / img_w y_center (min(ys) max(ys)) / 2.0 / img_h width (max(xs) - min(xs)) / img_w height (max(ys) - min(ys)) / img_h # 裁剪到 [0,1] 防止越界 x_center max(0, min(1, x_center)) y_center max(0, min(1, y_center)) width max(0, min(1, width)) height max(0, min(1, height)) lines.append(f{class_map[label]} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) txt_name json_file.stem .txt with open(os.path.join(output_dir, txt_name), w) as f: f.write(\n.join(lines)) # 调用示例 labelme_to_yolo(./annotations, ./labels, CLASS_MAP)这段代码的关键点一是坐标归一化必须用原图宽高不能搞错二是要裁剪到 [0,1]Labelme 有时候会标出边界外的点不裁剪训练时会报错三是类别映射表要和后续 data.yaml 里的 names 顺序完全一致否则模型学出来的类别是乱的。2.2 Ubuntu 20.04 下 YOLOv8 环境配置与 CPU 版本跑通环境搭建这块Ubuntu 20.04 是最稳的选择驱动兼容性好。如果你手头只有 CPU 或者想在服务器上先验证流程CPU 版本也能跑就是慢。步骤如下# 1. 创建虚拟环境强烈建议不要污染系统 Python conda create -n yolov8 python3.10 -y conda activate yolov8 # 2. 安装 PyTorchCPU 版本如果有 GPU 换成对应 CUDA 版本 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu # 3. 安装 Ultralytics pip install ultralytics # 4. 验证安装 yolo checksyolo checks会输出环境信息重点看 Python 版本、PyTorch 版本、以及是否有 GPU 可用。CPU 版本训练速度大概是 GPU 的 1/20 到 1/50GTX1660Ti 上跑 100 轮可能 2 小时CPU 上可能要一整天。所以 CPU 版本只适合验证代码能不能跑通真正训练还是建议上 GPU。2.3 data.yaml 配置与第一轮训练命令YOLOv8 的数据配置文件 data.yaml 结构如下path: /home/user/dataset # 数据集根目录 train: images/train # 训练集图片相对路径 val: images/val # 验证集图片相对路径 test: images/test # 测试集可选 nc: 4 # 类别数 names: # 类别名顺序必须和标注时的 class_id 一致 0: recyclable 1: kitchen_waste 2: hazardous 3: other目录结构建议这样组织dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml第一轮训练命令yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/train \ namegarbage_v1参数说明modelyolov8n.pt是最小的预训练权重适合快速验证imgsz640是输入分辨率垃圾分类场景如果物体较小可以提到 1280但显存占用会翻倍batch16在 GTX1660Ti 上差不多是极限显存不够就降到 8patience20表示 20 轮验证集指标不提升就早停防止过拟合。训练完成后损失曲线和 mAP 曲线会自动保存在runs/train/garbage_v1/下直接看 results.png 就行。3. 训练参数调优与模型改进从损失曲线判断问题到注意力机制引入3.1 损失函数曲线怎么看三类典型异常与对应调参策略YOLOv8 训练输出的损失曲线包含 box_loss、cls_loss、dfl_loss 三条。正常情况三条都应该是下降趋势验证集损失跟随训练集下降但略高。常见异常有三种第一种训练损失下降但验证损失上升这是过拟合。解决方法是增加数据增强augmentTrue是默认开的可以调mosaic1.0、mixup0.1、减少模型参数量从 yolov8m 换回 yolov8n、或者加 dropout。垃圾分类场景如果某些类别样本太少过拟合会特别明显。第二种损失震荡不收敛。通常是学习率太大lr00.01是默认值但如果你的 batch 很小比如 4 或 8学习率要相应降到 0.001 或 0.005。另外检查一下标注有没有问题比如同一个物体标了多个框、或者框的宽高为 0。第三种cls_loss 居高不下。说明分类头学不动可能是类别不平衡导致的。比如「有害垃圾」只有 50 张图其他类有 1000 张模型会倾向于把所有东西都预测成多数类。解决办法是用cls_pw参数给类别加权或者在数据集层面做重采样。3.2 用协调注意力机制改进 YOLOv8 检测头YOLOv8 的检测头是解耦头分类和回归分开。在垃圾分类场景里有些物体外观相似比如塑料瓶和玻璃瓶单纯靠卷积特征容易混。引入注意力机制可以让模型更关注区分性区域。协调注意力Coordinate Attention是一种轻量方案计算量增加不多但能提升空间定位能力。具体做法是在ultralytics/nn/modules/block.py里加一个 CoordAtt 模块然后在ultralytics/nn/modules/head.py的 Detect 类里插入。代码大致如下import torch import torch.nn as nn class CoordAtt(nn.Module): 协调注意力分别沿 H 和 W 方向做池化再融合 def __init__(self, inp, reduction32): super().__init__() self.pool_h nn.AdaptiveAvgPool2d((None, 1)) self.pool_w nn.AdaptiveAvgPool2d((1, None)) mip max(8, inp // reduction) self.conv1 nn.Conv2d(inp, mip, kernel_size1) self.bn1 nn.BatchNorm2d(mip) self.act nn.SiLU() self.conv_h nn.Conv2d(mip, inp, kernel_size1) self.conv_w nn.Conv2d(mip, inp, kernel_size1) def forward(self, x): identity x n, c, h, w x.size() x_h self.pool_h(x) # (n,c,h,1) x_w self.pool_w(x).permute(0, 1, 3, 2) # (n,c,w,1) 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插入位置建议在 Detect 头的三个分支之前对 P3、P4、P5 特征图各加一个 CoordAtt。改完后重新训练mAP 通常能涨 13 个点但推理速度会降 5%10%。如果部署在 RK3588 这类边缘设备上要权衡精度和延迟。3.3 训练参数含义速查与调参优先级YOLOv8 的训练参数有几十个但真正影响大的就那几个。下面这张表是我实际调参时总结的优先级参数默认值作用调参建议lr00.01初始学习率batch 小就降到 0.0010.005lrf0.01最终学习率系数一般不动除非损失震荡momentum0.937动量保持默认weight_decay0.0005权重衰减过拟合时提到 0.001warmup_epochs3.0预热轮数小数据集可以降到 1box7.5框损失权重定位不准时提到 10cls0.5分类损失权重分类混淆时提到 1.0dfl1.5DFL 损失权重一般不动mosaic1.0Mosaic 增强概率小数据集保持 1.0mixup0.0Mixup 增强概率过拟合时开到 0.10.2copy_paste0.0复制粘贴增强分割任务用检测可不开调参优先级先调 lr0 和 batch再看损失曲线决定要不要加正则化最后才考虑改损失权重。不要一上来就大改否则出了问题都不知道是哪个参数导致的。4. 模型验证与部署前排查mAP 达标但实际效果差的五个原因4.1 验证集指标与真实场景的差距分析训练完看 mAP0.5 到了 0.9 就以为万事大吉结果一部署到实际场景就翻车这是最常见的踩坑。原因通常是验证集和真实场景的数据分布不一致。比如验证集都是白底产品图实际场景是传送带上的垃圾光照、角度、遮挡全变了。解决办法是验证集一定要从真实场景里采不要用网上下的干净数据集凑数。如果真实场景数据少至少要做一轮实地拍摄哪怕只有 200 张也比没有强。另一个容易忽略的点是置信度阈值。训练时默认conf0.25但实际部署时这个值要重新调。阈值太高会漏检太低会误检。垃圾分类场景里误检的代价可能比漏检高把可回收物分到有害垃圾里后续处理很麻烦所以阈值可以适当调高到 0.40.5。4.2 模型导出 ONNX 与 RK3588 部署注意事项如果要在 RK3588 上部署标准流程是PyTorch → ONNX → RKNN。导出 ONNX 的命令yolo export modelruns/train/garbage_v1/weights/best.pt formatonnx imgsz640 opset12 simplifyTrueopset12是 RKNN 工具链兼容性最好的版本simplifyTrue会做图优化去掉冗余算子。导出后可以用 Netron 看一下网络结构确认没有不支持的算子比如某些自定义注意力模块可能不被 RKNN 支持需要替换或删除。转 RKNN 的步骤大致是先用rknn-toolkit2加载 ONNX做量化校准需要准备 100200 张校准图然后导出 rknn 模型。量化时注意垃圾分类的颜色特征比较重要如果用 int8 量化导致精度掉太多可以改用混合量化把第一层和最后一层保持 fp16。4.3 推理速度优化从 GTX1660Ti 到边缘设备的延迟对比不同硬件的推理延迟差异很大。下面是我实测的一组数据YOLOv8n输入 640×640硬件精度单帧延迟备注GTX1660TiFP16812msTensorRT 加速后RK3588 NPUINT82540ms单核 NPU多核可并行CPU i7-10700FP32120200ms不推荐实际部署Jetson Orin NanoFP161525msTensorRT 加速如果延迟要求高优先考虑 TensorRT 或 RKNN 量化加速。另外输入分辨率从 640 降到 416 可以提速约 40%但小物体检测精度会下降垃圾分类场景里瓶盖、电池这类小目标要谨慎降分辨率。5. 垃圾分类识别落地避坑五条血泪经验5.1 标注不一致导致模型学偏现象训练 loss 正常下降但验证集 mAP 卡在 0.5 上不去混淆矩阵里某些类别互相混。原因多人标注时标准不统一。比如塑料瓶有人标整个瓶身有人只标瓶盖纸箱有人标完整外框有人只标有字的一面。模型看到同一类物体有完全不同的框自然学不好。解决标注前先定规范文档明确每个类别的标注边界。标注完成后抽 10% 做交叉检查IoU 低于 0.5 的框要重新标。如果已经训了一轮发现这个问题别急着调参先把标注修干净再训。5.2 类别不平衡导致小类召回率极低现象整体 mAP 看起来还行但「有害垃圾」这类样本少的类别召回率不到 0.3。原因YOLOv8 默认的损失函数对类别不平衡没有特殊处理样本少的类梯度贡献小模型倾向于忽略。解决三个方案按优先级排——一是数据层面过采样小类把「有害垃圾」的图片复制多份注意要做不同的数据增强不能简单复制二是用cls_pw参数给类别加权值设为多数类样本数除以少数类样本数三是改用 Focal Loss 替换默认的 BCE Loss但需要改源码改动较大。5.3 数据增强过度导致训练不收敛现象训练 loss 震荡剧烈mAP 忽高忽低甚至出现 NaN。原因Mosaic 和 Mixup 同时开太高概率或者mosaic1.0加上mixup0.5生成的图片语义混乱模型学不到有效特征。解决Mosaic 保持 1.0 没问题但 Mixup 建议从 0.1 开始试不要超过 0.3。如果数据集本身已经很大超过 1 万张Mosaic 可以降到 0.5。另外copy_paste在检测任务里不要开那是给分割用的。5.4 导出 ONNX 后精度下降现象PyTorch 模型 mAP 0.9导出 ONNX 后用 onnxruntime 推理 mAP 掉到 0.7。原因通常是 opset 版本不匹配或者某些算子导出时被简化掉了。比如 SiLU 激活函数在低版本 opset 里不支持会被替换成近似实现。解决导出时指定opset12或更高加simplifyTrue让 Ultralytics 自动做图优化。导出后用 Netron 对比 PyTorch 和 ONNX 的结构看有没有算子被替换。如果还是掉点试试dynamicFalse固定输入尺寸动态轴有时候会引入误差。5.5 RK3588 量化后精度暴跌现象ONNX 模型在 PC 上 mAP 0.88转 RKNN 做 int8 量化后 mAP 掉到 0.6。原因int8 量化对激活值范围敏感垃圾分类场景里颜色和纹理特征丰富量化误差累积后分类头先崩。解决一是校准集要覆盖所有类别和光照条件不能只用几十张图二是改用混合量化把分类头的前几层和最后几层保持 fp16三是如果精度还是不行放弃 int8用 fp16 推理延迟会高一些但精度有保障。RK3588 的 NPU 对 fp16 支持也还行实测延迟增加约 30%。6. 从训练到产线用 TensorRT 加速和置信度后处理把误检压下去模型训好、部署跑通之后真正决定能不能上产线的往往是后处理。垃圾分类场景里误检的代价很高——把塑料瓶识别成有害垃圾后续分拣线要停机人工干预。我一般会在推理端加两层过滤第一层是置信度阈值第二层是类别特定的 NMS 策略。置信度阈值不要全局用一个值。我的做法是给每个类别单独设阈值可回收物 0.45厨余垃圾 0.5有害垃圾 0.6其他垃圾 0.4。有害垃圾阈值最高因为误检代价最大。这个阈值不是拍脑袋定的是在验证集上画 P-R 曲线找 F1 分数最高的点。NMS 的 IoU 阈值默认是 0.7但在垃圾堆叠场景里两个物体挨得很近时会被误抑制。可以降到 0.50.6让重叠的框保留更多。如果用的是 TensorRT 加速NMS 可以放到 GPU 上做用EfficientNMS_TRT插件比 CPU 后处理快 510 倍。TensorRT 加速的完整流程# 1. 导出 ONNX前面已经做过 yolo export modelbest.pt formatonnx opset12 simplifyTrue # 2. 用 trtexec 转 TensorRT 引擎FP16 模式 trtexec --onnxbest.onnx \ --saveEnginebest_fp16.engine \ --fp16 \ --workspace4096 \ --minShapesimages:1x3x640x640 \ --optShapesimages:1x3x640x640 \ --maxShapesimages:4x3x640x640 # 3. Python 推理调用import tensorrt as trt import pycuda.driver as cuda import numpy as np class TRTInference: def __init__(self, engine_path): self.logger trt.Logger(trt.Logger.WARNING) with open(engine_path, rb) as f: self.engine trt.Runtime(self.logger).deserialize_cuda_engine(f.read()) self.context self.engine.create_execution_context() self.stream cuda.Stream() def infer(self, input_np): input_np: 预处理后的 NCHW float32 数组 # 分配显存、拷贝输入、执行推理、取回输出 # 具体绑定逻辑根据引擎的 binding 名称调整 pass # 使用示例预处理 - 推理 - 后处理置信度过滤 NMSTensorRT 引擎的绑定名称和输出布局跟导出时的配置有关建议先用trtexec --onnxbest.onnx --dumpLayerInfo看一下输出层的名字和维度。后处理里的框解码要注意YOLOv8 的输出是[batch, 4nc, num_anchors]需要转置后再做解码别搞反了。最后说一个我踩过的坑TensorRT 引擎和硬件绑定在 GTX1660Ti 上生成的 engine 不能直接拿到 Orin 上用必须重新转。如果产线有多台不同型号的设备建议在每台设备上单独生成引擎或者用 ONNX 作为中间格式在设备端首次运行时自动转换。这个流程虽然多一步但省去了版本不匹配的玄学问题。希望帮到你。本文还有配套的精品资源点击获取