☰
YOLOv5格式管道焊缝缺陷检测数据集制作与训练实战
2026/10/2 8:32:21 网站建设 项目流程

简介:面向目标检测与焊接质量检测场景,这份YOLOV5目录格式的管道焊接缝缺陷检测数据集包含good、bad两个类别,图片分辨率统一为800×800的RGB图像,可直接用于YOLOV5系列模型训练。压缩包共1995个文件,约93.27MB,主体为996张jpg图片和997个txt标注文件,另有1个可直接运行的py可视化脚本与1张png说明图;数据集已划分训练集和验证集,训练集908张图片及对应标签,验证集206张图片及对应标签,无需额外格式转换。目前已有196人学习下载。配合附带的可视化脚本,随机传入一张图片即可自动绘制边界框并保存到当前目录,可用于快速检查标注质量;整份资源适合需要开展管道焊缝缺陷检测、目标检测入门练习或YOLOV5数据准备的开发者使用。

1. 管道焊缝缺陷检测数据集:为什么 2 类 YOLOv5 格式就够用

拿到一批管道焊接缝的现场照片,想做缺陷检测,第一件事不是找模型,而是先确认数据集长什么样。这里说的「目标检测数据集(YOLOV5目录格式)」并不是某个特定项目,而是一种通用的数据组织方式:图片放在 images 目录,对应的标注文件按同名规则放在 labels 目录,每行一个目标的类别和边界框坐标。管道焊缝的缺陷场景通常只关心两类目标——比如气孔和裂纹,或者缺陷和正常焊道,所以类别数不需要多,2 类足够把模型训起来。

这个格式最大的价值在于它和 YOLOv5 的 data.yaml 配置、训练脚本、评估脚本完全打通。你从现场采集的几百张焊缝照片,只要按这个目录结构整理好,就能直接用 YOLOv5 训练自己的数据集,不需要改一行源码;配合标注工具导出成 txt,再写几行脚本划分训练集和验证集,整个流程半天内能跑通第一版。这套方案适合手里有现场图像但还没建立标注规范的团队,也适合刚接触目标检测的工程师快速验证缺陷检测的可行性。

2. YOLOv5 目录格式拆解:images 与 labels 的对应关系及标注规范

2.1 两个核心目录的命名规则与对应关系

YOLOv5 对数据集目录的要求非常固定。常见做法是在一个根目录下放 images 和 labels 两个子目录,每个子目录再按训练集、验证集拆分。结构如下:

pipe_weld_dataset/ ├── images/ │ ├── train/ │ │ ├── weld_001.jpg │ │ ├── weld_002.jpg │ │ └── ... │ └── val/ │ ├── weld_010.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── weld_001.txt │ │ ├── weld_002.txt │ │ └── ... │ └── val/ │ ├── weld_010.txt │ └── ... └── data.yaml

图片和标注文件靠「同名前缀」对应:weld_001.jpg对应的标注文件必须是labels/train/weld_001.txt。YOLOv5 训练时通过图片路径去推导 label 路径,规则是把 images 替换成 labels,把图片扩展名替换成 .txt。所以只要保持 basename 完全一致,路径层级可以灵活调整。

每个 txt 文件里的内容格式是:

<class_id> <x_center> <y_center> <width> <height>

比如一行0 0.532 0.447 0.214 0.132,代表 class_id 为 0 的目标框。四个坐标值都是相对图片宽高的归一化比例,取值范围 0~1。注意这里不是左上角和右下角坐标,而是中心点坐标加宽高。初次转换标注时最容易在这摔倒,后面会单独讲。

2.2 类别定义与 data.yaml 配置

2 类数据集在 data.yaml 里只需要指定两个路径和两个名字。常见做法是这样写:

path: pipe_weld_dataset # 数据集根目录 train: images/train # 训练图片目录 val: images/val # 验证图片目录 nc: 2 # 类别数量 names: ['porosity', 'crack'] # 类别名,顺序必须和标注txt里的class_id一致

names的顺序很关键,它决定了 class_id 0 是气孔还是裂纹。一旦训练中途改了顺序,之前所有标注文件里的 id 含义就全变了。我一般会在项目开始时先把类别名固定下来,用中文名也可以,但建议用英文,避免编码问题。path可以用绝对路径,也可以写相对路径,相对路径是相对于执行训练命令的工作目录。

还有一个容易忽略的细节:如果检测目标只有「缺陷」和「正常焊道」,那「正常焊道」这个类别意义不大——因为背景本身就是负样本,单独标正常焊道反而会让模型困惑。2 类的更合理切分是气孔与裂纹,或者表面缺陷与内部缺陷,具体取决于你的焊缝工艺类型。实际做管道焊缝检测时,气孔、夹渣、未熔合、裂纹是常见缺陷,如果现场数据里只有两类出现频率高,就只标这两类,类别数少对收敛速度和稳定性都是好事。

3. 标注到训练:把现场焊缝照片变成可训练数据集的过程

3.1 标注工具的选型与导出

标注是数据集制作里最耗时的一步。YOLOv5 目录格式要求 txt 文件,但标注工具原生导出的格式往往是 JSON 或 XML,所以需要经历「标注 -> 导出 -> 转换」三个环节。

常用标注工具里,LabelImg 可以直接导出 YOLO 格式,操作路径是:画框后选择 YOLO 保存格式,保存后在同目录生成同名 txt。但 LabelImg 维护较早,遇到大图或视频帧序列时体验一般。X-AnyLabeling 是更现代的选择,支持矩形框、多边形、自动标注辅助,导出时选 YOLO 格式即可。无论用哪个工具,最终产物必须是上面提到的五列 txt。

如果手头已有 VOC 格式的 XML 标注,转换脚本是绕不开的。下面这个脚本可以把单张图片的 XML 转成 YOLO txt:

import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_path, out_path, class_list): tree = ET.parse(xml_path) root = tree.getroot() img_w = int(root.find('size').find('width').text) img_h = int(root.find('size').find('height').text) lines = [] for obj in root.findall('object'): name = obj.find('name').text if name not in class_list: continue class_id = class_list.index(name) bndbox = obj.find('bndbox') xmin = float(bndbox.find('xmin').text) ymin = float(bndbox.find('ymin').text) xmax = float(bndbox.find('xmax').text) ymax = float(bndbox.find('ymax').text) x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h # 边界裁剪,防止归一化后越界 x_center = min(max(x_center, 0.0), 1.0) y_center = min(max(y_center, 0.0), 1.0) width = min(width, 1.0) height = min(height, 1.0) lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") with open(out_path, 'w') as f: f.write('\n'.join(lines)) # 使用示例:class_list 必须和 data.yaml 里的 names 顺序一致 class_list = ['porosity', 'crack'] convert_voc_to_yolo('weld_001.xml', 'weld_001.txt', class_list)

脚本逻辑分三段:解析 XML 拿到图片尺寸和目标框绝对坐标;将绝对坐标换算成归一化中心点与宽高;做一次边界裁剪防止越界。最后一步看着多余,实际很有用——标注时手滑把框画到图片边缘外,生成的坐标可能大于 1,训练时会导致 loss 异常甚至程序报错。裁剪能把这类脏数据挡在训练之前。

3.2 训练集与验证集的划分策略

标注完所有图片后,不能直接把全部数据丢进训练。YOLOv5 训练脚本会自动读取 images/train 和 images/val 两个目录,所以要提前按比例分配图片。常见做法是 8:2 或 9:1,管道焊缝这种缺陷样本分布不均匀的场景,我更推荐按缺陷类别做分层抽样,而不是简单随机划分。

import random import shutil import os random.seed(42) src_images = 'all_images/' src_labels = 'all_labels/' train_ratio = 0.8 images = [f for f in os.listdir(src_images) if f.endswith('.jpg')] random.shuffle(images) train_files = images[:int(len(images) * train_ratio)] val_files = images[int(len(images) * train_ratio):] for split, file_list in [('train', train_files), ('val', val_files)]: os.makedirs(f'dataset/images/{split}', exist_ok=True) os.makedirs(f'dataset/labels/{split}', exist_ok=True) for img in file_list: base = os.path.splitext(img)[0] shutil.copy(f'{src_images}/{img}', f'dataset/images/{split}/{img}') label_path = f'{src_labels}/{base}.txt' if os.path.exists(label_path): shutil.copy(label_path, f'dataset/labels/{split}/{base}.txt')

这段脚本值得一提的是随机种子固定,保证每次运行划分结果一致,方便复现实验。另一个点是把 txt 对应关系也一起拷贝,避免图片过去了标注没跟上。划分完可以顺手数一下两个 split 的文件数量比,确认没有极端失衡。

3.3 训练命令与超参数设置

YOLOv5 训练入口是 train.py,官方仓库里直接跑下面的命令即可:

python train.py \ --data pipe_weld_dataset/data.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --device 0 \ --name weld_exp1

几个参数按实际情况调:batch-size看显存,8G 显存跑 yolov5s 用 16 通常没问题,用 10G 以上显卡可以尝试 32;imgsz默认 640,如果焊缝缺陷是小目标,比如气孔直径只有十几个像素,建议先用 640 跑通流程,之后再用 1280 做对比实验;weights用官方预训练权重做迁移学习,比随机初始化收敛快很多,对几百张的小数据集尤其重要。

训练过程中重点看两个日志指标:box_loss 和 cls_loss。如果 cls_loss 在某个 epoch 后不再下降,说明类别区分度不够,可能原因包括标注框太粗糙或两类样本数量悬殊。训练结束后会生成 runs/train/weld_exp1 目录,里面的 weights/best.pt 和 weights/last.pt 分别是最优权重和最后一轮权重,后续推理用 best.pt。

4. 训练与评估阶段的避坑:常见问题与排查记录

4.1 loss 直接变成 nan:坐标越界和空标注文件

现象:训练刚跑几个 iteration,box_loss 输出 nan,程序随后崩掉。

原因:最常见的是标注 txt 里出现负数坐标或者大于 1 的坐标值,YOLOv5 在计算框损失时遇到非法值直接溢出。另一种情况是某些 txt 文件是空的,即图片存在但没有任何标注,这类图片在 mosaic 增强时会让标签矩阵出现空行,触发 nan。

解决:在训练前写一个检查脚本,逐行读取所有 label 文件,过滤掉空文件和越界行。更简单的方法是直接用下面这个命令扫一遍:

find labels -name '*.txt' -size 0 -delete

这条命令把 0 字节的标注文件删掉,但图片还在,模型会把它们当纯背景样本处理。如果空标注文件对应的图片本来就有缺陷,那说明是标注遗漏,需要补标;如果没有缺陷,删掉 label 文件反而对了。

4.2 mAP@0.5 很高但实际检测漏检:验证集图片与训练集重叠

现象:训练结束打印出的 mAP@0.5 到 0.95 都很漂亮,但把模型部署到现场采集的新图片上,漏检率明显偏高。

原因:训练前划分数据集时,同一根管道不同角度的照片可能被同时分进了训练集和验证集。这些图片背景高度相似,模型在验证集上的表现其实是「背答案」,不是真正的泛化。我遇到过最夸张的一次是 mAP@0.5 达到 0.97,换了一台管口的照片直接掉到 0.4。

解决:重新划分数据集时,按「管道编号」作为分组单位,而不是按单张图片。保证同一根管道的所有图片都进同一个 split。操作上先对文件名做前缀分组,再按组随机分配。另外现场验证时至少留 20 张完全没参与训练的照片做 final test,这组数据不进任何训练逻辑。

4.3 小目标气孔完全检不出:输入分辨率与锚框问题

现象:模型能检测裂纹这类长条缺陷,但气孔(直径十几个像素)几乎全漏。

原因:640 输入下,小目标在特征图上的尺寸只有几个像素,YOLOv5s 的 P3 特征图对这类目标表达能力不足。而且气孔样本量少,锚框尺寸分布偏向了裂纹这类大目标。

解决:先统计标注框的宽高分布。写一个小脚本读取所有 label 文件,统计 width 和 height 的中位数与分位数,如果大量框的宽度小于 0.05(即小于 32 像素),说明小目标占比高。这时有两个改动方向:第一,把 imgsz 提高到 1280,相当于让小目标在特征图上的像素翻倍;第二,关闭自动锚框的默认行为,在 data.yaml 里手动传入自适应锚框参数,YOLOv5 训练时会根据你的标注数据重新聚类锚框,只要不是用--noautoanchor显式关闭,默认会重新计算。多数场景下只调 imgsz 就能改善,代价是训练和推理速度下降,显存占用翻倍。

4.4 训练过程中验证集 loss 震荡剧烈:学习率与 mosaic 关闭时机

现象:前 50 个 epoch 验证集 loss 稳定下降,50 之后开始大幅波动,但训练集 loss 还在降。

原因:YOLOv5 默认训练轮次为 300,如果只设 100 轮,cosine LR 调度器在训练后期学习率降得太快,加上 mosaic 增强在最后 10 轮才关闭,两个因素叠加导致验证集表现不稳定。

解决:显式设置--cos关闭余弦退火,改用线性衰减;同时把 mosaic 关闭轮次提前,可以在训练到总轮次的 70% 时手动停掉增强。具体做法是改 train.py 里的close_mosaic参数,YOLOv5 新版支持在命令行传--close-mosaic 10,表示最后 10 轮关闭 mosaic。如果数据量只有几百张,建议总轮次设 150 而不是 100,给学习率衰减留足空间。

4.5 类别严重不均衡:气孔 2000 个框,裂纹只有 80 个框

现象:训练出的模型几乎只输出气孔,裂纹偶尔能测到但置信度很低。

原因:目标检测的类别不均衡不像分类任务那么容易通过 class weight 解决。YOLOv5 的 cls loss 默认对每个类别一视同仁,少样本类别在正负样本对撞中容易被淹没。

解决:两个手段配合。第一,样本少的类别做离线复制增强,用旋转、亮度抖动、加噪声生成额外样本,注意别把裂纹的形态学特征破坏掉;第二,把少样本类别的图片重复多份放进训练集,让每个 epoch 里这个类别出现次数增多。数据层面比改 loss 更可控,因为改 loss 权重容易让模型对多类别的误检率上升。

5. 提升焊缝缺陷检出率的实用技巧:数据增强与后处理调优

数据增强配置藏在 YOLOv5 的超参数文件 hyp.scratch.yaml 里。小数据集上我一般调整三个值:hsv_h、hsv_s和hsv_v,控制色相、饱和度和明度的随机扰动幅度。焊缝图像在不同光照条件下色温差异大,把hsv_v从默认 0.4 调到 0.5,能明显增强模型对明暗变化的鲁棒性。degrees和translate按需小幅度放开,旋转超过 30 度会让焊缝缺陷形态失真,不建议拉太高。

推理阶段的后处理同样值得调。YOLOv5 的 detect.py 支持--conf-thres和--iou-thres两个参数。管道焊缝场景我习惯把置信度阈值降到 0.15~0.2,因为漏检缺陷的代价远高于误检,多框出来几个可疑区域让质检员人工确认,比直接漏掉更安全。NMS 的 IoU 阈值默认 0.45,如果现场缺陷密集、互相靠近,把 IoU 阈值调到 0.3 可以减少重叠框的合并损失。同时开启--agnostic-nms,让不同类别的框之间也做抑制,防止气孔旁边紧贴裂纹时多出重复框。

最后分享一个我自己的处理习惯:训练结束后别急着部署,先用 best.pt 跑一遍验证集的全部图片,把预测结果可视化保存下来,逐张看漏检和误检的分布。漏检集中在哪种缺陷、哪种光照条件,比对后回到数据处理环节补样本,而不是盲目堆训练轮次。这套「数据 -> 训练 -> 后处理 -> 人工复核」的闭环,是我做管道焊缝检测项目时最稳定的流程。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询