简介面向垃圾分类与智慧城市场景的YOLOV5实战数据集包含满溢垃圾桶、未满溢垃圾桶和垃圾三个类别共3349张已标注图像其中训练集2680张、验证集669张标签均为txt格式适合目标检测初学者及项目开发者直接训练和迁移学习。资源共2000个文件以txt标注、py训练脚本、yaml模型配置、sh辅助脚本和md说明文档为主压缩包约450MB内含完整代码、数据集及训练好的权重参数经测试可直接使用。项目已迭代100个epoch最佳精度达到map0.50.91、map0.5:0.950.73runs目录下还保存了验证集混淆矩阵、PR曲线、F1曲线及全部推理结果便于复盘与调试。目前已有363人学习下载对于需要快速搭建垃圾桶满溢检测方案的研究者来说是一份开箱即用的实践参考。1. 垃圾桶满溢检测数据集3类别到底解决什么问题城市环卫、商场物业、园区巡逻每天都要面对同一个问题垃圾桶到底满没满。靠人工巡检要么跑得太勤浪费人力要么跑得不够勤导致垃圾溢出、异味扩散。用 YOLOv5 做垃圾桶满溢检测本质是把“桶有没有满”从人工判断变成视频画面里的自动识别。这个数据集包含 3 个类别常见做法是按“未满 / 半满 / 满溢”划分也就是 not_full、half_full、overflow 三个状态。数据集的价值不只是给 YOLOv5 当燃料它直接决定模型对“满溢”的敏感度以及误报率能不能压到可接受范围。适合正在做智慧环卫、智能楼宇、园区安防的算法工程师也适合想用 YOLOv5 训练自己数据集的学生。一个反直觉的经验是这个项目里最难的不是训练模型而是把“满溢”的标注边界定清楚。2. 攒自己的垃圾桶满溢数据集3 个类别怎么定、怎么拍、怎么标数据集质量决定模型天花板。这一章把采集、标注、划分的关键点一次说清这些工作在训练之前做省下的时间远大于你花在标注上的精力。2.1 三个类别先定标签边界满溢不是“垃圾多”很多第一次做的人把类别写成 empty / full 两个实际部署时会发现“半满”状态出现的频率极高两分类会把半满硬分到某一边导致大量误报。三类划分是更稳的落地方案因为清运决策本身就分三档不用管、可以再等等、必须现在清。三个类别的判断标准如下表所示。类别 ID类别名判断标准典型画面0not_full垃圾低于桶口桶内可见明显空隙桶内壁清晰垃圾量少1half_full垃圾接近桶口但未超出桶口平面袋口高于桶内桶盖仍可盖上2overflow垃圾超出桶口平面或桶外有明显散落物袋口突出、盖子盖不上、桶边有散落垃圾关键点在于标注标准要以“清运决策”为准。满溢的判断标准是“要不要派人来清运”而不是“垃圾多不多”。垃圾堆到桶口但还能盖上盖子就定义成 half_full一旦袋口超出桶口平面或桶边出现散落垃圾必须归为 overflow。前后标注不一致会让模型在 half_full 和 overflow 之间摇摆训练完看混淆矩阵会是一片乱。实际项目里翻车率最高的环节不在训练而在标注阶段把同一桶的相似画面标成不同类别。我建议在动手标注前写一页标注规范文档配三张示例图让每个参与标注的人先看一遍再动手。标注过程中碰到边界情况按文档执行不要临时发挥。2.2 采集视角与光线让数据贴近摄像头真实部署位先定视角。常见部署位是监控杆或墙面支架摄像头斜向下 40~60 度俯拍桶口而不是平视。采集时按这个视角拍如果只拿手机平拍一堆桶训练出来的模型在俯拍画面里会认不出桶口特征。我一般会先确定摄像头安装高度和角度再采集或者在现场先拍一段视频再抽帧。再定光线。垃圾桶部署场景分室内和室外。室内的走廊、茶水间光线相对稳定室外的园区、路边则有正午强光和夜间局部路灯的差异。YOLOv5 自带的 HSV 增强能缓解一部分亮度差异但解决不了“夜间只有一盏路灯照明一侧亮一侧全黑”这种极端情况。常见做法是白天和夜间各采集一批夜间画面单独分组加入训练集。视频抽帧时不要连续抽相邻帧否则大量高度相似的画面会让 train 和 val 分布过于接近验证结果虚高。我一般每隔 6 帧抽一帧抽完后人工筛掉运动模糊和大幅遮挡的画面。用 ffmpeg 抽帧# 从现场视频每 6 帧抽一帧输出到 frames 目录q:v 2 保证输出质量接近原视频 ffmpeg -i site_2024_11_02.mp4 -vf selectnot(mod(n\,6)) -q:v 2 frames/%04d.jpg参数说明select滤镜里的mod(n,6)表示帧号对 6 取模为 0 时选中也就是每 6 帧取一帧。q:v 2控制输出 JPEG 质量数值越小质量越高2 已经足够后续标注使用。每个点位抽 200~400 张不是越多越好画面多样性比数量更重要。起步量参考三类各 800~1200 张左右可以开始第一轮训练。不要一上来就想标几千张先跑一轮看每类的 AP再针对表现差的类别补数据比一次性标完更省时间。2.3 标注实操用 LabelImg 标注并导出 YOLO 格式YOLO 格式训练首选 LabelImg因为它直接输出每个类别对应的 txt 文件不需要再做格式转换。安装时建议放在独立 conda 环境里避免和后面的训练环境互相污染。# 创建独立环境安装 LabelImgPython 3.9 下比较稳 conda create -n labelimg python3.9 -y conda activate labelimg pip install labelimg labelimg安装完成后打开工具先确认输出格式为 YOLO再设置类别名。标注时有个容易踩的坑bounding box 要包含垃圾本身的轮廓而不是整个垃圾桶。因为满溢检测关心的是“垃圾是否高出桶口”如果框住整个桶模型学到的是桶的轮廓对桶口处垃圾高度的变化完全不敏感。overflow 类别的框尤其要贴住突出的袋口和散落物宁可稍微放大一点包含边缘也不要框得比垃圾还小。导出后的标注格式是每张图一个 txt内容如下2 0.453125 0.318750 0.214062 0.293750每行五个值类别 ID、归一化后的中心点 x、中心点 y、宽度、高度。全部是 0~1 浮点数不需要再做额外处理。2.4 清洗、划分与文件组织训练前最后的检查标注完成后把所有图片和 txt 分别放进 dataset/images 和 dataset/labels 两个目录然后按 8:2 划分 train 和 val。YOLOv5 的 data.yaml 里 train 和 val 指向目录训练时自动去同级的 labels 目录找对应标签。划分脚本如下import random import shutil from pathlib import Path IMAGES Path(dataset/images) LABELS Path(dataset/labels) TRAIN Path(dataset/train) VAL Path(dataset/val) random.seed(42) imgs sorted(IMAGES.glob(*.jpg)) random.shuffle(imgs) val_count int(len(imgs) * 0.2) for idx, img in enumerate(imgs): label LABELS / (img.stem .txt) if not label.exists(): print(f[跳过] {img.name} 没有对应标签) continue dest VAL if idx val_count else TRAIN dest_img dest / images / img.name dest_lbl dest / labels / (img.stem .txt) dest_img.parent.mkdir(parentsTrue, exist_okTrue) dest_lbl.parent.mkdir(parentsTrue, exist_okTrue) shutil.move(str(img), str(dest_img)) shutil.move(str(label), str(dest_lbl))逻辑说明先把图片列表随机打乱按 20% 的比例切出 val 集。val_count int(len(imgs) * 0.2)控制验证集大小1000 张图就是 200 张。random.seed(42)固定随机种子保证每次运行划分结果一致这样不同实验之间才有可比性。脚本用shutil.move而不是copy原始目录里不会残留重复文件避免训练时同一份数据被统计两次。运行划分前建议先跑一个检查统计每个类别的框数量防止某个类别只有十几张。在 labels 目录下执行# 统计 dataset/labels 里所有 txt 中每个类别 ID 出现的次数 find dataset/labels -name *.txt -exec cat {} \; | awk {print $1} | sort | uniq -c输出结果会显示 0、1、2 三个 ID 各自的实例数量。如果某个类别明显偏少先补数据再训练这个顺序不要反。3. 用 YOLOv5 训练自己的垃圾桶满溢数据集环境、命令与参数数据准备好之后进入训练阶段。这一章覆盖环境配置、data.yaml 编写、训练命令以及几个最常改的超参数。照着跑能复现按自己的数据量改参数也能跑通。3.1 conda 环境配置与 YOLOv5 源码准备YOLOv5 的训练入口是 train.py先拉源码再装依赖。常见做法是从官方仓库 clone固定一个 commit 或版本 tag不要每次都用最新的 main 分支避免依赖变动导致训练结果不可复现。git clone https://github.com/ultralytics/yolov5 cd yolov5 conda create -n yolov5 python3.8 -y conda activate yolov5 pip install -r requirements.txt python -c import torch; print(torch.__version__, torch.cuda.is_available())requirements.txt 会自动安装 torch 和 torchvision。最后一行验证 torch 装没装对会打印版本号和 CUDA 是否可用。如果cuda.is_available()返回 False说明本机 CUDA 版本与默认安装的 torch 不匹配。常见做法是先去 PyPI 查对应 CUDA 版本的 torch 安装命令再手动 pip 安装例如 CUDA 11.8 对应 cu118 系列。这条路属于 yolov5 环境配置里最常踩的坑而且报错信息往往不直观多半是在 import torch 后才发现 GPU 用不了。提示pip 安装 torch 前先确认 nvidia-smi 里的 CUDA 版本再按版本选择安装命令。不要混用 conda-forge 和 pip 的 PyTorch 包环境不干净会带来大量难查的报错。环境装好后建议先跑一次内置的 detect.py 官方预训练权重把模型下载和推理链路先通一遍再回来训练自己的数据。这样后面训练报错时能先排除环境问题不用对着报错信息猜黑匣子。3.2 准备 data.yaml 与首次校验YOLOv5 用 data.yaml 描述数据集路径和类别。垃圾桶满溢检测的 data.yaml 如下# data/trash_bin.yaml train: ../dataset/train/images val: ../dataset/val/images nc: 3 names: 0: not_full 1: half_full 2: overflow关键说明train 和 val 指向 images 目录YOLOv5 会自动去同级的 labels 目录找标注文件。路径建议写相对当前工作目录的相对路径写成绝对路径容易在换机器后失效。nc必须和names的条目数一致3 个类别就写 3。names的顺序必须和标注阶段使用的 ID 一致。标注时把 overflow 放在 ID 2data.yaml 里也必须保持一致。如果这里写乱训练不会报错但验证集的混淆矩阵会告诉你模型被教坏了。这种错位是最难排查的错误类型因为 loss 曲线看起来一切正常只有分析推理结果时才发现类别全错位了。第一次训练前建议先跑一个 epoch 做数据校验python train.py --data data/trash_bin.yaml --epochs 1 --weights yolov5s.pt跑一个 epoch 的目的是验证数据读取、标签解析、缓存生成都没问题。这一步如果报“label 格式错误”或“找不到图片”说明数据准备环节有遗漏趁早回去查数据别等正式训练跑了几小时才发现。3.3 跑通训练命令从预训练权重迁移学习正式训练命令python train.py \ --data data/trash_bin.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --project runs/train \ --name trash_bin_v1逻辑说明--weights yolov5s.pt用的是 COCO 预训练权重里面已经包含大量瓶、杯、袋等常见垃圾物的底层特征迁移到满溢检测上能大幅缩短收敛时间不要从随机权重开始训练。--img 640是输入分辨率垃圾桶满溢检测属于中尺寸目标640 够用不需要上 1280 给显存增压。--batch 16在 8G 显存配合 s 模型时刚好能跑。参数说明--project和--name控制输出目录每次实验用独立的--name后面比较权重时才不会互相覆盖。--device 0指定第一块 GPU只有 CPU 的机器改成--device cpu但要接受训练速度慢一个量级100 个 epoch 可能要跑一天。训练过程中终端会打印每轮的 mAP、loss 和当前进度。不要只看 loss 下降迁移学习初期的 box_loss 会有一个先上升再下降的过程这是正常现象。真正要盯的是 val 集的 mAP0.5它会先快速上升然后变平。如果 80 轮后 mAP0.5 还在缓慢爬升可以把 epoch 加上去继续跑。3.4 训练中的关键超参数与调整手段YOLOv5 支持通过自定义 hyp yaml 覆盖默认超参数。垃圾桶满溢检测常用调整集中在数据增强、翻转、学习率三个方面。自定义文件如下# hyp.trash_bin.yaml lr0: 0.01 lrf: 0.01 mosaic: 0.8 flipud: 0.0 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4flipud: 0.0是最关键的一项。垃圾桶画面上下翻转会产生“桶在天上、垃圾掉到地上”的非法样本这类垂直翻转增强对语义有破坏建议直接关掉。mosaic: 0.8把四张图拼在一起训练对小数据集提升明显保持 0.8 左右即可。lr0是初始学习率用预训练权重时保持默认 0.01不需要像从零训练那样调低。使用方式是在训练命令里加一行python train.py --data data/trash_bin.yaml --hyp hyp.trash_bin.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100如果训练中途中断想恢复实验用--resumepython train.py --resume runs/train/trash_bin_v1/weights/last.pt这个命令会沿用上次实验的数据配置和超参数从 last.pt 继续训练。注意 resume 时不要再传--epochs否则会覆盖原计划。一个容易忽略的点yolov5 超参数里还有anchor相关设置。垃圾桶的宽高比比较固定默认锚框在 COCO 上训练过直接用于垃圾桶检测通常够用。如果你的数据里桶都是长方形立桶可以先跑一轮看 recall如果 recall 低而 precision 高再考虑用--evolve重新进化锚框。这个功能耗时较长数据量不够时意义不大。4. 垃圾桶满溢检测训练与部署避坑5 个必踩的坑训练阶段踩坑很常见。下面几个是我自己在垃圾桶满溢检测项目里真实遇到过的问题每条按现象、原因、解决的顺序写希望能帮你少走弯路。4.1 满溢类别 AP 特别低loss 却很正常现象训练结束后三个类别里 overflow 的 AP 只有 0.3 左右其他两类都在 0.8 以上但总 loss 已经收敛到平稳水平看起来训练很成功。原因loss 是三个类别的加权平均overflow 样本占总数比例低时它对总 loss 的贡献被稀释。模型只要把框往 not_full 方向推一点就能让平均 loss 变好看代价是牺牲了 overflow 的精度。解决先统计三类实例数量数据准备时检查一遍。如果 overflow 明显偏少去现场补拍满溢的桶不要复制粘贴已有的图。目标是把三类实例数量差控制在 1.5 倍以内。补完数据重训通常 mAP 能回到正常水平。另一个辅助手段是在 train.py 里把--cls分类损失权重调高让低样本类别在反向传播时获得更大的梯度但这是治标补数据才是治本。4.2 半满和满溢互相混淆混淆矩阵一片乱现象val 集里 half_full 被识别成 overflow、overflow 被识别成 half_full混淆矩阵非对角线区域聚集了大量错误整体 mAP 被拉到 0.6 以下。原因边界定义不清楚。标注时有的人把垃圾堆积到桶口附近的图标成 overflow有的人标成 half_full。“接近桶口”和“超出桶口”之间没有一条清晰的线模型学到的边界就是乱的。解决重新统一标注规则把判定标准改成“袋口是否超出桶口平面”。超出即 overflow哪怕只超出一点没超出的即使垃圾堆得很高也是 half_full。这条硬性规则能解决 70% 以上的混淆问题。如果重新标注后发现某些图确实难以肉眼判断直接删掉不要让模型学一个连人都无法稳定判断的标签。4.3 多桶并排时靠边的桶漏检严重现象单桶画面一切正常一到三五个桶并排的画面靠左或靠右的桶经常漏检置信度低到阈值以下导致满溢事件漏报。原因训练集中单桶居中画面占比太高模型对画面边缘位置的目标学习不充分。检测模型在特征图上对边缘位置的目标响应天然偏弱如果训练数据里没有足够的边缘样本这个问题会被放大。解决调整训练集构成单桶居中的画面控制在六成以下至少三分之一的图保留多桶并排让模型见过边缘分布的目标。推理时把置信度阈值从默认的 0.25 调到 0.15~0.2。漏检的代价通常比误检高满溢漏了会造成清洁资源浪费误检最多是派人白跑一趟。4.4 GPU 利用率只在 30% 左右训练速度像“玄学”现象nvidia-smi 看到 GPU 利用率只有 20%~30%显存却占了不少训练一个 epoch 的时间比预期长一倍。原因最常见是图片尺寸或 batch 太小GPU 空转等待数据从 CPU 搬运。另一个常见因素是数据加载线程数太少Windows 下还会遇到路径包含中文导致文件 IO 变慢的情况。解决先把--workers从默认的 8 调大到 16 或 32Linux 下有效。第一次训练时缓存生成阶段速度慢是正常的等缓存文件生成后速度会恢复。如果这些都没问题把--batch从 16 调到 32或者把--img从 640 降到 480让 GPU 算力被真正占满。GPU 利用率在数据量只有一两千张时影响不大但往几万张规模走它就是训练吞吐量的主要瓶颈。4.5 白天能检出来夜间或背光场景直接翻车现象白天测试视频表现稳定同一地点晚上路灯照明下垃圾桶几乎全部漏检少部分框出来置信度在 0.15 以下。原因训练集中夜间样本占比过低。YOLOv5 的 HSV 增强只能改变颜色空间没法模拟路灯下局部强光和阴影的对比关系更没法生成夜间特有的色彩偏移。解决补采夜间样本或者对白天样本做亮度扰动。应急手段是把 hyp 里的hsv_v调到 0.7 左右模拟更大范围的亮度变化。更有效的做法是在部署位安装带红外补光的摄像头让夜间画面接近黑白灰度图同时给训练集加一部分灰度图。灰度图训练好后模型对颜色特征不再依赖夜间漏检率能降到和白天同一水平。背光场景的原理相同本质是动态范围问题不是模型结构问题。5. 验证、导出与部署把训练好的模型装进边缘设备训练完成后还要做三件事看指标判断能不能用、导出部署格式、在目标设备上跑通推理。这三步做完模型才算真正落地。5.1 用验证指标判断模型能不能用训练结束后YOLOv5 在 runs/train/trash_bin_v1/ 目录下输出 results.csv、混淆矩阵、PR 曲线等。对垃圾桶满溢检测来说优先看 mAP0.5而不是 mAP0.5:0.95。满溢检测属于单标签状态判断场景IOU 0.5 已经能正确框住目标更高的 IOU 精度对“要不要派人”这个决策没有额外价值。常见标准三类 mAP0.5 在 0.75 以上可以进入试点0.85 以上可以稳定使用。如果某类低于 0.6基本就是数据问题回到第 2 章补样本更有效调参只是浪费时间。验证时不要只看总体 mAP。单独看每一类的 Precision 和 Recall重点盯 overflow 这一行的 Recall。满溢检测里漏报的代价远大于误报所以如果 overflow 的 recall 低于 0.8哪怕 AP 过了 0.85也要先把阈值往下调再评估一轮。另一个容易被忽略的点验证集里要保留一部分训练时没见过的点位画面至少占 10%。如果验证集和训练集来自同一批点位结果会偏乐观部署到新点位时效果会明显打折。5.2 导出 ONNX 与 TorchScript部署格式怎么选训练完成后常见做法是先把 best.pt 导出为 ONNX再转 TensorRT 或在边缘推理框架里加载。YOLOv5 自带 export.pypython export.py \ --weights runs/train/trash_bin_v1/weights/best.pt \ --include onnx \ --img 640 \ --batch 1说明导出 ONNX 的输入尺寸必须和训练时一致否则推理时尺寸不匹配会直接报错或出现坐标偏移。--batch 1是推理部署的标准配置不要用大于 1 的 batch 导出。注意导出 ONNX 时如果用--batch 1后续部署就只能单张推理。如果业务需要批量处理导出时要同时处理动态 batch这部分在部分推理框架里会有额外的配置工作。部署格式选型参考部署端推荐格式说明服务端 GPUTensorRT 或 ONNX吞吐量高适合多路视频流处理树莓派 / JetsonONNX 或 TorchScript兼容性好便于调试纯 CPU 工控机ONNX OpenVINOCPU 推理速度提升明显如果计划在树莓派 5 这类边缘设备上部署自己训练的 YOLOv5 模型我一般先导出 ONNX 用 onnxruntime 跑通确认输出逻辑没问题后再考虑换成更快的方案。导出后一定要用同一张真实场景图分别跑一遍 pth 和 onnx对比输出框是否一致。常见翻车点是 ONNX 的 NMS 输出与原始模型不一致导致坐标偏移或重复框。导出前还有一个小技巧对一张 1280x960 的现场照片分别用 640 和 1280 跑一遍推理如果 1280 下能检出更小的桶而 640 下漏检明显说明场景存在小目标需求导出时可以直接用 1280 尺寸。代价是推理耗时翻倍需要按硬件能力权衡。5.3 最小推理脚本本地跑通一张图用 YOLOv5 自带的 detect.py 是验证效果最快的方式python detect.py \ --weights runs/train/trash_bin_v1/weights/best.pt \ --source test_images/ \ --conf-thres 0.2 \ --iou-thres 0.45 \ --save-txt \ --save-conf说明--source可以是图片目录、单张图片或摄像头地址detect.py 全部支持。--conf-thres沿用第 4 章的低阈值策略垃圾桶满溢检测建议 0.2 起步再根据误报率上下调整。--save-txt输出每个目标的类别和坐标--save-conf把置信度一并写入 txt方便后续做后处理逻辑。detect.py 适合做效果验证集成到业务系统时不推荐直接调用它面向命令行交互不是为嵌入式或服务化设计的。集成场景用 YOLOv5 的 YOLO 类更干净import torch model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/trash_bin_v1/weights/best.pt, force_reloadTrue) results model(test_images/img_001.jpg, size640) for det in results.pandas().xyxy[0].itertuples(): print(det.name, det.confidence, det.xmin, det.ymin, det.xmax, det.ymax)说明torch.hub.load加载的是本地训练好的模型custom模式不需要联网下载额外权重。推理时传入size640对应训练时的输入尺寸。results.pandas()会把检测结果转成 DataFrameitertuples()逐行读取name 是类别名confidence 是置信度后面四个是坐标值可以直接对接业务逻辑。6. 让满溢检测“活”起来连续帧确认再加业务动作模型能检出来只是第一步。真实项目里如果每一帧都把结果上报系统会被误报淹没——一阵风吹动袋口、清洁工路过挡住画面、夜间探照灯扫过都可能让置信度在边缘反复横跳。我现在做这个方向时都会加一层时序确认只有当同一位置的框连续 5 帧以上都达到阈值才触发上报避免单帧抖动造成的假警报。核心逻辑如下from collections import defaultdict # key 对应画面位置value 是连续检出帧数 HISTORY defaultdict(int) def on_frame(detections, frame_id): for det in detections: # 把坐标映射到格子避免摄像头微抖导致同一目标被拆成多个 key key (round(det.xmin / 50), round(det.ymin / 50)) if det.name overflow and det.confidence 0.2: HISTORY[key] 1 if HISTORY[key] 5: notify_cleanup(key, frame_id) HISTORY.pop(key, None) else: HISTORY.pop(key, None)参数调整建议帧数窗口和触发阈值都要配合视频帧率。25 帧的摄像头取 5 帧相当于 0.2 秒确认响应足够快如果是 10 帧的低帧率摄像头建议把窗口降到 3保证“有人经过挡住镜头”这类瞬时遮挡不误报同时又不让满溢事件的响应太慢。置信度 0.2 是配合低阈值策略的设定误报率高的点位可以提到 0.3。这个项目的完整链路做下来最深的体会是数据集标注规范才是决定模型效果的天花板训练参数只是把这份规范兑现成指标。我第一次做的时候在标注上偷了懒类别边界定得很随意结果训练阶段花了两倍时间在补数据、清标签上绕圈。如果你正准备做这个方向先把第 2 章的标注规则定下来再开始采集和训练后面会顺畅很多。希望帮到你。本文还有配套的精品资源点击获取