资讯动态

四类垃圾3000张数据集:从数据体检到模型训练全流程

发布时间:2026/10/22 17:29:47 来源:尧图企业网站定制
简介这份资源是专门面向生活垃圾智能分类赛项与目标检测训练整理的标注数据集包含约三千张四类实拍生活垃圾图像覆盖有害垃圾电池、过期药品、可回收垃圾易拉罐、小号矿泉水瓶、厨余垃圾小土豆、切块白萝卜、胡萝卜以及其他垃圾瓷片、鹅卵石、砖块可用于23年赛题初决赛阶段的模型训练与调参。压缩包内共2000个文件其中以1998个XML标注文件和2个TXT路径划分文件为核心XML记录每张图片中目标的类别与边界框两个TXT分别对应YOLOv5训练集和验证集列表整体包体约411.59MB。该数据集贴近真实赛题的尺寸与重量约束并预留多目标同时识别的场景适合准备算法验证、作品演示或论文实验。目前已有1626人学习下载能够帮助开发者免去繁琐的人工标定流程快速获得一份规范、可直接投入训练的数据底稿。1. 四类垃圾 3000 张数据集别急着训练先想清楚这份数据能做什么手里拿着一份「垃圾分类打完标签的数据集四类垃圾共计 3000 张左右」大多数人的第一反应是丢进训练脚本里跑一版。我的建议刚好相反先花一个晚上做体检再决定怎么用。因为“打完标签”只代表有人碰过这些图片不代表标注格式统一、类别名规范、坐标没出界、训练能收敛。我第一次拿到类似数据时跳过体检直接训练mAP 一塌糊涂后来才发现光是类别别名混乱就分了五种写法换名重训才勉强救回来。这篇笔记会从一线的角度把这套四类垃圾数据集的检查思路、格式转换、训练验证和踩坑记录一次讲完适合正在评估这份数据能不能用、以及想用它快速跑通模型的人。2. 拿到数据集先体检目录结构、类别分布与标注格式识别2.1 先看目录判断标注是分类还是检测格式拿到压缩包不要急着解压训练先解压到一个没有空格和中文的路径下然后列目录。这一眼能决定后面所有处理走哪条路。我见过不少所谓“打完标签”的垃圾分类数据集实际分两种形态一种是整图分类文件夹名就是类别另一种是物体检测图片旁边有同名 xml 或 txt。两种形态的数据处理方式完全不同搞混了后面会白做一晚上。# 进入数据根目录只列一层目录避免刷屏 cd ~/dataset/garbage4 ls -la # 如果 images 和 labels 是分开的说明是检测格式 # 如果看到 4 个类别文件夹说明是整图分类格式常见的目录结构大概长这样检测格式下图片在 images 里标注在 labels 里xml、json、txt 都有可能分类格式则按「厨余 / 可回收 / 有害 / 其他」建文件夹每类下面堆着几百张图。判断依据很简单看到同名标注文件就是检测只看到类别目录就是分类。这一步决定了后续是写转换脚本还是直接读图训练所以我会先列目录再找一张图打开看标注内部长什么样。看清形态再动手是这行省时间的核心习惯。2.2 一个脚本看清类别分布和图片尺寸不管哪种格式下一步都是统计类别分布和图片尺寸。四类垃圾共 3000 张理论上每类 750 张但实际分布往往参差不齐。有的类别占了 1200 张有的类别只有 400 张这种不均衡会直接拉低少数类别的召回率。图片尺寸也很重要如果主要图片是 1080p训练时下采样到 640 没问题如果混着一批 320p 的缩略图模型会越发越糊涂。import os from collections import Counter, defaultdict from PIL import Image root /Users/me/dataset/garbage4/images exts {.jpg, .jpeg, .png, .bmp} size_counter Counter() count_per_class defaultdict(int) for fname in os.listdir(root): if os.path.splitext(fname)[1].lower() not in exts: continue # 假设检测标注是同名 txt第一列是类别索引 label_path os.path.join(root.replace(images, labels), os.path.splitext(fname)[0] .txt) if os.path.exists(label_path): for line in open(label_path, r): cls int(line.strip().split()[0]) count_per_class[cls] 1 # 图片尺寸直接读头信息不需要完整解码 with Image.open(os.path.join(root, fname)) as im: size_counter[(im.width, im.height)] 1 print(类别分布:, dict(count_per_class)) print(尺寸分布:, size_counter.most_common(10))这段脚本会输出两个最关键的统计每类标注框出现的次数以及图片尺寸的分布。注意这里统计的是标注框数量而不是图片数量因为一张图里可能有两个瓶子按图片数会低估类别占比。如果发现某个类别的标注数明显偏低训练时要考虑给它加权重或者用复制粘贴增强补样本。尺寸分布则决定了训练时的输入分辨率如果 3000 张里混着大量不足 500px 的小图imgsz 设成 640 就会造成大量上采样模型学到的纹理全是马赛克。先跑完这两个统计再决定增强策略和训练参数心里才有底。2.3 标注质量的三项快速检查统计完数量接下来要抽查标注本身的质量。四类垃圾数据集的标注质量普遍不稳定我踩过的比较典型的问题包括txt 里混入空行导致解析失败、坐标归一化后超出 0~1 范围、类别索引写错导致某个类实际一个样本都没有。这些坑不会报错只会让训练 loss 看起来很收敛但验证集 recall 上不去。所以我会固定跑一套三项检查标注文件能否全部解析、坐标是否越界、是否有图片找不到对应标注。import os img_root /path/images lab_root /path/labels errors [] for fname in os.listdir(lab_root): if not fname.endswith(.txt): continue img_name os.path.splitext(fname)[0] img_path os.path.join(img_root, img_name .jpg) # 也可能是 .png if not os.path.exists(img_path): errors.append(f{fname}: 图片缺失) continue for lineno, line in enumerate(open(os.path.join(lab_root, fname), r)): parts line.strip().split() if len(parts) ! 5: errors.append(f{fname} 第{lineno 1}行: 列数不是5) continue cls_id, cx, cy, w, h map(float, parts) if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): errors.append(f{fname} 第{lineno 1}行: 坐标越界) if cls_id 0 or cls_id 3: # 四类垃圾索引0~3 errors.append(f{fname} 第{lineno 1}行: 类别索引超出范围) print(发现问题:, len(errors)) for e in errors[:20]: print(e)这套检查脚本应该在你准备转换格式前跑一遍。坐标越界和列数不对这两类问题最常见的来源是有人在 Excel 里手改过标注文件另存时把 NaN 写进了文本类别索引超出范围则多半是合并多个来源的标注时漏了类别映射。发现任何一条记录下文件名清单后面统一修。需要注意这份数据集的标注格式可能是 xml 或 json检查脚本只要把解析部分替换一下即可统计和判断逻辑完全通用。3. 把数据集整理成训练可用的格式YOLO 转换脚本与四个边界坑3.1 统一类别名先做映射再做转换四类垃圾数据集往往不是一个人标注的自然会出现类别名不统一的局面。我见过最典型的例子同一种“厨余垃圾”在标注文件里同时出现 leftover、kitchen_waste、china_food 三种写法把循环播放的视频抽帧后不同批次的命名习惯又不一样。如果你拿到的数据集是 xml 格式里面name字段千奇百怪第一步不是写坐标转换而是把类别名映射到统一的 0~3 索引。# 定义别名到标准类别的映射 alias_map { recycle: 0, recyclable: 0, kehuishou: 0, kitchen: 1, kitchen_waste: 1, chuyu: 1, harmful: 2, hazardous: 2, youhai: 2, other: 3, residual: 3, qita: 3, } def normalize_cls(name: str) - int: key name.strip().lower() if key not in alias_map: raise ValueError(f未识别的类别名: {name}) return alias_map[key]映射之后我建议立刻对全量标注跑一遍输出所有没匹配上的类别名。这一步能帮你发现那些藏得比较深的拼写错误比如 harmfu l、kithen 这种。写映射字典时保留英文别名的同时也要保留中文拼音因为不少标注工具默认输出拼音。只有类别名全部能落进 0~3后面转 YOLO 格式才不会出现类别索引错位。3.2 VOC/通用格式转 YOLO txt 的脚本常见做法是把 xml 标注转成 YOLO 格式的 txt因为绝大多数检测框架原生吃这份格式。转换的核心只有一件事把绝对值坐标xmin, ymin, xmax, ymax归一化到 0~1然后换算成中心点和宽高。具体公式不复杂但注意力要放在防止除零和宽高为负这两个边界问题上。import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_dir, alias_map): tree ET.parse(xml_path) root_xml tree.getroot() img_w int(root_xml.find(size/width).text) img_h int(root_xml.find(size/height).text) lines [] for obj in root_xml.iter(object): name obj.find(name).text cls_id normalize_cls(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 裁剪到图像边界防止归一化后出现负数 xmin max(0, xmin); ymin max(0, ymin) xmax min(img_w, xmax); ymax min(img_h, ymax) if xmax xmin or ymax ymin: continue # 无效框直接丢弃 cx (xmin xmax) / 2 / img_w cy (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_name os.path.splitext(os.path.basename(xml_path))[0] .txt with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(lines))这段脚本把每张图的 xml 读取、坐标归一化、类别映射全串起来了。注意我把坐标先裁剪到图像边界再参与计算这是防止后续在增强时出现越界框的关键一步。另外丢弃 xmax xmin 或 ymax ymin 的框这类数据多半是标注时误操作产生的竖线或横线留着只会让模型学会预测无意义的细长框。转换完成后用第一节的检查脚本重新跑一遍输出确保每行都是 5 列且坐标在 0~1 之间。3.3 切片与数据集划分顺序打散避免同场景连续帧进入同一个验证集转换完成后还有一道重要手续划分训练集和验证集。很多人直接取前 2400 张做训练、后 600 张做验证这在垃圾分类数据上是典型的错误姿势。因为许多数据集是从视频抽帧得到的前几百张可能全是同一个垃圾桶里的同一个苹果核如果它们同时落进验证集模型相当于提前见过了答案。import os import random import shutil random.seed(42) labels sorted([f for f in os.listdir(labels) if f.endswith(.txt)]) random.shuffle(labels) train_ratio 0.8 split_idx int(len(labels) * train_ratio) train_files, val_files labels[:split_idx], labels[split_idx:] for split, files in [(train, train_files), (val, val_files)]: os.makedirs(fimages/{split}, exist_okTrue) os.makedirs(flabels/{split}, exist_okTrue) for lab in files: img lab.replace(.txt, .jpg) shutil.copy(fimages/{img}, fimages/{split}/{img}) shutil.copy(flabels/{lab}, flabels/{split}/{lab})随机种子设成固定值能保证每次划分结果一致便于复现实验。更重要的是如果确认数据里有连续帧稳妥做法是先对场景做去重再划分但通常我们拿不到拍摄时间信息那么随机洗牌加上短路径已经能规避大部分泄漏问题。这 3000 张四类垃圾里80% 进训练、20% 进验证基本能支撑后续判断。3.4 四个边界坑第一坑路径带空格或中文。有些标注工具导出时保留了原始文件名比如“厨余垃圾 001.jpg”到了 OpenCV 和部分训练框架里直接读不进来报错还是隐性的表现为某张图一直不参与训练但没任何 warning。解决方式是先统一重命名全部换成garbage_0001.jpg这种纯 ASCII 短名。第二坑类别索引写错但脚本不报错比如把可回收和厨余的索引对调训练时 loss 照常下降推理时才暴露。解决方式是在转换脚本里打印每个类别的样本数和原始统计对账。第三坑一张图对应多个同名标注文件比如001.jpg的标签有001.txt和001.xml同时存在框架只会按优先级读其中一个造成实际参与训练的标注量少于你看到的数量。解决方式是在划分前删掉旧的 xml。第四坑是空标注文件有些标注员对“没有垃圾的图”也生成了空 txt这会让模型学到“看到这张图就不要输出任何框”验证集的 recall 被瞬间拉低。解决方式是把空文件对应的图片直接移出数据集或者单独建一个负样本集。4. 用 3000 张四类数据先跑一个小模型训练命令与参数怎么调4.1 数据划分与 class 文件确认标注格式正确、数据已切分之后下一步是让模型先跑起来。无论你最终打算用分类网络还是检测网络都要先写一份数据描述文件。以检测为例用当前主流的检测框架跑时需要提供一份 yaml 文件里面包含训练集、验证集路径和类别名列表。这里有个最容易踩的细节yaml 里的类别顺序必须和你转换脚本里的类别索引完全一致第三行写了厨余、第四行写了有害那么索引 1 就是厨余、索引 2 就是有害一旦写反模型训练时不会报错但推理结果会张冠李戴。4.2 一次能验证数据质量的最小训练流程数据文件准备好后先做一个最小训练目的是验证数据链路而不是刷精度。这个训练集只有 3000 张左右四类垃圾用小模型、小分辨率、短 epoch 先跑通。我一般会选轻量级网络batch 视显存而定先确保能在一个小时内跑完。# 训练四类垃圾检测模型imgsz640 是通用值batch 按显存调整 yolo train datagarbage4.yaml modelyolov8n.pt epochs50 imgsz640 batch16 device0这条命令在普通单卡环境就能跑。imgsz 设 640 是因为检测任务中垃圾框通常只占画面的 5%~30%分辨率太低会丢掉小目标信息如果你手里的图片本身只有 480p那就改成 512 而不是 640。epochs 设 50 是刻意的这个规模的数据集不需要 300 个 epoch跑到 50 轮已经能看出数据有没有问题一次性跑太久只会在错误数据上浪费算力。batch 设 16 是 8GB 显存左右的安全值显存不够就往下调但别低于 8。4.3 参数解释与期望值参数建议值说明imgsz640 或原图缩放至 640分辨率过高会显著加长训练时长过低则小目标容易丢batch8~32显存 8G 建议 1612G 以上可以 32再大会让 BN 不稳定epochs50~120先跑 50 轮验证数据模型稳定后再加workers4~83000 张图吞吐量不大workers 太高反而加大 IO 争抢optimizerauto 或 SGD小数据集用 SGD 收敛更稳AdamW 容易早停不动这几项里最关键的是 imgsz 和 epochs 的配合。很多新手把 epochs 拉到 300但 3000 张图的数据在小模型上 80 轮左右就会过拟合用验证 loss 早停即可。优化器选 auto 省心但如果发现训练集 loss 降得很快、验证集纹丝不动换成 SGD 会有改善。4.4 训练结果怎么看判断“能用的数据”还是“白折腾的数据”跑完 50 轮不要只看 mAP 这一个数字。我会先看三个指标训练集 loss 是否连续下降、验证集 mAP50 是否稳步爬升、类别维度上有没有某个类明显拉胯。四类垃圾数据如果 mAP50 在 0.5 附近说明标注质量不错如果只有 0.2 左右不要急着调模型先用测试图片可视化看几个预测结果。我习惯把验证集里置信度最高的 20 张和置信度最低的 20 张打印出来对比观察模型对哪个类别的预测框歪了。多数情况是某个类别的样本不够或标注框画得太随意这时回到数据和标注去修比加模型复杂度有效得多。记住在小规模数据集上模型只是测量标注质量的工具训练阶段玄学最少的部分是看曲线趋势而不是盯着一张 loss 图瞎猜。5. 人工排查 5 类常见标注坑从现象到原因再到解决5.1 坑一训练正常但某个类别 recall 始终为 0现象四类垃圾里其他三类 mAP 都还行只有“有害垃圾”的 recall 一直是零。曲线从头到尾没抬过头。原因我遇到过两次第一次是类别映射漏了该类的别名导致所有该类别的标注在转换时被归到“其他”模型从头到尾没见过这个类的正样本第二次是转换脚本里该类别的索引和 yaml 文件里排列顺序错位。排查时先打印每个类别的训练样本数如果“有害垃圾”显示 0就回去查映射字典和读取逻辑而不是调模型。解决修复映射关系重新转换再训练一版短的看曲线是否抬升。5.2 坑二训练 loss 出现周期性尖峰现象loss 曲线整体下降但每隔几十个 step 会突兀地跳出一个尖峰随后又恢复正常。原因这通常是训练集里混入了损坏图片或超大分辨率图片某个 batch 加载失败导致 loss 计算异常。我遇到的具体场景是数据里有一批 6000×4000 的航拍大图被缩略后放进训练集加载时内存占用突增训练进程卡顿后 loss 激增。解决检查数据里的极端尺寸和损坏文件把超过某个阈值的超清图统一降采样到 1280 以内然后用imghdr或 PIL 扫描一遍所有图片是否能正常解码。5.3 坑三验证集 loss 下降但 mAP 忽高忽低现象验证集 mAP50 在 0.3 到 0.6 之间剧烈波动每个 epoch 变化很大。原因验证集太小且验证集里混着大量相似图片。3000 张数据切出 20% 只有 600 张如果再有三五个相似场景各占几十张评估结果就会异常不平稳。解决先确认切分时有没有打散如果确认已打散但波动仍在就把验证集占比从 20% 降到 15%同时保证每类都有足够样本或者改用 K 折交叉验证观察稳定性。5.4 坑四推理结果框到了背景上现象训练完成模型在测试图上稳定地把垃圾桶边缘或桌子角识别成“可回收垃圾”。原因标注时框的范围太随意有些框把垃圾之外的背景也包进去了模型学到的是背景纹理而不是垃圾本体的特征尤其是塑料瓶和纸箱这类带明显边缘的物品更容易触发这种误检。解决对验证集中置信度在 0.3~0.5 之间的预测框做可视化看看模型喜欢在哪些区域给错答案。如果是背景误检回到标注文件把框收紧而不是单纯调低置信度阈值。5.5 坑五数据增强后训练时间翻倍但精度不涨现象加了 mosaic、旋转、色彩抖动之后训练时间明显变长mAP 几乎没变甚至轻微下降。原因3000 张的小数据集本身多样性不足增强如果过于激进会让模型学到扭曲后的伪特征另一个常见问题是训练图分辨率太低旋转后大量边缘区域被填充黑边模型被迫学这些黑边。解决在分辨率本来就有限的数据上优先使用亮度扰动和轻微缩放mosaic 可以开但把拼图比例调低旋转角度限制在 ±15 度以内。增强的作用是补足样本分布不是替代人工数据补充。6. 让这 3000 张数据发挥更大价值置信度清洗与二次标注的实用技巧6.1 用置信度做半自动清洗数据量只有 3000 张时与其花大量时间逐张翻图不如让模型先帮你筛一遍“可疑标注”。思路很简单用一个已经训练好的模型对训练集做一次推理输出每张图中置信度最低的框。置信度低有两种可能一是模型没学到位二是标注本身有问题。无论哪种都值得优先人工复审。from ultralytics import YOLO model YOLO(best.pt) results model.predict(sourceimages/train, conf0.1, save_txtTrue, save_confTrue) # 找出平均置信度最低的 200 张图优先人工检查 import os from collections import defaultdict conf_map defaultdict(list) for r in results: img_name os.path.basename(r.path) if len(r.boxes) 0: conf_map[img_name] [0.0] continue conf_map[img_name] r.boxes.conf.tolist() ranked sorted(conf_map.items(), keylambda kv: sum(kv[1]) / len(kv[1])) for img, confs in ranked[:200]: print(f{img}: {confs})这段脚本把低置信度图片按平均分排序输出。人工复审时只看前 200 张而不是 3000 张时间成本从一整天压缩到一两个小时。要注意的是置信度设 0.1 是为了让模型尽量把可疑目标都框出来宁可多召回也别漏检。复审时重点看两类框明显错位的和类别判断与肉眼不符的。6.2 少量人工复审把“回报率”最高的图挑出来二次标注不必追求全量重标那样跟重新做一遍数据集没区别。我会按类别做分层抽样四类各挑 50 张低置信度图片共 200 张由一个人用标注工具过一遍。修正后再把这 200 张重新丢进训练集模型通常会有肉眼可见的提升。这个效果的来源是错标和漏标对梯度的伤害远大于正常标注对模型的贡献纠偏 200 张的收益可能比增加 500 张重复样本更大。做完之后保留清洗清单记录哪些图被改了什么方便后面排查问题。我一直保持的习惯是任何数据集改动都会留一个训练前后对比表改动类别名、修坐标、删无效图都记下来这样模型一旦变差我能从前一天的改动里快速定位而不是把时间花在反复试参上。这份四类垃圾 3000 张的数据集把格式、分布、边界坑和清洗流程都走一遍之后后续的训练就能稳定复现希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑