尧图精选

基于650张小样本数据集的YOLO行李箱缺陷检测实战

🕒 发布时间:2026/10/1 6:24:56 📁 来源:尧图网络
简介本资源为行李箱缺陷检测数据集面向从事目标检测算法训练与验证的开发者、学生及研究人员可用于行李箱外观质量检测场景下的模型训练与效果评估。压缩包共1953个文件包含650张jpg图片、650个xml标注文件与653个txt标签文件分别对应VOC与YOLO两种格式方便直接接入主流检测框架整体约25.16MB图片分辨率清晰未做数据增强。数据集共2类标签damaged与good_condition其中damaged框数199、good_condition框数737总框数936均为矩形框标注适用于目标检测识别任务。目前已有34人学习下载。读者可借助该数据集快速搭建缺陷检测实验流程对比两种标注格式的转换与读取方式并基于真实标注开展模型训练与验证为后续调参与优化提供可靠的数据基础。1. 650 张行李箱缺陷检测数据集小样本 YOLO 落地到底值不值得做行李箱缺陷检测这个方向真正做过的人都知道痛点不在模型而在数据。工业质检场景里箱包表面划痕、凹陷、色差、拉链破损这些缺陷单条产线一天能拍几万张图但标注成本高、缺陷样本极度不均衡最后能用的往往就是几百张。这个标题里的 650 张、2 类、YOLO/VOC 双格式恰好是大多数中小团队能拿到的真实数据规模——不大但足够跑通一条从标注到部署的完整链路。它解决的不是我要发论文的问题而是我手上就这几百张图怎么让 YOLO 真的检出缺陷的问题。适合两类人一是刚接手工业质检项目、需要快速验证可行性的算法工程师二是想用真实缺陷数据练手 YOLO 训练全流程的开发者。650 张 2 类的规模意味着你不可能靠堆数据取胜必须把增强、类别平衡、验证策略这几件事做扎实而这恰恰是小样本缺陷检测最值钱的经验。下面按数据理解、格式转换、训练配置、避坑、进阶验证的顺序讲透。2. 先搞懂 650 张 2 类缺陷数据集的真实构成与选型逻辑拿到一个缺陷检测数据集第一件事不是急着训练而是搞清楚它到底长什么样。650 张、2 类这个规模背后隐含的信息量比想象中大类别少意味着模型容量需求低但样本少意味着过拟合风险高YOLO/VOC 双格式意味着它大概率是从 VOC 标注流程转过来的原始标注可能是 XML再转成 YOLO 的 txt。理解这一点能帮你判断后续要不要重新清洗标注。2.1 2 类缺陷的类别定义与样本分布判断2 类缺陷通常对应两种最常见的表面问题比如划痕和凹陷或者破损和污渍。类别少的好处是分类头压力小坏处是如果两类样本数量差距大模型会偏向多数类。你拿到数据集后第一件事应该是统计每类的标注框数量而不是图片数量——一张图可能有多个框也可能一个框都没有纯背景图。常见做法是写个脚本统计类别分布和框的尺寸分布。框尺寸分布尤其关键行李箱缺陷如果是细长划痕框的长宽比会很极端这时候默认的 anchor 或者 YOLOv8 的 anchor-free 头都需要留意。下面这段脚本直接读 YOLO 格式的 labels 目录做统计import os from collections import Counter import numpy as np label_dir datasets/labels/train cls_counter Counter() wh_list [] for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname)) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue c, x, y, w, h int(parts[0]), *map(float, parts[1:]) cls_counter[c] 1 wh_list.append((w, h)) print(类别框数分布:, dict(cls_counter)) wh np.array(wh_list) print(宽高均值:, wh.mean(axis0), 宽高最大值:, wh.max(axis0)) # 长宽比分布判断是否以细长缺陷为主 ratio wh[:, 0] / (wh[:, 1] 1e-6) print(长宽比中位数:, np.median(ratio))这段代码的逻辑是先遍历所有 label 文件把类别索引和归一化后的宽高收集起来。cls_counter告诉你两类是否均衡如果一类有 800 个框、另一类只有 120 个框那训练时必须做类别加权或者重采样。ratio的中位数如果明显偏离 1说明缺陷偏细长数据增强时就要慎用大幅度的随机缩放否则细长目标容易被压没。参数上YOLO 格式的坐标是归一化到 0-1 的所以宽高最大值不会超过 1。如果你发现某个 w 或 h 接近 1说明这个框几乎覆盖整张图要么是标注错误要么是缺陷本身占满画面后者在训练时反而容易学。2.2 为什么小样本场景优先选 YOLO 而不是两阶段检测器650 张图这个量级Faster R-CNN 这类两阶段检测器基本没戏——RPN 需要大量候选框样本来学样本一少就崩。YOLO 系列的单阶段结构在小样本上更稳原因是它的损失函数把分类和回归耦合在一起每个正样本同时贡献定位和分类梯度梯度利用率高。而且 YOLOv8 之后默认 anchor-free省掉了聚类 anchor 这一步对 650 张这种规模特别友好因为你根本没有足够数据去聚类出稳定的 anchor。选型上如果只是验证可行性YOLOv8n 或 YOLOv8s 足够如果要上产线YOLOv8m 是性价比拐点。更大的模型在 650 张上几乎必然过拟合除非你做大量增强或者用预训练权重冻结主干。这里有个血泪经验小样本缺陷检测里预训练权重的价值远大于模型结构的花哨改进。COCO 预训练的 backbone 已经学到了边缘、纹理这些底层特征缺陷检测恰好吃这一套。提示不要一上来就改网络结构。650 张数据下结构改动的收益远不如把增强策略和验证集划分做对。3. VOC 转 YOLO 格式转换脚本、目录结构与四个边界坑标题里写了 YOLO/VOC 双格式实际使用中你大概率拿到的是 VOC 的 XML 标注需要转成 YOLO 的 txt。这一步看着简单但翻车点极多尤其是坐标归一化和类别映射。转换错了训练 loss 会正常下降但 mAP 死活上不去排查起来非常痛苦。3.1 VOC XML 到 YOLO txt 的转换脚本VOC 的 XML 里存的是绝对像素坐标xmin, ymin, xmax, ymaxYOLO 要的是归一化的中心点加宽高。转换公式是cx (xminxmax)/2/Wcy (yminymax)/2/Hw (xmax-xmin)/Wh (ymax-ymin)/H。下面这个脚本同时处理类别映射和目录生成import os import xml.etree.ElementTree as ET import shutil VOC_ANN VOCdevkit/VOC2007/Annotations VOC_IMG VOCdevkit/VOC2007/JPEGImages OUT_IMG datasets/images/train OUT_LBL datasets/labels/train # 类别名到索引的映射必须和训练时的 data.yaml 一致 CLASS_MAP {scratch: 0, dent: 1} os.makedirs(OUT_IMG, exist_okTrue) os.makedirs(OUT_LBL, exist_okTrue) for xml_file in os.listdir(VOC_ANN): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(VOC_ANN, xml_file)) root tree.getroot() size root.find(size) W, H int(size.find(width).text), int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_MAP: continue # 跳过未定义类别避免索引错乱 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) # 边界裁剪防止标注越界导致归一化后超出 0-1 xmin, ymin max(0, xmin), max(0, ymin) xmax, ymax min(W, xmax), min(H, ymax) cx (xmin xmax) / 2 / W cy (ymin ymax) / 2 / H w (xmax - xmin) / W h (ymax - ymin) / H lines.append(f{CLASS_MAP[name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) if lines: base os.path.splitext(xml_file)[0] with open(os.path.join(OUT_LBL, base .txt), w) as f: f.write(\n.join(lines)) # 同步拷贝图片保证图片和标签同名 src_img os.path.join(VOC_IMG, base .jpg) if os.path.exists(src_img): shutil.copy(src_img, os.path.join(OUT_IMG, base .jpg))逻辑上这段脚本做了三件关键事类别映射过滤、坐标边界裁剪、图片标签同步拷贝。CLASS_MAP必须和后续data.yaml里的names顺序严格一致否则模型学到的类别会整体错位。边界裁剪是很多人忽略的一步VOC 标注里偶尔会出现xmax超过图片宽度的情况不裁剪的话归一化后 w 会大于 1YOLO 训练时虽然不报错但那个框的梯度是错的。参数说明cx, cy, w, h保留 6 位小数足够YOLO 内部会再处理。如果你的图片是 png 格式把.jpg换成.png即可但要注意图片和标签必须同名同基。3.2 转换后必须做的三项校验转换完不要直接开训先做校验。第一项是数量校验图片数、标签数、XML 数三者应该一致除非有纯背景图。第二项是坐标范围校验所有 txt 里的数值必须在 0-1 之间出现负数或大于 1 就是转换 bug。第三项是可视化校验随机抽 20 张图把框画出来肉眼看框是否贴合缺陷。import cv2 import os import random img_dir datasets/images/train lbl_dir datasets/labels/train samples random.sample(os.listdir(img_dir), 20) for img_name in samples: img cv2.imread(os.path.join(img_dir, img_name)) h, w img.shape[:2] lbl_path os.path.join(lbl_dir, os.path.splitext(img_name)[0] .txt) if not os.path.exists(lbl_path): print(缺标签:, img_name) continue with open(lbl_path) as f: for line in f: c, cx, cy, bw, bh line.split() cx, cy, bw, bh map(float, (cx, cy, bw, bh)) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(fvis_{img_name}, img)可视化校验是最省事的后悔药。很多转换 bug 在数值上看不出来但画出来一眼就能发现框偏移、框翻转、类别标错。这一步花十分钟能省掉后面几小时的 loss 排查。3.3 目录结构怎么组织才不踩坑YOLO 训练对目录结构有隐含要求图片和标签的路径要能通过替换字符串对应上。常见做法是images/train配labels/trainimages/val配labels/val。如果你把标签和图片混在一个目录或者 val 集没有对应标签目录训练时会出现找到图片但找不到标签的警告然后这些图被静默跳过你以为在训 650 张实际可能只训了 500 张。推荐结构如下路径内容说明datasets/images/train训练图片约 520 张datasets/labels/train训练标签与图片同名 txtdatasets/images/val验证图片约 130 张datasets/labels/val验证标签与图片同名 txtdata.yaml数据集配置含路径和类别名划分比例上650 张建议 8:2即 520 训练、130 验证。不要用 7:3验证集太大会让训练样本更少小样本下每一张都珍贵。划分时要保证两类缺陷在训练和验证集里都有分布不能出现验证集只有一类的情况。注意划分后检查验证集里每类的框数如果某类少于 10 个框验证指标会剧烈波动这时候要么调整划分要么接受指标仅供参考。4. YOLOv8 训练配置从 data.yaml 到超参的实操参数数据准备好之后训练配置决定了你能不能把这 650 张榨干。YOLOv8 的配置分两层一层是data.yaml定义数据一层是训练命令里的超参。小样本场景下超参的调整比模型选择更重要。4.1 data.yaml 的正确写法和路径陷阱data.yaml里最容易错的是路径。YOLO 支持相对路径和绝对路径但相对路径是相对于你运行训练命令的目录不是相对于 yaml 文件。很多人把 yaml 放在 datasets 目录下然后写path: .结果训练时找不到数据。稳妥做法是写绝对路径或者明确写清楚相对基准。path: /home/user/project/datasets train: images/train val: images/val nc: 2 names: 0: scratch 1: dentnc是类别数必须和names的长度一致。names的顺序必须和转换脚本里的CLASS_MAP完全一致这是硬约束。如果顺序错了模型会把划痕预测成凹陷mAP 看起来还行但实际全错。4.2 小样本训练的超参设置与理由650 张图batch size 设 16 比较合适太大梯度不稳太小 BN 统计不准。epochs 设 100-150配合早停。学习率用默认的 0.01 起步但小样本建议降到 0.001因为样本少梯度噪声大学习率高了容易震荡。权重衰减保持默认 0.0005。关键在增强参数。小样本必须开强增强但缺陷检测有它的特殊性不能做垂直翻转缺陷方向有物理意义不能做大幅度旋转划痕角度是特征。推荐配置yolo detect train \ datadatasets/data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.001 \ patience30 \ hsv_h0.015 hsv_s0.7 hsv_v0.4 \ degrees10.0 \ translate0.1 \ scale0.5 \ fliplr0.5 \ flipud0.0 \ mosaic1.0 \ mixup0.1 \ copy_paste0.1逐个说hsv_h/s/v是色调饱和度明度扰动工业图像光照变化大这三个值可以适当放大。degrees10限制旋转角度避免缺陷方向被破坏。flipud0.0关闭上下翻转这是缺陷检测和通用检测的重要区别。mosaic1.0是 YOLO 的招牌增强把四张图拼一张对小样本特别有效因为它变相增加了场景多样性。mixup和copy_paste各给 0.1前者做图像混合后者做缺陷复制粘贴都是小样本的救命稻草。patience30是早停验证指标 30 轮不提升就停。小样本训练很容易过拟合早停能帮你省时间。imgsz640是默认值如果你的缺陷特别小可以提到 1280但显存和速度要权衡。4.3 训练过程要看哪些指标哪些是假象训练时终端会打印 box_loss、cls_loss、dfl_loss 和 mAP。小样本下loss 下降不代表模型变好因为 650 张很容易被记住。真正要看的是验证集的 mAP50 和 mAP50-95以及混淆矩阵。一个典型假象训练 loss 一路降到 0.1验证 mAP 卡在 0.4 不动。这说明模型在背训练集泛化没跟上。解决办法是加大增强、加 dropout、或者减小模型。另一个假象mAP50 很高但 mAP50-95 很低说明框的位置不够准这时候要检查标注质量而不是调模型。混淆矩阵能告诉你两类是否被混淆。如果 scratch 大量被预测成 dent要么是标注本身有歧义要么是类别不平衡导致模型偏向某一类。YOLO 训练完会在 runs 目录下生成混淆矩阵图务必看一眼。提示小样本训练不要频繁看训练 loss容易自我安慰。盯验证集指标和混淆矩阵这两个才反映真实能力。5. 小样本缺陷检测的避坑清单5 个真实翻车场景这一章全是踩过的坑每条按现象、原因、解决写。650 张 2 类的规模下面这些问题几乎必然遇到至少两个。5.1 现象训练正常但验证 mAP 为 0原因通常是类别索引错位。转换脚本里的CLASS_MAP和data.yaml的names顺序不一致导致模型学到的类别和验证时对不上。另一种可能是验证集的标签路径没配对YOLO 静默跳过了所有验证图mAP 计算时没有正样本。解决先跑一遍 3.2 的校验脚本确认标签存在且坐标合法。再打印data.yaml的names和转换脚本的CLASS_MAP逐项对比。如果都没问题用yolo detect val单独跑验证看输出里有没有no labels found的警告。5.2 现象模型只检出一类另一类完全漏检原因是类别不平衡。650 张里如果一类有 600 个框、另一类只有 80 个框模型会倾向于只学多数类因为这样 loss 降得最快。小样本下这个问题被放大。解决三个手段叠加。一是用cls损失加权YOLOv8 支持在训练时通过数据集层面重采样二是对少数类做 copy_paste 增强把少数类缺陷复制到其他图上三是调整验证集划分保证少数类在验证集里有足够样本否则你连它有没有被学到都看不出来。5.3 现象验证指标波动极大两次训练差 0.2原因是验证集太小。130 张验证图如果每类只有几十个框mAP 的方差会很大换一次随机种子结果就变。这不是模型问题是评估问题。解决用 k 折交叉验证代替单次划分。650 张做 5 折每折 130 张验证最后取平均。虽然训练时间翻 5 倍但指标可信度大幅提升。如果时间不够至少固定随机种子保证可复现。5.4 现象训练到一半 loss 突然变 NaN原因是学习率过高或者某个 batch 里有异常标注。小样本下一个坐标越界的框就可能导致梯度爆炸。VOC 转换时如果没做边界裁剪w 或 h 可能大于 1归一化后损失计算会出问题。解决先检查所有标签的坐标范围用 3.2 的校验脚本扫一遍。然后把lr0降到 0.0005加梯度裁剪。YOLOv8 默认有梯度裁剪但如果异常值太大也压不住。最稳妥的是清洗数据把越界框修正或删除。5.5 现象模型在训练集上完美换一批新图全崩原因是过拟合加数据分布单一。650 张如果都来自同一批次、同一光照、同一角度模型学到的是这批数据的特征不是缺陷的本质特征。工业场景里换一批货、换一个工位分布就变了。解决增强要往分布多样性上做而不是只做几何变换。色调扰动、亮度扰动、模糊、噪声这些能模拟不同拍摄条件。如果条件允许主动采集不同批次、不同光照的图哪怕每类只加 50 张泛化提升也很明显。另外用预训练权重并冻结前几层能保留通用特征减少对特定分布的依赖。6. 用混淆矩阵和误检分析反推标注质量一个具体技巧训练完拿到 mAP 只是开始真正决定这个方案能不能上产线的是误检和漏检的分布。我一般会做一件事把验证集的预测结果导出按置信度排序重点看两类——高置信度误检和低置信度漏检。这两类样本往往指向标注问题而不是模型问题。具体做法是用yolo detect predict跑验证集保存 txt 结果然后写脚本对比预测框和真实框。下面这段代码统计每个类别的误检和漏检数量import os import numpy as np pred_dir runs/detect/predict/labels gt_dir datasets/labels/val IOU_THRESH 0.5 def load_boxes(path): boxes [] if not os.path.exists(path): return boxes with open(path) as f: for line in f: c, x, y, w, h line.split() boxes.append((int(c), float(x), float(y), float(w), float(h))) return boxes def iou(a, b): ax1, ay1 a[1] - a[3] / 2, a[2] - a[4] / 2 ax2, ay2 a[1] a[3] / 2, a[2] a[4] / 2 bx1, by1 b[1] - b[3] / 2, b[2] - b[4] / 2 bx2, by2 b[1] b[3] / 2, b[2] b[4] / 2 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 union a[3] * a[4] b[3] * b[4] - inter return inter / union if union 0 else 0 fp, fn 0, 0 for fname in os.listdir(gt_dir): gt load_boxes(os.path.join(gt_dir, fname)) pred load_boxes(os.path.join(pred_dir, fname)) matched_gt set() for p in pred: best_iou, best_idx 0, -1 for i, g in enumerate(gt): if i in matched_gt or g[0] ! p[0]: continue v iou(p, g) if v best_iou: best_iou, best_idx v, i if best_iou IOU_THRESH: matched_gt.add(best_idx) else: fp 1 # 误检 fn len(gt) - len(matched_gt) # 漏检 print(f误检: {fp}, 漏检: {fn})这段代码的核心是逐图做 IoU 匹配匹配上算正确预测多出来的算误检真实框没被匹配的算漏检。跑完之后如果误检集中在某个区域去看那些图大概率是标注漏标了如果漏检集中在某类缺陷去看那类的标注是不是框太小或者太模糊。我自己的习惯是每次训练完必看误检 top20 和漏检 top20 的图。十次里有八次能发现标注问题——要么是漏标要么是框画得太松。650 张的数据集标注质量比模型结构重要得多把标注修一遍mAP 涨 5 个点是常事。这个技巧不花哨但它是小样本缺陷检测里最实在的提分手段。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →