资讯动态

三千张四类垃圾数据集:标签校验、切分与训练避坑指南

发布时间:2026/10/26 11:10:59 来源:尧图企业网站定制
简介这份数据集面向参加生活垃圾智能分类竞赛的选手、计算机视觉学习者及目标检测项目实践者提供已完成标注的四类垃圾图像样本可直接用于YOLO系列模型的训练与验证。压缩包共约2000个文件以1998个XML标注文件为主对应每张图像的类别与边界框信息另含2个TXT文件用于划分训练集与验证集整体大小约411.59MB。样本覆盖有害垃圾电池、过期药品及内包装、可回收垃圾易拉罐、小号矿泉水瓶、厨余垃圾小土豆、切过的白萝卜、胡萝卜和其他垃圾瓷片、鹅卵石、砖块等类别贴合赛题对形状、尺寸与重量的实际约束。已有1626人学习下载读者可据此快速搭建数据加载流程、复现标注格式转换与训练验证划分省去从零采集与标注的成本把精力集中在模型调优与装置联调上。1. 三千张四类垃圾图为什么“打完标签”才是真正的地狱开局拿到一份“四类垃圾、约三千张、已打完标签”的数据集很多人的第一反应是直接开训跑个 YOLO 看 mAP 能不能上 0.8。我一开始也这么干结果第一轮就翻车验证集 mAP 卡在 0.62 上不去混淆矩阵里“可回收物”和“其他垃圾”互相串得厉害。问题不在模型在标签。垃圾分类这个场景的标注质量比图像数量重要得多——三千张里只要有两三百张边界框把“纸杯”框成了“其他垃圾”模型学到的就是错的语义。这篇笔记就围绕这份“四类垃圾约三千张已标注数据集”讲清楚它到底能干什么、怎么验标签、怎么切分、怎么训、坑在哪。适合手里已经有一份标注数据、准备做分类或检测落地的人也适合正在评估“这个方向值不值得投入”的从业者。2. 先验标签再谈训练三千张四类垃圾数据的体检流程数据集到手别急着写训练脚本。垃圾分类的标注有几个高频病灶一类是类别定义本身模糊奶茶杯算可回收还是其他二类是框贴边、框漏标三类是同一物体在不同图里标了不同类。这三类问题不解决后面调参全是玄学。我一般的顺序是先做类别分布统计再做标签可视化抽检最后做一致性清洗。三千张的体量人工全检不现实但抽检 10% 加上脚本自动查异常基本能把大问题捞出来。2.1 用脚本统计四类分布与框尺寸先看数据长什么样第一步不是看图片是看标签文件。常见做法是 YOLO 格式每张图一个 txt每行class cx cy w h归一化到 0~1。先跑一个统计脚本把每类数量、每类框的宽高分布、每张图的框数量都算出来。垃圾分类数据集最容易出现的分布问题是“其他垃圾”一家独大四类比例严重失衡这时候训练时类别权重就得提前想好。import os from collections import Counter, defaultdict label_dir labels/train # 标签目录 img_dir images/train # 图片目录 cls_count Counter() box_per_img [] wh_by_cls defaultdict(list) for fn in os.listdir(label_dir): if not fn.endswith(.txt): continue path os.path.join(label_dir, fn) with open(path) as f: lines [l.strip() for l in f if l.strip()] box_per_img.append(len(lines)) for line in lines: parts line.split() if len(parts) ! 5: print(格式异常:, fn, line) # 行字段数不对直接报出来 continue c, cx, cy, w, h int(parts[0]), *map(float, parts[1:]) cls_count[c] 1 wh_by_cls[c].append((w, h)) print(类别计数:, dict(cls_count)) print(每图平均框数:, sum(box_per_img) / len(box_per_img)) print(空标签图数量:, box_per_img.count(0)) # 空标签图要单独处理 for c, whs in wh_by_cls.items(): ws [x[0] for x in whs]; hs [x[1] for x in whs] print(f类{c} 宽均值{sum(ws)/len(ws):.3f} 高均值{sum(hs)/len(hs):.3f} 样本{len(ws)})这段脚本干三件事统计每类框数量、算每图平均框数、按类输出归一化宽高均值。参数上label_dir和img_dir要指向你实际的切分目录如果标签是 VOC 的 xml得先转成 YOLO 格式再跑。重点看两个输出一是“空标签图数量”垃圾分类里常有纯背景图被误放进数据集空标签图在训练时会被当成负样本数量多了会拉低召回二是各类宽高均值如果某一类的框普遍特别小比如 w、h 都小于 0.05说明标注时框得很紧小目标检测的 anchor 就得相应调小否则这类基本学不出来。2.2 标签可视化抽检把框画回图上一眼看出错标统计只能看数量看不出“框错位置”。第二步是把标签画回原图随机抽 50~100 张拼成网格看。这一步是血泪经验垃圾分类的错标大量集中在“框住了但类别错”纯靠数字统计发现不了必须眼睛看。我一般会按类别分层抽样保证四类都抽到尤其是数量最少的那一类要多抽。import cv2, random, os import numpy as np names [可回收物, 有害垃圾, 厨余垃圾, 其他垃圾] # 按你的类别顺序改 colors [(0,200,0),(0,0,255),(0,165,255),(255,0,0)] def draw_one(img_path, lbl_path): img cv2.imread(img_path) h, w img.shape[:2] with open(lbl_path) as f: for line in f: c, cx, cy, bw, bh line.split() c int(c); cx,cy,bw,bh map(float,(cx,cy,bw,bh)) x1 int((cx-bw/2)*w); y1 int((cy-bh/2)*h) x2 int((cxbw/2)*w); y2 int((cybh/2)*h) cv2.rectangle(img,(x1,y1),(x2,y2),colors[c],2) cv2.putText(img,names[c],(x1,max(y1-5,10)), cv2.FONT_HERSHEY_SIMPLEX,0.5,colors[c],1) return img # 分层抽样每类抽若干张含该类目标的图 samples [] for c in range(4): picked 0 for fn in os.listdir(labels/train): if picked 15: break p os.path.join(labels/train, fn) if any(l.split()[0] str(c) for l in open(p) if l.strip()): samples.append(fn); picked 1 grid [] for fn in samples[:60]: stem fn[:-4] img draw_one(fimages/train/{stem}.jpg, flabels/train/{fn}) img cv2.resize(img,(320,320)) grid.append(img) rows [np.hstack(grid[i:i6]) for i in range(0,len(grid),6)] cv2.imwrite(check_grid.jpg, np.vstack(rows))draw_one把归一化坐标还原成像素坐标画框colors和names必须和你的data.yaml里类别顺序严格一致——顺序错了画出来的颜色和名字全对不上抽检就白做了。分层抽样那段保证四类各抽 15 张避免小类被漏掉。生成的check_grid.jpg一张图看 60 个样本重点盯三件事框是否贴边截断、同一物体是否被重复框、类别名和物体是否匹配。抽检发现错标率超过 5%就别往下走了先返工清洗。2.3 一致性清洗同一张图重复标注与跨类冲突怎么处理抽检之后是脚本清洗。垃圾分类数据集有两个高频脏数据一是同一张图里同一个物体被标了两个框重复标注二是两个框高度重叠但类别不同跨类冲突。前者会让模型对同一目标产生两个正样本后者直接制造矛盾标签。处理策略我一般这样定IoU 大于 0.85 且类别相同的保留置信度更高或面积更大的那个IoU 大于 0.6 但类别不同的人工复核脚本先打标记不自动删。def iou(a, b): ax1,ay1,ax2,ay2 a; bx1,by1,bx2,by2 b ix1,iy1 max(ax1,bx1), max(ay1,by1) ix2,iy2 min(ax2,bx2), min(ay2,by2) iw,ih max(0,ix2-ix1), max(0,iy2-iy1) inter iw*ih ua (ax2-ax1)*(ay2-ay1) (bx2-bx1)*(by2-by1) - inter return inter/ua if ua 0 else 0 def clean_label(lbl_path, iou_dup0.85, iou_conflict0.6): boxes [] for line in open(lbl_path): if not line.strip(): continue c,cx,cy,w,h line.split() c int(c); cx,cy,w,h map(float,(cx,cy,w,h)) boxes.append([c, cx-w/2, cy-h/2, cxw/2, cyh/2]) keep, flagged [], [] for i, b in enumerate(boxes): dup False for j, k in enumerate(keep): v iou(b[1:], k[1:]) if v iou_dup and b[0] k[0]: dup True; break # 同类高重叠丢弃当前框 if v iou_conflict and b[0] ! k[0]: flagged.append((i, j, round(v,2))) # 跨类冲突打标记 if not dup: keep.append(b) return keep, flaggediou_dup设 0.85 是经验值同一物体两次标注的框通常高度重合0.85 以上基本可判定重复设太低会误删相邻的两个真实目标比如并排的两个瓶子。iou_conflict设 0.6 是冲突预警线低于 0.6 的重叠在垃圾分类里很常见垃圾袋里套着瓶子不能一刀切。flagged列表输出的是需要人工看的冲突对三千张里一般也就几十对复核成本可控。清洗完记得把改动写回新目录别覆盖原始标签后悔药得留着。3. 三千张怎么切分与增强小数据集的训练集/验证集/测试集策略三千张四类平均每类七百多张这个量级做检测偏小、做分类勉强够。切分策略直接决定你评估出来的指标可不可信。我见过最常见的翻车是随机切分导致同一场景的图同时出现在训练和验证集里mAP 虚高一大截上线就露馅。垃圾分类的图像往往来自固定几个拍摄场景同一个垃圾桶、同一批背景所以切分必须按场景或按来源分组不能纯随机。3.1 按场景分组切分避免验证集“泄题”如果数据集里图片有来源信息文件名前缀、拍摄批次优先按来源分组切。没有来源信息时退而求其次用图像相似度聚类把高度相似的图分到同一组再按组切分。比例上三千张我一般切 8:1:1即训练 2400、验证 300、测试 300。验证集用来调参和早停测试集只在最后跑一次中途反复看测试集等于变相过拟合。import hashlib, os, shutil def group_key(fn): # 有来源前缀就用前缀没有就用文件名哈希取模做伪分组 # 实际项目里建议换成感知哈希或聚类结果 return hashlib.md5(fn[:6].encode()).hexdigest()[:2] files [f for f in os.listdir(images/all) if f.endswith(.jpg)] groups {} for f in files: groups.setdefault(group_key(f), []).append(f) train, val, test [], [], [] for g, fs in groups.items(): n len(fs) n_val max(1, int(n*0.1)); n_test max(1, int(n*0.1)) val fs[:n_val]; test fs[n_val:n_valn_test] train fs[n_valn_test:] for split, fs in [(train,train),(val,val),(test,test)]: os.makedirs(fdataset/images/{split}, exist_okTrue) os.makedirs(fdataset/labels/{split}, exist_okTrue) for f in fs: stem f[:-4] shutil.copy(fimages/all/{f}, fdataset/images/{split}/{f}) shutil.copy(flabels/all/{stem}.txt, fdataset/labels/{split}/{stem}.txt) print(len(train), len(val), len(test))group_key这里是占位实现用文件名前六位哈希做伪分组目的是演示“同组不跨集”的逻辑真实项目里应该用拍摄批次号或图像感知哈希聚类的结果替换它。核心约束是同一个 group 的图只能进一个 split。这样切出来的验证集才反映模型在“没见过的场景”上的表现。切完检查一下三个集合的类别分布如果验证集里某一类几乎为零说明分组切分把某类集中切走了需要调整分组粒度。3.2 针对垃圾分类的增强组合哪些增强会帮倒忙小数据集必须靠增强撑但垃圾分类的增强有禁区。颜色抖动HSV 调整要克制因为“厨余垃圾发黄发暗”“有害垃圾颜色鲜艳”本身就是类别线索色相大幅偏移会把语义改掉。我一般开的增强是随机水平翻转、小角度旋转±10°、随机缩放裁剪scale 0.8~1.2、轻微亮度对比度扰动。Mosaic 和 MixUp 在检测里常用但垃圾分类里 MixUp 会把两类垃圾叠在一起语义直接乱掉不建议开。增强方式建议参数是否推荐原因水平翻转p0.5推荐垃圾无固定朝向旋转±10°推荐模拟拍摄角度偏差缩放裁剪0.8~1.2推荐适应不同拍摄距离亮度/对比度±0.2推荐模拟光照变化HSV 色相偏移幅度 0.05谨慎颜色是类别线索MixUp—不推荐两类叠加破坏语义Mosaicp0.5可选提升小目标但注意框越界Mosaic 之所以标“可选”是因为它会把四张图拼一张拼接处的框可能被截断垃圾分类里小目标多截断后标签就不准了。如果开 Mosaic务必确认训练框架的标签裁剪逻辑正确否则又是一批脏标签。3.3 用 data.yaml 把四类映射固定下来不管用哪个训练框架类别映射必须落成一个文件训练、评估、推理三处共用避免“训练时 0 是可回收、推理时 0 变成其他”这种低级但致命的错。常见做法是写一个data.yamlpath: ./dataset train: images/train val: images/val test: images/test nc: 4 names: [可回收物, 有害垃圾, 厨余垃圾, 其他垃圾]nc必须等于names长度names的顺序就是标签里类别 id 的顺序一旦定了就不能改。改类别顺序等于把所有标签重标一遍这是很多人踩过的坑中途觉得“有害垃圾应该排第一”改了 yaml 没改标签训练 loss 正常下降但 mAP 一塌糊涂排查半天才发现是映射错位。4. 从三千张到可用模型训练配置、评估指标与调参顺序数据验完、切完才轮到训练。三千张的体量我一般从轻量检测模型起步参数量几 M 级别先跑通 baseline 再谈涨点。上来就上大模型过拟合几乎是必然的而且训练慢、调参周期长不适合小数据集快速迭代。这一章讲清楚训练配置怎么设、指标怎么看、调参按什么顺序来。4.1 最小可跑训练命令与关键超参以常见的 YOLO 系检测框架为例最小训练命令大致是这样不同框架参数名略有差异按你用的框架对照python train.py \ --data data.yaml \ --weights yolov8n.pt \ --img 640 \ --epochs 100 \ --batch 16 \ --lr0 0.01 \ --lrf 0.01 \ --patience 20 \ --device 0逐项说--img 640是输入尺寸垃圾分类目标普遍不大640 是性价比高的起点显存够可以试 800--batch 16在单卡 8G 显存下比较稳显存不够降到 8--lr0 0.01是初始学习率小数据集上我一般会降到 0.005~0.01太大容易在前期就把模型带偏--lrf 0.01是最终学习率相对初始值的比例余弦退火到 1% 是常规做法--patience 20是早停耐心值验证集 20 轮不涨就停三千张数据 100 轮基本能收敛设太大纯浪费时间。--weights用预训练权重小数据集从零训几乎不可能收敛好这是硬经验。4.2 看混淆矩阵而不是只看 mAP四类互相串的定位方法mAP 是个汇总数涨了跌了都不知道为什么。垃圾分类真正要看的是混淆矩阵哪两类在互相串。我一般每训 10 轮存一次验证集混淆矩阵观察串类是否随训练收敛。如果“可回收物”和“其他垃圾”持续互串八成是这两类的标注边界本身模糊比如纸盒算哪类需要回到标签层面统一标准而不是继续调参。如果“有害垃圾”召回特别低先看它的样本量是不是最少再考虑加类别权重或针对性过采样。# 用验证集推理结果画混淆矩阵伪代码按框架 API 调整 from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt y_true, y_pred [], [] for img, labels in val_loader: preds model.predict(img) # 按 IoU0.5 且类别匹配做一对一匹配未匹配的记为背景 matched_true, matched_pred match_boxes(labels, preds, iou_thr0.5) y_true matched_true y_pred matched_pred cm confusion_matrix(y_true, y_pred, labels[0,1,2,3]) ConfusionMatrixDisplay(cm, display_labels[可回收,有害,厨余,其他]).plot() plt.savefig(cm.png)match_boxes的匹配阈值iou_thr0.5是检测评估的通用标准低于 0.5 的预测算误检、漏检的真值算漏检都会进混淆矩阵的对角线外。看矩阵时重点看两处对角线是否够“厚”以及非对角线上最大的那个格子是哪两类。前者反映整体准确率后者直接告诉你下一步该修数据还是修模型。这一步比盯着 mAP 小数点后两位有用得多。4.3 调参顺序先数据后模型先召回后精度小数据集调参最忌讳一上来就网格搜超参。我的顺序是固定的第一步修数据错标、漏标、类别失衡第二步调输入尺寸和增强强度第三步才动学习率和损失权重。原因是前两步对结果的影响远大于超参微调数据不干净时调出来的最优超参换个数据集就失效。指标取向上垃圾分类落地场景通常更怕漏检有害垃圾漏了后果更严重所以先看各类召回召回达标后再压误检提精度。如果某一类召回死活上不去优先查该类标注数量和质量而不是加损失权重硬拉。5. 避坑清单四类垃圾数据集训练里最容易翻车的五件事这一章是我自己和小团队踩过的坑按“现象 → 原因 → 解决”写每条都能对上前面章节的操作。三千张这个量级坑基本集中在标签、切分和评估三处模型本身反而很少是瓶颈。5.1 现象训练 loss 正常下降验证 mAP 却卡在 0.6 不动原因验证集和训练集存在场景重叠或者验证集标签有系统性错标。前者让验证指标虚高后突然卡住后者让模型在验证集上永远学不对。解决回到 3.1 的分组切分确认同场景图没有跨集再对验证集做一次 2.2 的可视化抽检验证集标签错标率往往比训练集更高因为大家清洗时容易只盯训练集。5.2 现象某一类常见是有害垃圾召回极低几乎检不出原因该类样本量最少且框普遍偏小加上增强时被 Mosaic 截断。解决先统计该类框尺寸2.1 脚本确认是否小目标再检查增强配置关掉 Mosaic 或降低其概率最后考虑对该类做定向过采样但过采样后要重新切分防止同一张图跨集。5.3 现象模型把“可回收物”大量判成“其他垃圾”混淆矩阵对应格子很厚原因这两类的标注标准在数据集内部不统一不同标注批次对“纸杯、塑料袋”的归类不一致。解决这不是调参能解决的必须回到标签抽这两类的图逐张看定一份类别判定细则比如“洁净纸类算可回收沾油污算其他”按细则重标冲突样本。三千张里这类冲突通常几百张重标成本可控。5.4 现象推理时类别名全错位模型输出 0 却显示成“其他垃圾”原因训练用的data.yaml类别顺序和推理脚本里写死的names列表不一致。解决把类别映射收敛到唯一一份配置文件训练、评估、推理全部读同一个文件禁止在代码里硬编码类别名。这是最冤的翻车模型没问题纯粹是映射错位。5.5 现象换一批新场景的图指标断崖式下跌原因三千张数据来源场景单一模型学到了背景捷径比如“灰色地面上的都是其他垃圾”。解决增强里加入随机背景替换或更强的裁剪缩放训练时混入少量新场景图评估时专门留一个“跨场景测试集”别只看同分布验证集。这个坑在实验室里看不出来一上线就暴露提前留测试集是唯一的后悔药。6. 把三千张用出三万张的效果主动学习与难例回流的具体做法三千张的天花板是明确的想再往上走靠的不是换更大的模型而是让数据自己长出来。我常用的做法是主动学习闭环用当前模型对未标注的新图做推理挑出模型最“犹豫”的样本送标标完回流进训练集。垃圾分类场景里模型犹豫的样本往往就是类别边界模糊的难例沾了油的外卖盒、混装的垃圾袋这些样本的信息量远大于随机新增的普通图。具体操作上用分类置信度加检测框重叠度做难例打分置信度在 0.3~0.6 之间的、或者同一区域出现多个类别高置信预测的优先送标。def hard_score(preds, low0.3, high0.6): score 0.0 for p in preds: conf p[conf] if low conf high: score 1.0 # 置信度落在犹豫区加分 # 同一区域多类高置信说明模型自相矛盾重点加分 # 实际实现里再加框重叠冲突检测 return score # 对未标注池逐图打分取 top-K 送标 pool load_unlabeled(unlabeled/) ranked sorted(pool, keylambda x: hard_score(model.predict(x)), reverseTrue) to_label ranked[:200]low0.3、high0.6这个犹豫区间是经验值低于 0.3 基本是背景噪声标了价值不大高于 0.6 模型已经比较确定边际信息少。每轮送标 200 张左右标完混入训练集重训观察验证集混淆矩阵里最厚的那两个格子有没有变薄——变薄说明难例选对了没变说明选样策略要调。这个闭环跑三轮通常能把最难的那一类的召回拉上来几个点比盲目加数据有效得多。还有一个容易被忽略的技巧把验证集里持续分错的样本单独拎出来做成一个“回归测试集”。每次重训后先在这个小集合上跑一遍如果之前分对的又分错了说明这轮改动引入了退化直接回滚不用等全量评估。这个习惯帮我省过很多次通宵排查。三千张数据不大但每一张错标、每一次切分失误、每一个映射错位都会被模型忠实地学进去。数据工程这活儿没有捷径验标签、分组切、看混淆矩阵、难例回流四步做扎实三千张也能训出能用的模型。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑