简介:这份资源面向从事工业质检、焊接工艺检测及计算机视觉方向的研究者与开发者,提供一套可直接用于目标检测模型训练的焊接缺陷数据集,帮助解决焊接缺陷样本稀缺、标注成本高的问题。压缩包共约2000个文件,以1999个xml标注文件和1个说明txt为主,整体约48.35MB,内含JPEGImages图片、Annotations标注与labels标签三类目录,图片与标注一一对应,便于直接接入YOLO或VOC训练流程。数据集覆盖烧穿、污染、良好焊缝、未完全融合、渗透不足、错位共6类标签,总框数2685个,各类别框数分布较为均衡,图片分辨率清晰且未做数据增强,适合作为基线训练或对比实验的原始素材。目前已有314人学习下载,读者可据此快速搭建焊接缺陷检测实验环境,理解多类别缺陷的标注规范与类别分布,为模型选型、数据增强策略及精度评估提供参考。
1. 焊接缺陷检测数据集:6类2684张的YOLO+VOC双格式到底怎么用
拿到一个标注好的焊接缺陷数据集,第一反应往往不是兴奋,而是怀疑——2684张够不够训一个能上产线的模型?6个类别是不是分得太粗?YOLO和VOC两套格式同时给,是省事还是埋坑?我最初接触焊接缺陷检测这个方向时,踩过的最大一个坑就是直接拿COCO预训练权重硬套,结果气孔和夹渣两类在验证集上几乎分不开。焊接缺陷检测属于典型的工业小目标检测场景,缺陷区域在整张焊缝图像里占比很小,背景纹理又高度重复,这跟车辆检测数据集bdd100那种大目标、强语义的场景完全不是一回事。这个数据集的价值在于它把6类常见焊接缺陷——气孔、夹渣、裂纹、未熔合、未焊透、咬边——做了统一标注,并且同时提供YOLO格式和VOC格式,意味着你不需要自己写格式转换脚本就能直接对接YOLOv5/v8系列和Faster R-CNN这类两阶段检测器。适合谁用?如果你正在做工业质检方向的落地,或者想找一个真实缺陷样本来验证自己的目标检测pipeline,这个规模的数据集刚好够你做完整的训练、验证、调参和导出onnx模型的全流程。2684张不算大,但焊接缺陷的类间差异本身就比自然图像小,关键看你怎么用增强和损失函数把边界撑开。
2. 先搞清楚6类缺陷的标注逻辑和格式差异
2.1 焊接缺陷的6个类别在实际标注中长什么样
气孔在图像里通常表现为圆形或椭圆形的暗斑,边缘相对清晰,但尺寸变化极大,小的可能只有十几个像素,大的能占到焊缝宽度的三分之一。夹渣则是不规则形状的暗色区域,经常沿着焊缝走向呈条带状分布,和背景的对比度比气孔更低。裂纹是最难标的一类,细长、分叉、走向随机,标注时很容易漏掉细小分支。未熔合和未焊透在视觉上非常接近,前者是焊缝与母材之间没融合,后者是根部没焊透,两者的区别往往需要结合焊接工艺参数才能判断,纯靠图像标注时边界模糊。咬边是焊缝边缘的凹槽,通常沿着焊缝两侧呈线状分布。
这6类在VOC格式里用<name>标签区分,在YOLO格式里用类别索引0到5对应。实际标注时最容易出问题的是夹渣和未熔合的混淆,以及裂纹的漏标。我见过不少公开数据集把这两类合并成“其他缺陷”,但这个数据集坚持分6类,说明标注时是有工艺背景的人参与的。你拿到数据后第一件事应该是统计每类的实例数量和平均bbox面积,如果某一类实例数少于200,训练时就要考虑过采样或者focal loss加大该类权重。
2.2 YOLO格式和VOC格式的目录结构差异
VOC格式的标准结构是Annotations放XML、JPEGImages放原图、ImageSets/Main放训练验证划分文件。每个XML里包含图像的宽高、每个目标的<bndbox>坐标(xmin、ymin、xmax、ymax)和类别名。YOLO格式则是每张图对应一个.txt文件,每行是class_id x_center y_center width height,全部归一化到0到1之间。两种格式的坐标体系不同,VOC是绝对像素坐标,YOLO是归一化中心点坐标,转换时最容易翻车的地方是归一化时的除零问题和坐标越界。
import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h, class_map): tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.findall('object'): cls_name = obj.find('name').text if cls_name not in class_map: continue cls_id = class_map[cls_name] 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) # 裁剪到图像边界内,防止标注越界导致归一化后坐标异常 xmin = max(0, min(xmin, img_w - 1)) xmax = max(0, min(xmax, img_w - 1)) ymin = max(0, min(ymin, img_h - 1)) ymax = max(0, min(ymax, img_h - 1)) if xmax <= xmin or ymax <= ymin: continue # 跳过无效框 x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") return lines这段代码的关键点有三个:一是坐标裁剪,工业图像里标注人员偶尔会把框拉到图像外面,不裁剪的话归一化后会出现负数或大于1的值,YOLO训练时直接报错;二是无效框过滤,xmax小于等于xmin的框要丢掉,否则w为负;三是保留6位小数,YOLO官方实现里对精度不敏感,但保留6位能避免小目标归一化后的精度损失。class_map需要你自己定义,比如{'气孔':0, '夹渣':1, '裂纹':2, '未熔合':3, '未焊透':4, '咬边':5},顺序要和训练时的data.yaml里names列表一致。
2.3 用脚本一键校验两种格式的一致性
拿到数据集后不要急着开训,先写个校验脚本确认YOLO的txt和VOC的XML描述的是同一批标注。常见的问题是转换脚本跑了两遍,或者部分图像只有VOC没有YOLO。校验逻辑很简单:遍历所有图像,检查对应的txt和xml是否都存在,然后随机抽100张对比转换后的坐标是否一致。
import os, random def validate_consistency(img_dir, yolo_dir, voc_dir, class_map, sample=100): imgs = [f for f in os.listdir(img_dir) if f.endswith(('.jpg','.png'))] missing = [] for img in imgs: stem = os.path.splitext(img)[0] if not os.path.exists(os.path.join(yolo_dir, stem+'.txt')): missing.append(stem) if not os.path.exists(os.path.join(voc_dir, stem+'.xml')): missing.append(stem) print(f"缺失标注的文件数: {len(missing)}") # 随机抽样对比坐标 for stem in random.sample([os.path.splitext(f)[0] for f in imgs], min(sample, len(imgs))): xml_path = os.path.join(voc_dir, stem+'.xml') txt_path = os.path.join(yolo_dir, stem+'.txt') # 这里调用前面的voc_to_yolo再和txt逐行对比 # 实际使用时建议把差异超过1e-4的行打印出来校验通过后再做训练集、验证集、测试集的划分。我一般按7:2:1切,但如果某类缺陷实例数少于300,会在划分时做分层抽样,保证每个子集里都有该类样本。焊接缺陷数据集的6类分布往往不均衡,气孔和咬边的实例数通常远多于裂纹和未焊透,划分时不做分层的话,验证集里可能一个裂纹都没有,mAP曲线会非常难看。
3. 用YOLOv8跑通焊接缺陷检测的最小训练流程
3.1 环境配置和data.yaml的写法
YOLOv8的环境配置比v5干净很多,pip install ultralytics基本能搞定,但要注意PyTorch版本和CUDA的匹配。如果你在AGX Orin上搭建YOLO环境,需要装JetPack对应的torch轮子,不能直接pip install torch。普通x86机器上,pip install ultralytics会自动拉取合适的torch版本。装完后yolo checks能看环境是否正常。
data.yaml是训练的核心配置文件,焊接缺陷检测的写法如下:
path: /data/weld_defect train: images/train val: images/val test: images/test nc: 6 names: ['porosity', 'slag', 'crack', 'lack_of_fusion', 'incomplete_penetration', 'undercut']path是数据集根目录,train/val/test是相对路径。nc必须等于6,names的顺序必须和YOLO txt里的class_id严格对应。我见过有人把names写成中文导致训练时标签乱掉,YOLOv8虽然支持中文路径,但names建议用英文或拼音,避免编码问题。另外path不要用相对路径,训练时工作目录一变就找不到数据。
3.2 训练命令和6个必调参数
最小训练命令就一行:
yolo detect train data=/data/weld_defect/data.yaml model=yolov8s.pt epochs=200 imgsz=640 batch=16 workers=4但直接跑这个命令大概率效果一般,焊接缺陷检测有6个参数必须根据数据特点调:
| 参数 | 建议值 | 理由 |
|---|---|---|
| imgsz | 640或960 | 裂纹和未焊透目标小,640以下会丢细节,960显存不够就640 |
| batch | 8到16 | 2684张图,batch太大容易过拟合,太小BN不稳定 |
| lr0 | 0.001到0.01 | 小数据集用0.001,配合cosine调度 |
| mosaic | 0.5到1.0 | 焊接缺陷背景重复,mosaic能增加场景多样性,但裂纹拼接后可能不连续,建议0.5 |
| fl_gamma | 1.0到2.0 | 类别不均衡时开focal loss,气孔和咬边多的数据集建议1.5 |
| patience | 30到50 | 小数据集收敛快,patience太大浪费时间 |
imgsz的选择要看你显卡显存,8G显存跑640的yolov8s大概占6G,跑960会OOM。如果裂纹在640下标注框小于8x8像素,那必须上960,否则下采样32倍后特征图上一个点都占不到。mosaic对焊接缺陷是把双刃剑,增强后气孔和夹渣的形态更丰富,但裂纹被拼接到不同背景后可能断裂成几段,标注框还是原来的,模型会学到错误的连续性。我的血泪经验是裂纹类占比高时mosaic降到0.3,甚至关掉。
3.3 训练过程中的关键监控指标
YOLOv8训练时会输出box_loss、cls_loss、dfl_loss和mAP50、mAP50-95。焊接缺陷检测最需要盯的是每个类别的AP,而不是总体mAP。如果气孔AP到0.9但裂纹只有0.3,说明模型在裂纹上欠拟合。这时候不要急着加epoch,先看验证集的预测可视化,大概率是裂纹的标注框太细,模型在anchor匹配阶段就丢了。
另一个关键指标是cls_loss的下降曲线。如果cls_loss震荡不降,通常是类别不平衡导致的,气孔和咬边的梯度淹没了裂纹和未焊透。解决办法是在data.yaml里加cls_pw或者用fl_gamma。YOLOv8默认的分类损失是BCE,对不平衡数据不如focal loss友好。我一般会在训练到50epoch时看一次混淆矩阵,如果裂纹被大量预测成夹渣,说明这两类的特征在浅层就混了,需要加更深的主干或者用更高分辨率。
4. 焊接缺陷检测的避坑与排查记录
4.1 现象:mAP50很高但实际推理全是误检
原因:验证集和训练集的背景分布太接近,模型学到了背景捷径。焊接缺陷数据集的图像往往来自同一批焊缝,背景纹理高度一致,模型只要记住“这个纹理区域有缺陷”就能在验证集上拿高分,但换一批焊缝就崩。
解决:划分验证集时按焊缝编号或拍摄批次切分,不要随机切。如果数据集没有批次信息,用图像哈希做聚类,把相似背景的图分到同一子集。另外训练时开mixup和copy_paste增强,强迫模型关注缺陷本身而不是背景。
4.2 现象:裂纹类AP始终低于0.4
原因:裂纹的标注框长宽比极端,YOLO的anchor匹配策略对细长目标不友好。默认anchor是正方形为主,裂纹的宽高比可能到1:20,匹配不到合适的anchor。
解决:用yolo detect train ... anchor_t=4.0放宽anchor匹配阈值,或者改用YOLOv8的anchor-free分支。更彻底的办法是把裂纹单独切patch训练一个二分类模型,再和主检测器做级联。我试过在640输入下裂纹AP只有0.35,切到960后涨到0.52,说明分辨率是瓶颈。
4.3 现象:训练loss正常但导出onnx后推理结果全乱
原因:YOLOv8导出onnx时默认不包含后处理,输出是原始特征图,需要自己写decode。很多人直接拿onnx输出当检测框用,坐标全是乱的。
解决:导出时加nms=True让onnx包含NMS,或者用yolo export model=best.pt format=onnx opset=12 simplify=True。推理时确认输入图像的预处理和训练一致,特别是归一化和letterbox的padding值。焊接缺陷图像如果是灰度图,训练时YOLO会复制成3通道,导出后推理也要做同样处理。
4.4 现象:VOC格式的XML里类别名有空格或大小写不一致
原因:标注人员手写XML时把“气孔”写成“气孔 ”或者“Lack_of_fusion”写成“lack_of_fusion”,转换脚本按字符串匹配时漏掉这些类。
解决:转换前先统计所有XML里的<name>文本,做strip和lower处理,建立映射表。不要直接信任原始标注的类别名,工业数据集里这种不一致非常常见。我一般会写个脚本把所有类别名打印出来人工确认一遍,再写死class_map。
4.5 现象:训练到后期验证集mAP突然掉点
原因:小数据集过拟合,模型开始记忆训练样本。2684张图训200epoch,后50epoch大概率在过拟合。
解决:开patience=30早停,或者用cos_lr让学习率在后半程降下来。另外weight_decay从默认的0.0005加到0.001,dropout在分类头加0.2。如果掉点发生在mosaic关闭的那个epoch,是正常的分布偏移,等几个epoch会恢复。
5. 把2684张用到极致:小数据集下的增强策略和验证技巧
2684张对于6类目标检测来说偏少,但焊接缺陷的特殊性在于类内差异小,模型需要学的特征维度比自然图像低。我的经验是把增强做狠一点,但要有针对性。几何增强里degrees开到10到15,焊接缺陷的走向在真实场景里有角度变化,但不要开到90,裂纹的走向是有工艺意义的。translate开到0.2,scale开到0.5,shear开到5。颜色增强里hsv_h开到0.015,hsv_s和hsv_v开到0.7,焊接图像在不同光照下灰度变化大,颜色增强能提升鲁棒性。
但有两类增强要慎用:flipud垂直翻转对焊接缺陷是危险的,咬边和未熔合在焊缝的上下位置有工艺含义,翻转后语义变了。mosaic前面说过,裂纹多的时候降到0.3。copy_paste对气孔和夹渣很有效,可以把缺陷实例复制到不同背景上,但裂纹复制后容易和背景纹理冲突,建议只对气孔、夹渣、咬边开。
验证阶段不要只看mAP,焊接缺陷检测的落地指标是漏检率和误检率。漏检一个裂纹的代价远大于误检一个气孔。我一般会在验证后单独统计每类的召回率,裂纹和未焊透的召回率低于0.85就不发版。测试时用yolo detect val ... conf=0.1把置信度阈值调低,看模型在低阈值下的召回上限,如果conf=0.1时裂纹还有漏检,说明模型本身没学到,不是阈值问题。
最后一个技巧是关于模型导出的。焊接缺陷检测最终要上产线,产线相机可能是灰度、可能是高分辨率、可能帧率要求30fps。导出onnx后用onnxruntime测一下单张推理时间,如果超过33ms,考虑用TensorRT或者换yolov8n。我习惯在训练完先导出onnx,用onnxsim简化后再测,简化前后推理速度能差20%。另外记得把预处理和后处理都写进推理脚本,别依赖ultralytics的python接口,产线上不一定能装。
这个方向值不值得做?如果你手上有真实的焊接缺陷数据,哪怕只有几百张,用这个数据集的6类定义和标注逻辑做迁移,比从零标起省至少两周。2684张训一个基线模型够用,但要上产线,至少还要补2000张不同批次、不同光照的图。我踩过最大的坑是拿一个批次的图训完直接上线,结果换了一批焊丝,气孔的对比度变了,模型召回掉了30%。后来养成的习惯是每批新数据先跑一遍验证集,看每类AP的波动,超过5个点就重新微调。希望帮到你。
本文还有配套的精品资源,点击获取