尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

YOLO垃圾检测数据集实战:VOC/COCO/YOLO标签转换与训练

发布时间:2026/9/28 15:11:09

资讯中心
01
ARTICLE

YOLO垃圾检测数据集实战:VOC/COCO/YOLO标签转换与训练

YOLO垃圾检测数据集实战:VOC/COCO/YOLO标签转换与训练
简介YOLO垃圾目标检测数据集面向目标检测入门与环保场景落地收录1000张真实场景的高质量图片使用LabelImg标注标注框质量可靠。压缩包总文件数为2000个其中包含VOC(xml)、COCO(json)、YOLO(txt)三种格式标签按文件夹分类存放可直接用于YOLO系列模型训练另有py脚本实现训练集、验证集、测试集自定义划分配套yaml配置和html操作文档整体约73.26MB。划分脚本会同步整理图片与标签便于一键生成新目录下的数据集结构。同时提供Windows与Linux下的YOLO环境搭建教程以及修改案例训练自定义数据的思路说明能帮助读者从数据准备、标签格式转换到模型训练跑通完整流程。已有1485人在CSDN浏览学习适合需要真实场景数据集、多格式标签和配套实践指引的开发者。1. 垃圾检测数据集到手先搞清这份资源包里装的是啥做垃圾分类或智慧环卫项目最耗时间的不是训练而是数据准备。YOLO垃圾目标检测数据集这份资源包把常被卡住的环节一次备齐1000张已标注图片对应VOC、COCO、YOLO三种格式标签外加划分脚本和训练教程。它提供的不是一套静态数据而是“原始图片到能出检测结果”的完整流水线。适合谁正在做垃圾分类、智慧环卫项目的从业者或者毕业设计、竞赛里需要快速跑通YOLO检测闭环的学生。对新手教程能省掉翻文档的时间对熟手三格式并存可以直接横向对比YOLO与传统检测框架不用重复造数据轮子。我见过不少翻车案例数据到位后在格式转换和划分上耗掉两三天这套脚本就是用来避开这些坑的。2. 三种标签格式的差异与互相转换VOC的XML、COCO的JSON、YOLO的txt2.1 VOC、COCO、YOLO三种格式到底差在哪先讲一个前提VOC、COCO、YOLO听起来是三种数据集本质是同一份标注信息的三次编码。垃圾检测这套资源给了同一批图片的三套标签我们要做的就是在三套编码之间翻译翻译错一个坐标后面训练和评测全部白做。VOC格式是一个XML文件对应一张图片。根节点annotation下用size子节点记录图片宽高用object节点描述每个目标。object里的bndbox存目标框四个值xmin、ymin、xmax、ymax都是绝对像素坐标表示左上角和右下角name子节点存类别名是字符串。除此之外object里还有difficult字段标记严重遮挡或难以辨认的目标转换成YOLO时这类目标通常直接丢弃提前想清楚比训练时才排查要省事。COCO格式与VOC不同它是用一个JSON文件聚合所有图片标注。顶层分三个数组images记录图片id、file_name、宽高annotations记录每个目标框字段是image_id、category_id、bbox、area、segmentation、iscrowdcategories把类别名映射成数字id。bbox的四个值是[x,y,w,h]x和y是左上角w和h是宽高也是绝对像素坐标。这点和VOC不同转换时不能把x直接当xmin平移。YOLO格式是一张图片一个txt文件每行五个值类别id从0开始、x_center、y_center、w、h后四个全部除以图片宽高做了归一化取值范围理论上在0到1。它不包含图片尺寸转回VOC或COCO时必须重新读原图拿宽高。三种格式的核心差异看下面这张表最直观。格式载体坐标表达类别表达是否记录图片尺寸VOC每图一个XMLxmin,ymin,xmax,ymax像素name字符串是size节点COCO单JSON聚合x,y,w,h像素categories数字id是images字段YOLO每图一个txtcx,cy,w,h归一化行首数字id否格式选型上给Faster R-CNN、Mask R-CNN、MMDetection这类框架用COCO最省心给YOLO系列用txt最直接VOC更适合当中间格式留存因为多数标注软件导出的就是它便于日后重新生成别的格式。2.2 VOC转YOLO最常用的一组转换代码拿到这套资源最常见的需求是把VOC的XML转成YOLO的txt。我一般直接用ElementTree解析不用安装额外依赖脚本放在标签目录旁即可运行。import xml.etree.ElementTree as ET import os # 类别顺序表必须与后续训练yaml的names完全一致 # 下面只是示例请按资源包里的类别说明替换 classes [battery, bottle, can, carton, glass, paper] def voc_to_yolo(xml_path, out_dir): tree ET.parse(xml_path) root tree.getroot() # 从size节点读取原图宽高归一化必须以此为准 img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) base os.path.splitext(os.path.basename(xml_path))[0] lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) x_center ((xmin xmax) / 2.0) / img_w y_center ((ymin ymax) / 2.0) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 边界保护防止个别标注越界污染训练 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w min(w, 1.0) h min(h, 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if lines: with open(os.path.join(out_dir, base .txt), w, encodingutf-8) as f: f.write(\n.join(lines)) os.makedirs(annotations/yolo, exist_okTrue) for xml_file in os.listdir(annotations/voc): if xml_file.endswith(.xml): voc_to_yolo(os.path.join(annotations/voc, xml_file), annotations/yolo)这段代码的核心逻辑是xmin加xmax取平均得到中心点横坐标再除以图片宽框宽等于xmax减xmin再除以图片宽。高方向同理。必须强调一个血泪经验分母用的img_w、img_h一定要来自XML的size节点而不是你脑子里计划训练的imgsz值比如640或416。拿后者归一化txt里的坐标全错训练时mAP直接归零还很难定位原因。另一个关键点是classes列表的顺序。txt第一列填的是classes.index(cls_name)也就是这个list的下标后续data.yaml里names的排列顺序必须和它完全一致否则训练时会出现“看着是瓶子框标签却是电池”的张冠李戴。换顺序等于重转所以第一次转换前就把类别定死。2.3 COCO转YOLO对准annotation的id是关键如果你拿到的是COCO的JSON转换思路和VOC完全不同。JSON里没有逐层嵌套的直观树必须建立两个索引一个是image_id到图片文件名和宽高的映射一个是category_id到连续下标的映射。COCO的class_id往往不是0到n-1的连续值而YOLO要求从0开始连续编号。import json import os def coco_to_yolo(coco_json, out_dir): with open(coco_json, r, encodingutf-8) as f: data json.load(f) img_id2info {} for img in data[images]: path img[file_name] if file_name in img else img[coco_url].split(/)[-1] img_id2info[img[id]] { file_name: path, width: img[width], height: img[height] } cat_id2cls {} for idx, cat in enumerate(data[categories]): cat_id2cls[cat[id]] idx img_id2anns {} for ann in data[annotations]: img_id2anns.setdefault(ann[image_id], []).append(ann) os.makedirs(out_dir, exist_okTrue) for img_id, anns in img_id2anns.items(): info img_id2info[img_id] img_w, img_h info[width], info[height] lines [] for ann in anns: # COCO的bbox是x,y,w,h不是xmin,ymin,xmax,ymax x, y, w, h ann[bbox] x_center (x w / 2.0) / img_w y_center (y h / 2.0) / img_h w_norm w / img_w h_norm h / img_h lines.append( f{cat_id2cls[ann[category_id]]} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f} ) out_txt os.path.join(out_dir, os.path.splitext(info[file_name])[0] .txt) with open(out_txt, w, encodingutf-8) as f: f.write(\n.join(lines))这里最容易踩的坑是bbox语义。COCO的bbox是“左上角x、左上角y、宽w、高h”所以中心点x要用x加上w的一半而不是像VOC那样把两个角相加除以2。另一个容易被忽略的是iscrowd字段标注员在人群、垃圾堆这类密集场景里会把整个簇标成一个iscrowd目标转YOLO前应当过滤掉否则模型会把一堆不规则的垃圾堆整体框住验证集mAP虚高真实场景根本不可用。2.4 转换完成后的三重校验转换代码写得没问题不代表转换结果没问题。我的固定动作是每转一批就做三次快速检查。第一随机抽三张图人工对比一下txt里的坐标是否落在目标位置附近肉眼能直接发现的低级错误比任何脚本都快。第二统计txt文件数量和XML/JSON里“有目标”的图片数量是否一致现实中经常有空图也就是图片存在但没有目标标注这类图不会产生txt必须在划分前剔除。第三写一个全校验脚本扫出所有越界坐标。import os def check_yolo_txt(txt_dir): bad [] total 0 for f in os.listdir(txt_dir): if not f.endswith(.txt): continue with open(os.path.join(txt_dir, f), r, encodingutf-8) as fh: for line in fh: parts line.strip().split() if len(parts) ! 5: bad.append((f, 列数不对)) continue cls_id, cx, cy, w, h parts cx, cy, w, h map(float, (cx, cy, w, h)) total 1 if not (0.0 cx 1.0 and 0.0 w 1.0): bad.append((f, 坐标越界)) if not (0.0 cy 1.0 and 0.0 h 1.0): bad.append((f, 坐标越界)) print(f共 {total} 个目标) print(bad if bad else 全部通过)校验脚本会把越界文件打出来接下来只要按文件名去查对应图片和原始XML就好。大部分越界都出在“用了resize后的尺寸做归一化”这种情况回到2.2的分母重新转一遍就能解决。这十分钟的检查能替你挡住训练环节最磨人的排错时间。3. 划分脚本train/val/test怎么切才靠谱3.1 划分脚本到底在切什么把1000张图按比例切成训练、验证、测试三份逻辑上只需要一个随机数但实际工程里有四个约束条件。第一同一张图不能同时出现在训练集和验证集这是数据泄漏会让模型在验证集上的mAP虚高一上真实场景就现原形。第二图片和配套的YOLO、VOC、COCO三套标签必须保持同一切分图片进了训练集而txt留在原地训练进程直接报找不到标签。第三各类别在每一份里的分布要尽量接近原始分布第四每次跑划分脚本结果要完全一致方便排障复现。这里有个隐藏问题值得单独说不少开源划分脚本会把图片和标签同时移动到train_images、val_images这类子目录再用目录路径表示train和val。这种结构对YOLO没问题但后续要用MMDetection或原生COCO评测时就得自己维护“哪张图属于哪个集合”的清单。我更偏爱列表文件方案图片原地不动额外生成train.txt、val.txt、test.txt三个清单。清单是YOLO生态的原生输入也天然保留了集合归属信息想转回别的框架时有据可查。3.2 一段可以直接改用的划分脚本与资源包同思路的划分脚本思路是这样的先扫描图片目录和标签目录取两者共同存在的文件基名做随机打乱按比例切片最后把图片绝对路径写入对应的txt。import os import random random.seed(42) # 固定种子保证两次运行结果一致 img_dir images yolo_dir annotations/yolo train_ratio, val_ratio 0.8, 0.1 yolo_names { os.path.splitext(f)[0] for f in os.listdir(yolo_dir) if f.endswith(.txt) } all_names [] for f in os.listdir(img_dir): name, ext os.path.splitext(f) # 只保留图片和标签都存在的样本空标签图宁可不要 if name in yolo_names: all_names.append((name, ext)) all_names.sort() random.shuffle(all_names) n_train int(len(all_names) * train_ratio) n_val int(len(all_names) * val_ratio) train_set all_names[:n_train] val_set all_names[n_train:n_train n_val] test_set all_names[n_train n_val:] def write_split(split_data, out_txt): with open(out_txt, w, encodingutf-8) as f: for name, ext in split_data: f.write(f{os.path.join(img_dir, name ext)}\n) write_split(train_set, train.txt) write_split(val_set, val.txt) write_split(test_set, test.txt)这里有三个要点值得说一下。random.seed(42)是复现性的保证团队里两个人跑同一套数据出来的train/val必须一模一样否则你复现不了同事的mAP。其次我只保留了图片和txt同时在手的样本垃圾检测这类数据里总会有几张开图还没标注强行留下会在训练中途报标签缺失。最后输出的是路径列表而不是移动文件这样以后调整比例只需重跑脚本不需要恢复文件目录。3.3 划分前的类别分布审计划分脚本本身不难真正让项目翻车的是类别不均衡。比如1000张图里瓶子有600张电池只有80张随机划分后验证集里电池可能只剩8张测试集甚至一张都没有这个类的精度评估就完全失真。所以在跑划分之前或者之后我会先做一次类别计数。from collections import Counter def count_classes(name_list): counter Counter() for name, _ in name_list: txt_path os.path.join(yolo_dir, name .txt) if not os.path.exists(txt_path): continue with open(txt_path, r, encodingutf-8) as f: for line in f: if line.strip(): counter[int(line.split()[0])] 1 return counter print(train:, dict(count_classes(train_set))) print(val:, dict(count_classes(val_set))) print(test:, dict(count_classes(test_set)))如果某一类在val或test里数量小于10不要急着开训练。两个处理思路一是让数据增强分担比如mosaic把多个小目标拼在一起二是直接合并类别把容易混淆的几类合成一个“瓶罐类”或者“纸制品类”牺牲粒度换可用性。很多垃圾检测项目最终都做了这种妥协因为细分到“易拉罐还是塑料瓶”对环卫场景的决策意义不大。3.4 划分完的路径检查后缀与空标签划分脚本跑完后我还会做一道路径体检。第一是后缀检查资源包的图片可能是jpg和jpeg混存如果YOLO按后缀匹配标签就会出现部分图片对不上txt。我的习惯是先重命名统一为.jpg再跑划分。第二是路径中的空格Windows下目录带空格大概率没问题但切到Linux容器部署时绝对路径里的空格会在拼接命令时造成奇奇怪怪的错误能用下划线就提前改掉。第三是验证train.txt、val.txt、test.txt的行数之和是否等于图片总数同时检查val.txt不为空。曾见过有人把val_ratio设成0导致验证集为空训练也能跑输出best.pt却没有任何验证指标可看等于白训。这三项检查各花一分钟属于典型的低成本高收益操作。4. 训练教程落地环境配置、参数设置与一轮完整训练4.1 环境配置Ultralytics YOLO的最小安装训练这块我用的是Ultralytics YOLO这个开源实现它把数据加载、训练、验证、导出统一到一套命令行接口里也是目前社区最主流的通吃方案。最小环境是Python 3.8以上加PyTorch 1.8以上有NVIDIA显卡就装对应CUDA版本没有显卡纯CPU也能跑完1000张图的小数据集只是慢一些。conda create -n yolo python3.9 conda activate yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics装完先做一个GPU可用性测试这一步能筛掉大部分环境配置的暗坑。import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU only)如果输出cuda.is_available()为False大概率是torch装成了CPU版或者CUDA驱动版本太老识别不了。这种情况重新装匹配驱动版本的PyTorch就好纯CPU训练也不是不能跑只是每个epoch耗时翻好几倍。4.2 data.yaml与训练启动参数怎么设训练入口是一个data.yaml文件它告诉框架数据集根目录、训练和验证列表、类别数量和类别名。在数据集根目录下建data.yaml内容如下。path: /data/garbage_detection train: train.txt val: val.txt nc: 6 names: - battery - bottle - can - carton - glass - paper注意path建议写绝对路径。相对路径在终端里跑没问题一旦换成脚本批量训练或定时任务工作目录变了就会找不到图片。启动命令是这个样子yolo train datadata.yaml modelyolov8s.pt epochs100 batch16 imgsz640 patience20参数说明model指定预训练权重yolov8s.pt是轻量版显存压力小1000张图的数据规模用s级足够epochs取100垃圾检测里类别不多、场景相对固定100轮以内基本收敛batch16是8GB显存的保守值24GB卡可以试着调到32imgsz640与预训练输入一致垃圾目标普遍偏小想提升小目标召回可以上960显存占用接近翻倍patience20表示验证集连续20轮没有提升就提前结束这是省时间最有效的一招。预训练权重要从官方仓库下载后放到项目根目录没有网络条件的机器可以直接拷贝已经下好的.pt文件。4.3 拿损失函数判断训练是否健康训练跑起来后不要只盯mAP要看results.csv里那三条损失曲线box_loss、cls_loss、dfl_loss。box_loss评估边框回归质量正常趋势是快速下降然后趋平cls_loss评估分类置信度垃圾检测里一般降得比box_loss慢dfl_loss是分布式焦点损失绝对数值常常比前两个大不要因为它大就以为崩了。判断训练健康的标准动作是中途对比train和val曲线train在降、val已经反弹过拟合来了epochs再跑多也是浪费电train和val同步下降且val没有大幅抖动可以放心等着patience触发。还有一个经验垃圾检测里小目标占比高box_loss会比mAP更早进入平台期这是小目标本身的物理限制不是你代码的问题继续硬跑不如早点做数据增强调整。4.4 断点续训与训练产物训练中断是家常便饭可能是机器重启也可能是容器被杀。Ultralytics的训练机制默认每个epoch结束都会存last.pt恢复训练只在命令行加一个参数。yolo train datadata.yaml modelruns/detect/train5/weights/last.pt resumeTrueresumeTrue会读取之前的训练状态包括epoch数、优化器状态和当前学习率继续往后跑而不是重头再来。这是我最常用的一条后悔药。训练结束后runs/detect下会有一整套产物weights/best.pt是验证集表现最好的权重last.pt是最后一个epoch的权重results.csv是全程指标曲线数据confusion_matrix.png和PR曲线图直接可用于汇报。val的结果还会记录每一类的mAP先看小类的mAP它比总mAP更能反映数据质量。5. YOLO垃圾检测训练中的常见问题排查五个高频坑5.1 标签坐标越界与归一化异常现象训练日志频繁出现“labels have width/height outside of image”的警告或者loss下降缓慢。原因大多出在格式转换一步用imgsz640去归一化原始标签算出来的框宽高大于1或者原始XML里某个标注框本身就越出了图片边界。解决先用2.4的校验脚本扫一遍txt把越界文件单独揪出来然后回到转换脚本加上min max钳制同时把“分母用原始尺寸”写进代码注释里。处理完再看训练日志警告基本消失。5.2 训练中loss突变成NaN与BN崩溃现象训练到十几轮或几十轮box_loss突然变成nan之后所有指标全部失守。原因常见导火索是学习率过大、某张图片文件损坏、标签坐标出现负值。在社区里这类问题常被叫做bn崩溃因为BatchNorm层在梯度爆炸后参数全部失控重新加载权重才能恢复。解决先把学习率从默认值降到0.001再扫描数据集里是否存在0字节图片或空标签文件最后在训练命令里加verbose参数让它打印出触发问题的图片路径。换数据集后我习惯先在30张图上跑5个epoch验证数据管道再上全量能避免90%的NaN。5.3 混淆矩阵总和不是100%现象验证阶段打开confusion_matrix.png每个格子都是小数把一行加起来要么大于1要么小于1怎么看怎么不对劲。原因YOLO输出的混淆矩阵默认按行归一化每一行代表“该类别真实目标被预测到各类别的比例”所以每一行的行和才是100%看整张表的总和必然不是1也没有意义。解决读表时先确认自己关心的是行归一化还是列归一化。想看某个类被认成了哪些类就看行想看某个预测框对应的真实来源就看列。矩阵是定位混淆关系的工具不是算总体正确率的工具总体正确率直接看mAP。5.4 显存OOM下如何调整batch与imgsz现象训练命令敲下去几秒终端直接抛出CUDA out of memory。原因batch和imgsz的乘积超过显存容量。解决先把batch砍到4imgsz保持640能跑起来再逐级上调如果目的是提小目标召回优先把imgsz从640提到960batch相应减半不要两个参数同时加。还有一个容易被忽略的因素是workers数量数据加载线程太多也会放大显存峰值在训练命令里手动指定workers4会稳定很多。跑长训练前先拿5个epoch试出当前显卡的安全batch值这个时间花得值。5.5 小类别全不检出的类别不平衡现象验证集里瓶子类mAP接近70%电池类mAP只有百分之几甚至完全没有预测框。原因数据集标签分布天然倾斜某个小类全图只有几十个目标模型直接把它当背景忽略掉了。解决先用第三章的审计脚本确认每个类的目标数然后打开mosaic增强增加小类在每张训练图里的出现频率。如果增强后依旧不管用最务实的方案是把小类并进语义相近的大类比如各种不同规格的电池统一为“电池”一类牺牲细分类别换回可用的召回率。垃圾检测项目里类别合并是常态化操作不是妥协。6. 从训练好的模型到自建项目验证脚本与推理加速训练结束后的验证我的固定动作是把best.pt单独拷出来先用predict命令在测试图片上跑一遍看框再用val命令出指标。yolo predict modelruns/detect/train5/weights/best.pt sourcetest_images device0 yolo val modelruns/detect/train5/weights/best.pt datadata.yaml splittestpredict生成的标注图用来看框是否贴合真实垃圾轮廓会不会漏检角落里的目标val命令输出的混淆矩阵和PR曲线才是给评审或客户看的正式指标。这个阶段我还会专门挑十张现场实拍、光线不理想的图片做盲测因为数据集里的test仍是同分布数据只有真实场景图能暴露模型的光照和遮挡边界。推理加速方面要部署到边缘设备就把权重导出成TensorRTNVIDIA设备上用FP16精度通常能拿到数倍提速没有GPU就导出ONNX再交给OpenVINO或NCNN跑CPU。这些平台的算子兼容性问题不少我自己的习惯是每次导出后先用模拟数据验证输出shape和数值范围一致再接业务代码否则到部署现场才发现算子不支持会非常被动。说到底我现在拿到任何一个数据集第一件事不是开训练而是花二十分钟做数据审计格式、类别分布、损坏文件、划分比例。这个习惯来自一次在线下环保项目里因为一张损坏图片让整个训练白跑两天的教训。数据侧的耐心永远值得希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。