ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

焊接件表面缺陷检测数据集实战:2292张VOC+YOLO双格式10类缺陷训练全解析

焊接件表面缺陷检测数据集实战:2292张VOC+YOLO双格式10类缺陷训练全解析 简介这份资源是面向工业质检与计算机视觉方向的焊接件表面缺陷检测数据集适合从事目标检测算法训练、缺陷识别模型调优的研究者与工程师使用。数据同时提供Pascal VOC与YOLO两种标注格式包含jpg原图及一一对应的xml与txt标注文件可直接接入主流检测框架省去格式转换环节。压缩包为7z格式共约2000个文件以1999个xml标注文件和1个说明txt为主整体约256.38MB标注类别覆盖crease、crescent_gap、inclusion、oil_spot、punching、rolled_pit、silk_spot、waist_folding、water_spot、welding_line共10类焊接缺陷。目前已有913人学习下载说明其在同类工业缺陷数据中具备一定参考价值。读者可借助该数据集完成从数据加载、类别分布分析到模型训练与评估的完整流程尤其适合需要多类别细粒度缺陷样本的检测任务为焊接质量智能检测提供扎实的数据基础。1. 焊接件表面缺陷检测数据集2292 张 VOCYOLO 双格式的 10 类缺陷到底怎么用拿到一个标注好的焊接件表面缺陷数据集第一反应往往不是兴奋而是怀疑2292 张够不够训一个能上产线的模型10 个类别里有没有长尾到几乎没样本的VOC 和 YOLO 两套格式是不是同一批图的两份标注还是各标各的这些问题不搞清楚直接train.py一把梭最后大概率得到一个 mAP 看着还行、一上真实焊缝就疯狂漏检的黑匣子。这个数据集的价值在于它把「表面缺陷检测」这个工业质检里最刚需的场景压缩成了一个可以直接跑通的规模2292 张图、10 类缺陷、同时给 VOC XML 和 YOLO TXT 两种标注。它适合两类人——一类是想验证某个检测改进比如注意力、损失函数、neck 结构在工业缺陷上到底有没有用的算法同学另一类是要快速搭一个焊接质检 demo、先跑通再谈精度的工程同学。下面我按「先看清数据长什么样再决定怎么切、怎么训、怎么避坑」的顺序把这条链路讲透。2. 先摸清数据底细VOC 与 YOLO 双格式的对应关系和 10 类分布2.1 VOC XML 和 YOLO TXT 到底差在哪为什么两个都要留VOC 格式是每张图一个同名 XML缺陷框写在object里坐标是绝对像素值xmin/ymin/xmax/ymax还带name类别名。YOLO 格式是每张图一个同名 TXT每行一个框格式是class_id x_center y_center width height全部归一化到 0~1。两者描述的是同一批框只是坐标系和存储方式不同。保留双格式的实际意义在于VOC 方便你用 labelImg 打开复核、也方便转成 COCO 或做可视化YOLO 格式是 ultralytics 系列YOLOv5/v8/v11直接吃的输入。很多人拿到只有 VOC 的数据集第一步就得写转换脚本而这个数据集省掉了这一步。但要注意双格式不等于双份标注转换过程如果有精度损失比如归一化时四舍五入两边框可能对不齐所以第一步必须做一致性校验。2.2 用脚本统计类别分布和框尺寸别靠肉眼在训之前先跑一段统计脚本把每个类别的实例数、每张图的平均框数、框的宽高分布打出来。这一步决定了你后面要不要做重采样、要不要改 anchor。import os, glob import xml.etree.ElementTree as ET from collections import Counter voc_dir annotations # VOC XML 目录 cls_counter Counter() box_wh [] img_box_num [] for xml_path in glob.glob(os.path.join(voc_dir, *.xml)): tree ET.parse(xml_path) root tree.getroot() objs root.findall(object) img_box_num.append(len(objs)) for obj in objs: name obj.find(name).text.strip() cls_counter[name] 1 bnd obj.find(bndbox) w float(bnd.find(xmax).text) - float(bnd.find(xmin).text) h float(bnd.find(ymax).text) - float(bnd.find(ymin).text) box_wh.append((w, h)) print(类别实例数:, cls_counter.most_common()) print(平均每图框数:, sum(img_box_num) / len(img_box_num)) print(最大框数:, max(img_box_num), 最小框数:, min(img_box_num)) ws [b[0] for b in box_wh]; hs [b[1] for b in box_wh] print(框宽 min/mean/max:, min(ws), sum(ws)/len(ws), max(ws)) print(框高 min/mean/max:, min(hs), sum(hs)/len(hs), max(hs))逻辑说明遍历所有 XML用Counter统计类别频次同时收集每个框的宽高。参数上voc_dir指向解压后的 VOC 标注目录如果你的 XML 和图片混在一起改成对应路径即可。跑完重点看三件事——有没有某个类别实例数低于 50长尾需要过采样或专门增强、平均每图框数是不是远大于 1密集缺陷anchor 和小目标策略要调、框宽高最小值是不是只有几个像素小目标输入分辨率不能压太低。2.3 校验 VOC 与 YOLO 是否一一对应双格式最容易翻车的地方是「图有、XML 有、TXT 没有」或者类别 id 对不上。写个校验脚本把两边框数对齐检查一遍。import os, glob img_dir images voc_dir annotations yolo_dir labels imgs {os.path.splitext(os.path.basename(p))[0] for p in glob.glob(f{img_dir}/*.jpg)} xmls {os.path.splitext(os.path.basename(p))[0] for p in glob.glob(f{voc_dir}/*.xml)} txts {os.path.splitext(os.path.basename(p))[0] for p in glob.glob(f{yolo_dir}/*.txt)} print(图-XML 差集:, imgs - xmls) print(图-TXT 差集:, imgs - txts) print(XML-TXT 差集:, xmls - txts) # 抽查框数是否一致 import xml.etree.ElementTree as ET mismatch [] for stem in list(imgs xmls txts)[:200]: n_xml len(ET.parse(f{voc_dir}/{stem}.xml).getroot().findall(object)) with open(f{yolo_dir}/{stem}.txt) as f: n_txt len([l for l in f if l.strip()]) if n_xml ! n_txt: mismatch.append((stem, n_xml, n_txt)) print(框数不一致样本:, mismatch[:10], 共, len(mismatch))逻辑说明三个集合做差集任何非空差集都说明有文件缺失。抽查部分样本比对框数不一致的样本要单独拎出来看是标注错误还是转换 bug。参数上imgs xmls txts取交集保证只比对三边都存在的样本避免差集干扰。这一步做完你才对「2292 张」这个数字有底——它到底是图片数还是标注数有没有空标注图混在里面。3. 从 2292 张到可训练集划分、增强与 YOLO 目录组织3.1 训练/验证/测试怎么切才不泄漏工业缺陷数据最常见的泄漏是「同一焊缝的连续帧被分到训练和验证两边」导致验证集 mAP 虚高。2292 张如果来自若干条焊缝或若干次拍摄正确做法是按「拍摄批次/工件编号」分组切分而不是随机按图切。如果数据里没有批次信息退而求其次用感知哈希或图像相似度做聚类把相似图分到同一侧。import os, glob, shutil, random from sklearn.model_selection import train_test_split random.seed(42) stems [os.path.splitext(os.path.basename(p))[0] for p in glob.glob(images/*.jpg)] # 若有批次信息替换为按批次分组这里演示按 8:1:1 随机切 train, temp train_test_split(stems, test_size0.2, random_state42) val, test train_test_split(temp, test_size0.5, random_state42) for split, items in [(train, train), (val, val), (test, test)]: for sub in [images, labels]: os.makedirs(fdataset/{split}/{sub}, exist_okTrue) for s in items: shutil.copy(fimages/{s}.jpg, fdataset/{split}/images/{s}.jpg) shutil.copy(flabels/{s}.txt, fdataset/{split}/labels/{s}.txt) print(len(train), len(val), len(test))逻辑说明train_test_split两次调用实现 8:1:1。参数random_state42保证可复现。关键提醒——如果你的数据有批次字段把stems换成按批次聚合后的列表再切否则验证集不可信。切完检查三个 split 的类别分布是否接近长尾类如果只在训练集出现验证指标会失真。3.2 针对焊接缺陷的增强策略别照搬 COCO 那套焊接件表面缺陷的成像特点是金属反光强、缺陷与背景对比度低、缺陷形态细长裂纹或成片气孔、夹渣。通用增强里颜色抖动要慎用因为缺陷判据很大程度依赖灰度对比随机裁剪要控制幅度避免把细长裂纹裁断。我一般会开这几项mosaic提升小目标召回但焊接缺陷密集时可能引入不合理拼接建议 0.5 而非默认 1.0、hsv_h/s调小到 0.01 左右、degrees限制在 10 以内工件旋转角度有限、flipud/fliplr视拍摄方向决定。下面是对应的 YOLO 数据配置。# dataset/weld.yaml path: ./dataset train: train/images val: val/images test: test/images nc: 10 names: [crack, porosity, slag, undercut, overlap, spatter, burn_through, incomplete_fusion, crater, surface_scratch]逻辑说明nc必须和实际类别数一致names顺序必须和 YOLO TXT 里的class_id严格对应错一位整个训练就废了。path用相对路径方便迁移。这份 yaml 是 ultralytics 系列的标准入口训练时datadataset/weld.yaml即可。3.3 类别 id 映射表要单独存一份10 个类别的 id 映射一旦定下就不要改。建议单独存一个classes.txt每行一个类名行号即 id。转换脚本、可视化脚本、推理后处理都读同一份避免「训练时 id 是 A推理时 id 是 B」这种血泪事故。id类别名典型形态标注难点0crack细长线状边界模糊易与划痕混1porosity圆形小孔小目标密集时易漏2slag不规则块状与背景对比低3undercut沿焊缝边缘凹槽形态随焊缝走向变化4overlap焊瘤堆积与正常余高易混5spatter飞溅颗粒极小标注一致性差6burn_through烧穿孔洞样本少长尾7incomplete_fusion未熔合条带内部缺陷表面不明显8crater弧坑圆形尺寸小9surface_scratch表面划痕与裂纹难区分这张表不是摆设——标注一致性差比如 spatter 和 surface_scratch 边界模糊的类别训练时可以考虑合并或加权具体看你的业务能不能接受。4. 训练参数怎么设从 yolov8n 起步到 10 类收敛4.1 先用小模型跑通再换大模型2292 张、10 类属于中小规模。直接上 yolov8x 大概率过拟合而且调参周期长。我的习惯是先用 yolov8n 或 yolov8s 跑一个 baseline确认数据管线和类别映射没问题再决定要不要换大模型。yolo detect train \ datadataset/weld.yaml \ modelyolov8n.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ warmup_epochs3 \ cos_lrTrue \ patience30 \ projectruns/weld \ namebaseline_n逻辑说明modelyolov8n.pt用预训练权重起步小数据集上预训练能显著加速收敛。imgsz640是默认值如果统计发现小目标多框宽高最小值小于 16 像素提到 960 或 1280 再试。batch16按显存调显存不够就降 batch 并等比调 lr。patience30早停避免无效训练。cos_lrTrue余弦退火在中小数据集上通常比阶梯下降稳。4.2 关键参数anchor、损失权重、类别不平衡YOLOv8 是 anchor-free不用手动设 anchor但损失里的分类和框回归权重仍会影响长尾类。如果统计发现 burn_through 这类样本极少可以在训练时对稀有类做复制过采样或者用cls损失权重调整。ultralytics 默认不直接暴露每类权重常见做法是在数据集层面过采样稀有类图片。另一个容易忽略的是overlap_mask和mask_ratio分割任务才用检测任务不用管。检测里真正要盯的是box和cls的 loss 曲线如果 cls loss 一直不降多半是类别标注有噪声或 id 错位如果 box loss 震荡检查框坐标有没有越界归一化后应在 0~1。4.3 训练中该看哪些指标别只盯 mAPmAP50 是主指标但工业质检更关心召回率——漏检一个裂纹的代价远大于误报。训练时重点看metrics/recall和每类的 P-R 曲线。如果整体 mAP 不错但某类召回极低去混淆矩阵里看它被误判成了哪一类。焊接缺陷里 crack 和 surface_scratch、porosity 和 crater 是最容易互相混淆的两对混淆矩阵能直接暴露。# 训练后加载模型看混淆矩阵ultralytics 会在 runs 目录自动生成 from ultralytics import YOLO model YOLO(runs/weld/baseline_n/weights/best.pt) metrics model.val(datadataset/weld.yaml, splitval) print(mAP50:, metrics.box.map50) print(每类 AP:, metrics.box.ap50)逻辑说明model.val会输出每类 AP 和混淆矩阵图。参数splitval指定验证集。拿到每类 AP 后低于 0.5 的类别要单独分析——是样本太少、标注太乱还是该类本身视觉特征就不明显。5. 避坑与排查焊接缺陷数据集训练中最容易翻车的 5 个点5.1 现象训练 loss 正常下降但验证 mAP 始终在 0.1 以下原因类别 id 映射错位。YOLO TXT 里的class_id从 0 开始而你的names列表如果顺序和标注时不一致模型学到的就是错位映射。另一个可能是图片和标签文件名不匹配比如图片是001.jpg标签是001_1.txt导致大量样本被当成背景。解决跑一遍 2.3 的校验脚本确认每个 TXT 的 class_id 都在[0, nc-1]范围内且文件名与图片一一对应。再抽查几张图用可视化脚本把框画出来肉眼确认类别名和框位置对得上。5.2 现象小目标spatter、crater召回率极低原因输入分辨率 640 下几个像素的缺陷在特征图上几乎消失。或者 mosaic 增强把本就不多的小目标进一步缩小。解决把imgsz提到 960 或 1280降低 mosaic 概率到 0.3 以下在数据层面统计小目标占比如果超过 30%考虑用切片推理SAHI或专门的小目标检测头。别指望不改任何东西就能召回小飞溅。5.3 现象验证集 mAP 很高但拿真实产线图推理全是误报原因数据泄漏或域偏移。2292 张如果都来自同一批工件、同一光照验证集和训练集分布几乎一样mAP 虚高。真实产线的光照、角度、工件材质一变模型就崩。解决切分时按批次分组见 3.1如果条件允许留一批完全不同工况的图做测试集哪怕只有几十张。域偏移严重时优先补数据而不是调模型。5.4 现象训练到一半 loss 突然变 NaN原因学习率过大、batch 里有异常框坐标越界或宽高为 0、或者某张图标注了不存在的类别 id。解决先降lr0到 0.001 重跑再用脚本扫一遍所有 TXT过滤掉宽高为 0 或坐标超出[0,1]的行检查是否有 class_id 大于等于nc的脏标注。焊接数据集里手工标注的越界框并不少见。5.5 现象同一类别在不同图里标注粒度不一致原因多人标注或标注规范不统一。比如 spatter 有人标单个颗粒有人标一整片。解决这是数据质量问题不是训练能救的。抽检每个类别的 20 张图统一标注规范后重标争议样本。如果重标成本太高考虑把粒度不一致的类合并或者用cls损失权重降低噪声类影响。提示以上 5 条里5.1 和 5.3 是最致命的前者让训练直接无效后者让指标失去意义。拿到任何新数据集先做这两项检查再开训。6. 把 2292 张用出 2 万张的效果过采样、切片推理与模型集成数据量固定时提升空间主要在「怎么用」而不是「换多大模型」。第一个技巧是稀有类过采样统计出实例数最少的 2~3 个类在训练集里把这些图复制 2~3 份同时保持验证集不变。这比调损失权重更直接代价是过拟合风险所以配合早停和强增强使用。第二个技巧是切片推理SAHI。焊接缺陷里小目标多整图推理时小目标在降采样后信息丢失。把大图切成带重叠的小块分别推理再合并小目标召回能明显提升。代价是推理变慢适合离线质检或对召回要求极高的场景。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathruns/weld/baseline_n/weights/best.pt, confidence_threshold0.25, devicecuda:0 ) result get_sliced_prediction( test_weld.jpg, model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_dirsahi_out/)逻辑说明slice_height/width是切片尺寸overlap_*_ratio控制切片重叠避免边缘目标被切断。参数confidence_threshold按你的误报容忍度调工业场景通常设 0.25~0.4。切片推理对小目标提升明显但整图大缺陷可能被切碎所以最终结果要和整图推理做融合。第三个技巧是模型集成用 yolov8n/s/m 各训一个推理时做 WBF加权框融合。2292 张训三个小模型的总成本低于训一个超大模型且集成对小样本类更稳。我一般用 n 和 s 两个就够m 加进来提升有限但推理翻倍。最后一个习惯每次训完把best.pt、对应的weld.yaml、classes.txt和这次的数据切分脚本一起归档到一个带日期的目录。焊接缺陷数据集我前后迭代过十几版没有一次能靠记忆复原「当时用的是哪版切分」。这个习惯帮我省下的返工时间比任何调参技巧都值。希望帮到你。本文还有配套的精品资源点击获取
返回列表