☰
可回收废物检测数据集:从YOLOv5到YOLOv8的训练实战与避坑指南
2026/10/10 20:17:03 网站建设 项目流程

简介:面向YOLO系列目标检测开发者,这份可回收废物检测数据集涵盖玻璃瓶、纸瓶、塑料瓶、塑料袋四类常见废弃物,包含完整标注与训练/验证集划分,可直接用于yolov5至yolo11等主流版本模型的训练与效果验证。压缩包约230MB,共2000个标注文件,VOC格式xml与YOLO格式txt并存,分别置于独立文件夹,坐标均按图像归一化处理,满足不同框架的读取习惯。数据集图像总量达6000张,覆盖室内外多种场景,可支撑垃圾分类、智能回收终端等落地项目的模型迭代。目前已有47人学习下载,适合需要高质量真实样本进行算法调优的研究者与工程师,省去自行采集和标注的时间成本,快速验证模型在可回收物分类场景下的表现。

1. 可回收废物检测数据集:6000张图够不够训练一个能上线的模型

先说结论:6000张图对于玻璃瓶、纸瓶、塑料瓶、塑料袋这四类可回收废物来说,不是“够不够”的问题,而是“能训练到多稳定”的问题。只要标签质量没问题、背景足够多样,用yolov5或yolov8从零训练,mAP@0.5做到0.9以上是正常水平,放到实际分拣场景里跑个实时检测完全够用。这个数据集我拆完后的第一印象是:它已经划分好了train/val/test,两种标签格式(yolo的txt和voc的xml)都齐全,等于省掉了数据准备阶段最烦人的两步——标注转换和数据集划分。刚接触yolo系列算法的朋友可以直接拿它练手,做毕设、做课程设计、做垃圾分类原型都合适;有经验的工程师则可以把重点放在训练参数调优和模型部署上,不用在数据清洗上浪费时间。

2. 数据集的真实构成:标签格式、目录结构与模型选型逻辑

2.1 两种标签格式并存:yolo的txt与voc的xml各自解决什么问题

这个数据集最值得说的不是6000张图的规模,而是它同时提供了两种标签格式。项目里的xml文件是典型的Pascal VOC标注,文件名像 img_067_686.xml、img_067_3869.xml 这样,按图片文件名一一对应。xml里记录的是完整的目标框信息,包括图片尺寸、目标类别名、bndbox的原始像素坐标。这种格式的好处是“人类可读”,用labelImg这类标注工具打开就能继续编辑,适合做二次标注或者人工校验。

txt文件则直接是yolo训练时吃的格式,每一行对应一个目标框,五个数字分别是类别索引、中心点x、中心点y、框宽、框高,全部是相对于图片宽高的归一化比例值,范围0到1。这种格式是yolo系列算法统一要求的输入格式,yolov5、yolov7、yolov8、yolov9、yolov10、yolo11全部通用,不需要转换,解压之后放进数据目录就能开训。

两种格式并存的意义在于互补:训练时用txt,因为训练代码读取效率高、不涉及坐标转换;人工核对或者可视化调试时用xml,因为能看到“这个框是猫还是狗”的文本描述,而不只是数字。常见做法是先用xml做校验,确认无误后用转换脚本批量生成txt。这个数据集已经把两边都给你准备好了,省掉了最容易出错的一步——手工转换时把归一化坐标算错。

2.2 标注字段逐项拆解:中心点坐标与宽高比例不能搞反

先看yolo格式的txt文件,一行内容的基本结构是:

0 0.514062 0.398148 0.282813 0.271296

这行数字的含义是:目标类别是索引0(对应数据集里排在第一位的类别),目标框中心点位于图片宽度方向的51.4%、高度方向的39.8%处,框宽度占整张图片宽度的28.3%,框高度占整张图片高度的27.1%。训练代码读取时,只会按这个顺序解析,不会帮你判断哪个数字代表什么,所以顺序不能错。

xml文件的bndbox节点里存的是原始像素坐标:

<bndbox> <xmin>263</xmin> <ymin>180</ymin> <xmax>444</xmax> <ymax>326</ymax> </bndbox>

从xml转yolo格式时,核心计算逻辑是这样的:

x_center = (xmin + xmax) / 2 / image_width y_center = (ymin + ymax) / 2 / image_height width = (xmax - xmin) / image_width height = (ymax - ymin) / image_height

这段转换逻辑是最容易翻车的地方。x_center必须用(xmin+xmax)/2求得像素中心点后再除以图片宽度,width直接用(xmax-xmin)除以图片宽度。很多新手会把x_center写成xmin / image_width,或者忘记除以图片宽高,导致训练出来的模型预测框全部偏在图片左上角。我每次拿到新的标注数据都先写个脚本抽查十几行txt,对应到原图上画框验证,确认没算错才敢开训。

2.3 目录结构与类别顺序:为什么拿到就能直接用而不只是噱头

数据集的目录划分是直接对标yolo训练规范的,我拆包后看到的目录结构基本是:

dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ (txt格式) │ ├── train/ │ ├── val/ │ └── test/ ├── voc_xml/ (xml格式) │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt └── dataset.yaml

train/val/test三个子目录已经按比例切好,不用再写脚本去random拆分。训练前只需要确认一件事:xml里object的name字段和txt里类别索引的对应顺序是否一致。比如xml里写的是glass_bottle,如果它在类别列表里排第0位,那txt里对应就是0;paper_carton排第1位,txt里就是1。这个对应关系一旦错位,模型训练过程不会报错,但预测结果会张冠李戴——检测到玻璃瓶却显示成塑料瓶,这类错位问题在训练阶段不会暴露,验证集里才看得出来。

关于模型选型,我的建议是:当前数据规模用yolov5s或yolov8n起步就够了,6000张图四分类不算大,不需要一上来就上yolov5x或yolo11x这种大模型。深度越大的模型在这个量级的数据上容易过拟合,训练时间翻倍,收益却很小。先把小模型跑到收敛,确认数据没问题,再根据需要换大模型或者做剪枝,这个思路更稳妥。

3. 用yolov5把数据集跑起来:环境准备到训练完成的全流程

3.1 环境准备与文件清单核对:少一个labels子目录都白搭

先假设你用的是yolov5官方仓库。完整训练流程的第一步不是装环境,而是核对文件。解压之后先确认images和labels两个目录下的train/val/test子目录齐全,再检查每一张jpg或png图片都能找到对应的txt标签文件。检查脚本不用写太复杂,一条bash命令的事:

for img in images/train/*.jpg; do base=$(basename "$img" .jpg) if [ ! -f "labels/train/$base.txt" ]; then echo "Missing label for $img" fi done

这段脚本做的事情是:遍历images/train目录下每张jpg图片,提取不带扩展名的文件名,去labels/train目录找同名txt标签文件,找不到就打印提醒。跑完之后没有任何输出,说明图片和标签是一一对应的,可以放心继续。做完这一遍我还会抽查五六个txt文件,确认里面不是空文件。空标签会让yolo训练时忽略对应图片,但这种忽略是“软忽略”,不会报错,只会让你实际参与训练的图片变少,模型泛化能力打折扣。

安装依赖时注意一点:yolov5仓库的requirements.txt里锁定的torch版本比较老,如果你的机器是新的CUDA环境,建议直接装新版torch再装其他依赖,避免torch版本冲突导致模型训练时GPU利用率上不去或者报CUDA初始化错误。

3.2 数据集配置文件与训练参数设置:yaml文件决定了这次训练的对错

yolov5训练前需要准备一个data.yaml文件,这个文件告诉训练代码去哪里读图、标签有哪几类。内容如下:

train: ./dataset/images/train val: ./dataset/images/val test: ./dataset/images/test nc: 4 names: ['glass_bottle', 'paper_carton', 'plastic_bottle', 'plastic_bag']

train、val、test三个路径指向图片目录,yolo会自动在相同路径下把images替换成labels来定位txt标签。nc必须和names列表长度一致,这个数据集是四类,所以nc填4。names的顺序就是类别索引顺序,第0个名字对应txt里所有类别索引为0的目标。如果你把names顺序写错,比如把plastic_bag放到第0位,那么训练出来的模型会把所有玻璃瓶都识别成塑料袋,而且loss值照样降得很漂亮——这个错不看混淆矩阵基本发现不了。

训练命令根据你的机器显存来调整参数:

python train.py --img 640 --batch 16 --epochs 150 --data dataset.yaml --weights yolov5s.pt --name recyclable_run

参数含义:--img 640表示训练输入图片尺寸缩放为640x640,这是速度和精度之间的常用平衡点;--batch 16是每批训练的图片数量,取决于显存大小,8GB显存跑16张640x640图片比较极限,不够就降到8或4;--epochs 150是训练轮数,这个数据量下100轮基本收敛,150轮是为了看透loss曲线的尾巴;--weights yolov5s.pt是从预训练权重开始迁移学习,不指定的话就完全从零训练,收敛速度会明显更慢。跑起来之后盯着loss曲线看就行,train和val两条曲线都逐渐下降并趋于平稳就是正常的。

3.3 训练验证与测试:从weights到实际检测效果的最后一段路

训练结束后,yolov5会在runs/train/recyclable_run目录下生成best.pt和last.pt两个权重文件。best.pt是验证集上mAP最高的权重,last.pt是最后一个epoch保存的权重,实际部署时只用best.pt。先用验证集看一眼模型效果:

python val.py --data dataset.yaml --weights runs/train/recyclable_run/weights/best.pt --img 640

val.py会输出各类别的precision、recall和mAP@0.5、mAP@0.5:0.95两个核心指标。对四分类回收废物检测来说,mAP@0.5超过0.9算合格,超过0.95说明数据质量和训练都到位了。mAP@0.5:0.95到0.7以上说明框的定位精度不错,这个指标本身比较苛刻,過度追求会逼着加大模型或者调高IoU阈值,实际部署时意义不大。

最后拿一张没参与训练的真实照片做推理测试:

python detect.py --weights runs/train/recyclable_run/weights/best.pt --source test_image.jpg --conf-thres 0.4

--conf-thres 0.4表示只有置信度超过40%的预测框才会被画在输出图片上。如果检测结果里出现大量框在目标物上但置信度只有0.1、0.2的情况,说明模型没学透,优先检查数据集本身的问题,而不是调低阈值硬撑。

4. 从yolov5迁移到yolov8:换模型不换数据的关键调整

4.1 yolov8的目录与格式要求:结构没变但细节有差异

yolov8训练时对数据目录结构的要求跟yolov5几乎一模一样,同样是images和labels两个顶层目录,train/val/test分开,txt标签格式完全相同。也就是说这个数据集解压后不需要做任何转换,直接就能喂给yolov8。但有几个细节差异必须知道。

第一个差异是yaml配置文件里的类别列表格式略有不同,yolov8对names部分的要求更严格,推荐写成字典形式:

path: ./dataset train: images/train val: images/val test: images/test nc: 4 names: 0: glass_bottle 1: paper_carton 2: plastic_bottle 3: plastic_bag

我建议大家如果要用yolov8,就把yaml改写成这种格式。这样names后面的数字索引就和txt里的类别索引完全显式对应了,排查类别错位问题的时候一眼就能看出来。第二个差异是yolov8内部自动做了mosaic增强等预处理,不需要手动配置,epochs和batch参数直接写在命令行里,整体更简洁。

4.2 yolov8训练命令与参数详解:命令行比配置文件更直接

yolov8的CLI训练命令不需要写python脚本,直接一行搞定:

yolo detect train data=recyclable.yaml model=yolov8n.pt epochs=150 batch=16 imgsz=640 device=0

几个关键参数说明:model=yolov8n.pt是nano版本预训练权重,参数最少、推理最快,适合在6000张图这个量级上先行验证;想追求更高精度可以换成yolov8s.pt或yolov8m.pt,但在这个数据量上提升有限,训练时间却会成倍增加。device=0指定用第一块GPU训练,没有GPU就填cpu,但训练速度会慢几十倍,400张图的epoch跑起来会很煎熬。

训练过程中yolov8会在控制台实时打印每个epoch的box_loss、cls_loss、dfl_loss以及precision、recall、mAP这几个指标。它的loss曲线变化趋势和yolov5不太一样,yolov8的cls_loss下降得更快,因为分类分支的损失权重设计不同,看到类别损失前20个epoch就降得很低不要慌,这不是bug。训练结束后权重保存在runs/detect/train/weights/best.pt,用下面的命令验证:

yolo detect val data=recyclable.yaml model=runs/detect/train/weights/best.pt batch=16

yolov8的val命令会自动输出混淆矩阵和PR曲线到runs/detect/val目录,打开confusion_matrix.png看一眼就能确认类别是否有错位。对四分类数据集正常情况是主对角线四个格子颜色最深,其余位置接近黑色。如果发现某一列有明显亮块,说明这个类别的样本被大量误判成了其他类,然后回到标注数据里检查该类别的框有没有标错。

4.3 导出部署格式:从yolov8权重到onnx再到实际项目集成

训练完模型的下一步常规操作是导出成onnx格式,方便后续接入TensorRT或者OpenCV DNN部署。yolo格式的txt标签和yolov8导出的模型完全兼容,不需要再处理标注。

yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=640

导出后可以用onnxruntime在Python里做推理测试,不依赖yolo框架。如果导出时报错提示opset版本不支持,加上opset=12参数重试。onnx是部署环节的中间态,用它接后端服务或者嵌入式设备都很方便,这也是工业落地时最常见的做法。

5. 避坑手册:标签错乱、类别遗漏与训练异常的排查记录

5.1 xml和txt坐标对不上,可视化画框偏到角落

现象:用脚本把txt标注画到原图上,发现检测框的位置明显不对,有些框跑到图片左上角,有些框大小异常。原因:xml转txt时没有按图片实际宽高做归一化,或者转换公式里(xmax-xmin)和(xmin+xmax)/2用反了。解决:写个python脚本读取原图尺寸,按2.2节列出的公式重新计算一遍,然后把新生成的txt覆盖到labels目录。我在处理别的数据集时遇到过更隐蔽的情况,图片尺寸在标注后被批量缩放,但xml里的像素坐标没同步更新,这种只能重新转。

5.2 训练日志提示图片和标签数量不匹配

现象:训练启动时控制台打印的图片数量比标签数量多几百张,或者反过来。原因:images目录下存在非图片文件;或者标注过程中有些图片漏标了,但文件被yolo框架忽略处理了。一般是先检查images和labels两个目录下的basename集合是否完全一致。用下面的命令直接找出差异:

diff <(ls images/train | sed 's/\.[^.]*$//' | sort) <(ls labels/train | sed 's/\.[^.]*$//' | sort)

这个命令先用sed去掉扩展名,再排序,最后用diff比较两边差异。有输出就按输出结果补齐或删除多余文件,没输出说明数量是匹配的。平时训练任何数据集我都会在开始前跑这一遍,这属于最基础的自检动作。

5.3 混淆矩阵里某一列或某一行特别亮

现象:模型训练完成,mAP指标也正常,但混淆矩阵显示某个类别被大面积误判成另一个类别。原因:两个类别之间标注边界严重重叠,或者目标本身外观太接近。最常见的具体原因是塑料瓶和玻璃瓶两种目标在图片里都是透明或半透明的,标注员把框画得过大,把背景也圈进去了,导致模型分不清两个类别的真实特征。解决:先可视化抽查这些类别的标注框,如果框确实包含大量背景,把标注框收紧重新训练。如果检查后发现标注没问题,就要考虑从数据层面增加这些目标的特写截图,或者把这几个混淆严重的类别的loss权重调高一些。

5.4 loss曲线不下降或训练早期出现NaN

现象:训练进行到第20个epoch,box_loss还在3以上,cls_loss几乎没有变化,或者loss直接变成NaN导致训练中断。原因:学习率设置过高、batch size太小导致梯度震荡、图片中存在全黑或全白样本干扰归一化、标签文件里出现超出0到1范围的坐标值。先说一套最直接的排查流程,先用下面命令检查标签数据合法性:

awk '{if ($2<0 || $2>1 || $3<0 || $3>1 || $4<0 || $4>1 || $5<0 || $5>1) print $0}' labels/train/*.txt

awk命令会遍历所有txt标签,找出任何一个坐标值越界的行并打印出来。这条命令有输出说明标签数据确实有问题,把那行对应的图片找出来重新标注即可。如果标签数据没问题,就检查训练初始学习率,yolov5默认0.01对大多数情况都适用,但如果你用的是更大batch size,建议按比例把学习率降到0.005左右再试。NaN问题常见于使用fp16训练时,如果确认数据没问题,加一句--no-half参数强制用fp32精度训练,能稳定很多。

5.5 验证集mAP为0或验证时类别数不匹配

现象:训练过程一切正常,val.py跑完之后打印的mAP全是0,或者直接报错说类别数量对不上。原因:data.yaml里的nc和names数量不一致,或者验证集的label文件里出现了训练时没见过的类别索引。最典型的例子是标签文件里混入了类别索引5,但data.yaml里只定义了0到3四类。解决方法是先运行下面的命令找出所有可能超范围的标签:

grep -E '^[^4-9] ' labels/val/*.txt || echo "all labels within range"

这个命令的逻辑是匹配行首数字大于4的标签行。如果输出内容就说明val目录下有非法类别索引。此类错误通常是个别图片标注时用错了类别Id,找到对应txt文件修改后重新训练。如果不想重新训练,也可以直接在data.yaml里把names列表补足到索引5,但这种做法会导致新类和原有类别共用同一个权重分支,部署时预测结果混乱,不建议这样处理。

6. 数据集质量的检验技巧:从图片样本到mAP曲线的自检方法

拿到数据集后不要急着开训,先花一两个小时把所有图像按类别随机抽出来,用python画一批可视化图,直接目测一遍标注框和真实物体的贴合程度。我的习惯是每个类别随机抽200张图,把框画出来存成一个拼图文件,从头翻一遍。这一步看起来土,但暴露问题最快——标注框是否偏大、是否有漏标目标、类别是否有标错的,肉眼一目了然。这个过程还能顺手验证txt标签的坐标是否和xml保持一致,一举两得。

训练完成之后做二次验证,标准动作是从不方便公开的场景里挑几张新的未标注图片,用训练好的模型跑一遍推理,看检测框的置信度和位置是否稳定。然后进一步做抗干扰测试。

第三步验证的是模型的稳定性,正常安排是拿测试集跑一组不同置信度阈值下的指标。yolo框架训练完默认用conf-thres 0.25做验证,但实际部署时阈值往往要调高。分别用0.25、0.4、0.5、0.6跑一遍测试集,对比precision和recall的变化曲线。阈值升高时precision会上升、recall会下降,找到一个平衡点是部署调参的关键动作。如果阈值从0.25升到0.5时recall断崖式下跌,说明模型对目标特征的学习还不够充分,优先回到数据层面补强而不是硬调阈值。从那次之后我每次拿到新数据集,都强制自己先走一遍上面说的流程,跑完才敢决定要不要继续往下训练或部署。很多翻车现场都发生在“看着指标不错,一上真实场景就崩”的瞬间,前期的数据质量检查能帮你避开大部分这种尴尬。希望这些经验能帮你在自己的项目里少走一段弯路。

本文还有配套的精品资源,点击获取

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

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

立即咨询