焊接表面缺陷目标检测数据集解析:YOLOV5格式、小目标与训练避坑指南
简介这是一份面向目标检测研究者与工业视觉开发者的焊接表面缺陷数据集按YOLOV5标准目录结构整理覆盖穿孔、折痕、压痕、内含物等10类常见缺陷可用于缺陷检测模型训练、算法效果对比或相关课程设计。图像为2048×1000的RGB高清图训练集含1836张图片及对应txt标注验证集含458张图片与标签已按YOLO格式生成可直接放入模型训练流程使用无需额外转换。包内共2000个文件其中1999个为标签与类别说明txt另有1个可视化py脚本该脚本无需修改即可随机读取图片并绘制边界框并保存到当前目录方便快速核验标注质量。压缩包整体约918.87MB。目前已有233人学习使用适合希望获得真实工业场景数据、减少标注与格式整理成本的目标检测入门及进阶用户。1. 焊接表面缺陷目标检测数据集10 类别 918MB 到手先别急着开训做目标检测的第一反应基本都是解压、扔进 train.py、开训。但焊接表面缺陷这类工业检测场景和自然场景完全是两回事——穿孔、折痕、压痕、内含物这些缺陷很多只有几十像素宽2048x1000 的图缩到 640 之后标注坐标稍微差一点特征直接被压没了。这份焊接表面缺陷目标检测数据集的卖点是 YOLOV5 目录格式训练集 1836 张加验证集 458 张每张图一个同名 txt理论上解压就能训。但格式规整不代表没坑类别 id 与 classes.txt 顺序、空标签文件、小目标与 img size 的取舍都会决定你看到的是 mAP 75 还是 mAP 25。这篇把目录结构、标注格式、可视化脚本、训练前检查和踩坑点一次讲透适合刚接触缺陷检测的新手也适合想拿工业数据补训练集的熟手。2. 目录结构与标注格式images / labels 如何映射到 10 类焊接缺陷2.1 解压后的目录树train / val 划分与同名 txt 配对关系YOLOV5 官方推荐的目录结构其实非常固定images 目录放图片labels 目录放同名 txttrain、val 各自一个子目录。这份数据集的摘要里写的是训练集在 datasets-images-train、验证集在 datasets-images-val按最常见的 YOLOV5 惯例理顺之后完整结构基本长这样datasets/ ├── images/ │ ├── train/ │ │ ├── 000741.jpg │ │ ├── 001224.jpg │ │ └── ... │ └── val/ │ ├── 000002.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── 000741.txt │ │ ├── 001224.txt │ │ └── ... │ └── val/ │ └── ... └── classes.txt有几个细节直接决定后续训练顺不顺。训练集 1836 张图对应 1836 个 txt验证集 458 张对应 458 个 txt两边数量完全一致。图片和标签的文件名必须一模一样只是后缀不同YOLOV5 训练时按文件名去 labels 目录找对应 txt。classes.txt 里的顺序就是类别 id 顺序这个顺序在训练阶段不能随便调整否则以前标好的数字全部错位。我一般拿到数据集先做一次配对校验一个快速方法是把两边文件名排序后 diffls datasets/images/train | sed s/\.jpg$// | sort train_img.txt ls datasets/labels/train | sed s/\.txt$// | sort train_lbl.txt diff train_img.txt train_lbl.txt | head -20diff 没有输出说明两边文件名完全一致。sed 的作用是把后缀去掉只看文件名主体sort 保证两边顺序一致再对比。只要 diff 有输出就说明存在有图没标签或者有标签没图的情况这种文件如果不清理训练时会出现缺失警告严重时直接跳过整批数据。2.2 一条 txt 标注的五个数字class_id 与归一化坐标的读写规则随便打开一个标签文件内容格式是固定的一行一个目标总共五个数字3 0.451172 0.612000 0.033203 0.042000五个数字的含义依次是类别 id、归一化中心点 x、归一化中心点 y、归一化宽度 w、归一化高度 h。全部是 0~1 之间的小数真实像素坐标等于归一化值乘以图像宽高。拿上面这条举例图像尺寸 2048x1000w0.033203 换算成像素宽度就是 0.033203×2048 ≈ 68 像素属典型中小缺陷。这里最容易翻车的是和 COCO 格式混用。COCO 用的是 x_min、y_min、w、h 的绝对像素坐标YOLO 用的是归一化中心点加宽高两种格式混在一起画出来的框全是偏的。我习惯写一个解析脚本把归一化坐标还原成像素坐标方便看单条标注的实际情况from pathlib import Path label Path(datasets/labels/val/000741.txt) img_w, img_h 2048, 1000 for line in label.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: print(f异常行{line}) continue cid, xc, yc, w, h map(float, parts) x1 (xc - w / 2) * img_w y1 (yc - h / 2) * img_h x2 (xc w / 2) * img_w y2 (yc h / 2) * img_h print(f类别{cid:.0f} 像素框({x1:.0f}, {y1:.0f}) - ({x2:.0f}, {y2:.0f}))逻辑说明把归一化坐标还原成像素坐标排查某一类缺陷的实际尺寸和位置是否合理。参数说明cid 转成整数显示如果发现 x2 超过 2048、y2 超过 1000说明这条标注越界了需要回查原图。这也是后面训练前校验脚本的基础逻辑。2.3 统计 10 个类别的样本分布哪些缺陷少到需要重点关照焊接缺陷数据集的典型问题是类别极度不平衡。穿孔这种常见缺陷可能有几百个标注框压痕、内含物这类可能只有几十个甚至某个类别在验证集里只有个位数样本。用脚本跑一遍分布心里才有底from collections import Counter from pathlib import Path def count_labels(label_dir): stat Counter() for txt in Path(label_dir).glob(*.txt): for line in txt.read_text().strip().splitlines(): if line.strip(): stat[int(line.split()[0])] 1 return stat train_stat count_labels(datasets/labels/train) val_stat count_labels(datasets/labels/val) with open(datasets/classes.txt) as f: names [x.strip() for x in f] for i, n in enumerate(names): print(f{i}: {n}: train{train_stat[i]} val{val_stat[i]})逻辑说明逐行读取所有标签文件用 Counter 统计每个类别 id 出现的次数。参数说明classes.txt 的每一行对应一个类别名称第几行就是 id 几。如果某个类别在 val 里只有几个标注训练出来的模型对这个类别的 recall 基本不会好看后面 6.1 节讲的增强策略就得重点往这个方向偏。3. show.py 可视化脚本零配置画框验证标注质量的正确姿势3.1 show.py 在做什么随机抽图、读同名 txt、OpenCV 画框保存数据集附带的 show.py 描述是“随机传入一张图片即可绘制边界框并保存在当前目录”。我拆开逻辑看实现思路很标准从图片目录随机挑一张图按文件名去 labels 目录找同名 txt逐行解析五个数字乘回 2048x1000 尺寸用 OpenCV 画矩形框最后 imwrite 保存到当前目录。核心流程等价于下面这段代码import cv2 import random from pathlib import Path image_dir datasets/images/train label_dir datasets/labels/train out_dir vis_output Path(out_dir).mkdir(exist_okTrue) img_path random.choice(list(Path(image_dir).glob(*.jpg))) label_path Path(label_dir) / (img_path.stem .txt) img cv2.imread(str(img_path)) h, w img.shape[:2] with open(label_path) as f: for line in f: cid, xc, yc, bw, bh map(float, line.split()) x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, str(int(cid)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) out_name img_path.stem _vis.jpg cv2.imwrite(str(Path(out_dir) / out_name), img) print(saved:, out_name)逻辑说明img_path.stem 取文件名主体不带后缀拼出对应标签路径坐标全部还原成像素值后画框。参数说明(0,0,255) 是 BGR 顺序的红色框线宽 2putText 在框左上角画类别 id循环处理一行一个目标一个文件画多个框不需要额外逻辑。3.2 不用改代码直接跑随机抽图与输出位置的两种处理原脚本设计成无需修改就能跑一般是因为它把图片目录和标签目录写死成了数据集的标准路径或者自动按传入文件的目录推断标签目录。如果你想把验证集也看一遍常见做法是改 image_dir 和 label_dir 两个路径再执行python show.py ls vis_output/运行后会在输出目录生成类似 000741_vis.jpg 的文件。这里我一般注意两点一是输出目录不要直接设在 datasets/images 内部否则检查用的图片会被写进训练集目录污染数据二是多跑几次show.py 每跑一次是随机抽一张想大面积检查就直接写个循环跑 20 次或者把 random.choice 改成遍历目录一次输出所有验证图的可视化结果。3.3 可视化能筛出四类问题串类别、出界、漏标与小目标丢失可视化不是跑通就完事关键是从画框结果里读数据质量。第一类是串类别框明显贴着一个压痕缺陷但角标数字对应的是折痕说明标注阶段就归错了类这种错类样本直接污染训练。第二类是坐标出界框超出图像边界说明归一化换算有问题回头查原始 txt。第三类是漏标图上肉眼可见的长条缺陷没有框这种漏标会让模型学会“看不见”比错标还难处理。第四类是小目标淹没框虽然正确但缺陷只有二三十像素在 2048x1000 的大图里看得很清楚一旦缩到 640 输入尺寸特征就没了。这四类问题里前两类需要在训练前处理后两类需要在训练配置层面处理。可视化这一步是我每次拿到标注数据后雷打不动的第一个动作比看任何统计报告都直观。4. 用 YOLOV5 训练前必做的四项检查dataset.yaml 到 img size 取舍4.1 dataset.yaml 的路径、nc、names 三者必须一致YOLOV5 训练的数据配置全部集中在 dataset.yaml内容不多但每个字段都关键train: datasets/images/train val: datasets/images/val nc: 10 names: 0: 穿孔 1: 折痕 2: 压痕 3: 内含物 # 其余类别按 classes.txt 顺序补齐train 和 val 指向图片目录不要指向 labels 目录这一点写错会直接报找不到图片。nc 必须等于 classes.txt 里的行数。names 的字典顺序必须和 classes.txt 一致如果 classes.txt 里第 5 行是压痕这里 names 的 4 就应该是压痕写错不会让训练崩掉但会让混淆矩阵完全没法读val 阶段你会看到一堆无法解释的错误归类。顺便说一句如果把这套数据喂给 YOLOv8 或更新的版本dataset.yaml 的写法基本一样names 顺序规则也通用换框架不用改数据集本身。4.2 训练入口命令与 img size 取舍640 直接训还是 1280 保小目标标准训练命令长这样python train.py --data weld.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --project runs/weld参数说明--img 640 是默认输入尺寸--batch 16 在 8G 显存上勉强够跑--epochs 100 对 2294 张图的数据集来说不算多。关键问题在 --img。焊接缺陷里大量小目标2048x1000 的图缩到 640相当于把画面压到三分之一大小一个 68 像素的穿孔缩完后只剩约 21 像素再经过 stride 32 的下采样可能只剩一个特征点。我遇到这种尺寸的工业数据一般先跑一轮 640 看 PR 曲线如果小类别 recall 明显低就换 --img 960 或 1280代价是显存占用翻倍batch 要跟着降到 8 甚至 4。还有一个实际经验不要第一次就上 yolo5x918MB 的数据量配 10 个类别s 或 m 模型足够看出数据本身的问题。跑大模型前先用小模型把数据链路验证通再换大的省时间也省显存。4.3 训练前快速校验脚本缺失标签、空文件与越界坐标一次扫完训练前我会固定跑一次校验脚本把三类低级错误全部扫出来from pathlib import Path def check_pair(img_dir, lbl_dir): imgs {p.stem for p in Path(img_dir).glob(*.jpg)} lbls {p.stem for p in Path(lbl_dir).glob(*.txt)} no_lbl imgs - lbls no_img lbls - imgs if no_lbl: print(缺标签:, list(no_lbl)[:5], 共, len(no_lbl)) if no_img: print(缺图片:, list(no_img)[:5], 共, len(no_img)) empty [p for p in Path(lbl_dir).glob(*.txt) if p.stat().st_size 0] if empty: print(空标签:, len(empty), empty[:3]) for txt in Path(lbl_dir).glob(*.txt): for line in txt.read_text().strip().splitlines(): vals list(map(float, line.split())) if len(vals) ! 5: print(异常字段数:, txt, line) break _, xc, yc, w, h vals if not (0 xc 1 and 0 yc 1 and 0 w 1 and 0 h 1): print(越界坐标:, txt, line) break逻辑说明用集合差找图片和标签的缺失对用文件大小查空标签逐行检查五个字段的数量和取值范围。参数说明坐标越界判断只做了 0~1 范围检查如果想查中心点加宽高后是否超出图像边界需要按 2.2 节的方式乘回像素值再判断。这套脚本跑完没有任何输出数据链路才算基本干净。5. 常见问题与排查焊接缺陷数据集训练时的 5 个典型翻车点5.1 训练时报 No labels found现象train.py 启动后日志大量出现 WARNING提示找不到标签或者 loss 完全不动。原因最常见的是 dataset.yaml 的 train 路径写成了 labels 目录其次是 images 和 labels 里有文件名配对不齐的文件第三种是 txt 文件里全是空行YOLOV5 认为它没有标注。解决用 4.3 节的校验脚本先跑一遍重点看缺标签和空标签两项。路径问题直接检查 yaml 里 train 指向的是 images 还是 labelslabels 目录下的文件名后缀是 .txt 而不是 .jpg路径指错以后索引文件全部为空。5.2 训练能跑但 mAP 低可视化看框又正常现象训练 50 轮 mAP 一直不到 0.2但拿 show.py 随机看几张图框都贴得挺好。原因这个现象在焊接数据上最常见的解释是 img size 太小。2048x1000 的原图缩到 640小缺陷特征下采样后丢了另一个可能是类别分布不平衡模型把少数类全部预测成多数类。解决先用第 2.3 节的统计脚本确认类别分布再用 --img 960 训 20 轮对比同一批验证集上的 mAP。如果 960 有明显提升说明问题确实在输入尺寸。如果提升不大再看混淆矩阵确认是不是某个类别被系统性吃掉。5.3 预测时同一缺陷出多个重叠框现象模型输出图上同一个穿孔同时被两三个框框住NMS 没有压干净。原因一是原始标注里同一个缺陷被标了两行坐标几乎一致二是小目标聚集区域模型预测出大量重复框三是置信度阈值定得太低。解决先去原始 txt 里查重复行坐标差值小于几个像素的重复标注直接删掉一行。然后把 --conf-thres 从默认 0.25 提到 0.4 试试重叠框通常会少一半。如果还是多检查数据增强里 mosaic 是否把小缺陷复制出了重影。5.4 验证集 mAP 很高现场实测漏检严重现象val 上 mAP 0.8换几张没见过的焊接图上去漏掉一大片。原因这种落差一般是数据划分的问题某个容易的批次被分进了 val难例全留在 train或者训练集和验证集来自同一批焊接件的不同角度模型学了表面纹理而不是缺陷本身。解决按焊接工艺批次重新划分数据集保证同一批工件的图不要同时出现在训练集和验证集另外把光照、角度变化做成增强项逼模型学缺陷形状而不是纹理背景。5.5 训练到一半爆显存换小 batch 又影响精度现象--batch 32 跑不到 10 轮就 CUDA out of memory改 --batch 8 能跑但收敛变慢。原因2048x1000 的大图虽然训练时会缩放到 640但 mosaic 增强会同时拼 4 张图实际占用的内存比想象高模型越大激活值越吃显存。解决先降 batch这是最稳妥的如果 batch 降到 8 还是爆检查是不是开了 --rect 或缓存图片到显存的选项。另一个有效做法是把 mosaic 概率从默认的 1.0 降到 0.5训练速度和显存占用都会改善代价是部分增强效果减弱。6. 增强与验证细节小样本缺陷类别多拿几个点 mAP 的落地做法6.1 不平衡样本的增强策略mosaic 概率和类别加权怎么调按第 2.3 节的统计结果哪个类别标注框少就往哪个方向加重增强。常见做法是修改数据增强配置中的 mosaic 概率默认 hyp 里 mosaic1.0 表示每张训练图都做 mosaic 拼接这会让少数类样本被高频重复组合反而容易过拟合。我一般会把 mosaic 降到 0.7 左右同时不开 mixup 或把 mixup 设到 0.1焊接缺陷的边界很细mixup 把两张图透明叠加后小目标的边界信息会被稀释得很厉害。如果少数类实在少到和多数类差一个数量级可以选择给损失函数做类别加权。YOLOV5 的 hyp 配置里可以通过修改 cls 系数调节分类损失的权重对少数类更敏感一些。这一步不是必须但做完通常能让压痕、内含物这类小类别的 recall 提升几个点。6.2 提前用 val.py 看混淆矩阵和 PR 曲线别等 100 轮训完再看很多人习惯训完 100 轮再开验证等结果出来发现某个类别完全没学会又得从头训。我自己的习惯是先用 20 轮小规模训练快速验证一轮用下面的命令在验证集上出混淆矩阵和 PR 曲线python val.py --data weld.yaml --weights runs/weld/exp/weights/best.pt --img 640 --save-json --save-conf逻辑说明val.py 会遍历验证集所有图片输出每个类别的 precision、recall 和 mAP同时生成混淆矩阵图。--save-json 用于导出 COCO 格式的预测结果方便二次分析--save-conf 会保存每条预测的置信度。读混淆矩阵时重点看主对角线之外的大数值块比如折痕那一列里大量真实穿孔被预测成了折痕说明这两个类别在特征空间里高度重叠小目标分辨率不足时最容易出现这种互相吞并。这时候再决定是换更大的 img size 还是调整类别权重比训完 100 轮翻车后再补救省太多时间。自从一次焊接缺陷项目在最后检查阶段才发现混淆问题后我每次拿到新数据集都强制走一遍这个流程先跑 show.py 可视化再跑校验脚本扫配对和越界然后 20 轮小训练看混淆矩阵最后才定最终参数。整套流程半小时内能完成但能省下后面好几天返工的时间希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →