ARTICLE DETAIL

资讯详情

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

YOLO焊缝缺陷识别实战:数据准备、模型训练与避坑指南

YOLO焊缝缺陷识别实战:数据准备、模型训练与避坑指南 简介基于YOLO的焊缝缺陷识别研究设计包围绕深度学习在工业视觉检测中的典型应用展开聚焦焊缝质量自动检测这一场景面向毕业设计、课程设计及智能质检方向的学习者提供从数据准备、模型训练到效果评估的完整工程参考。压缩包内共2000个文件以1090个txt标注文件与895张jpg焊缝图像为核心另有6个yaml配置、5个Python脚本、3个train/val/test缓存文件及1个说明文档整体93.41MB。目前已有59人学习下载包内脚本覆盖validate_dataset.py数据校验、train_ultralytics.py模型训练、evaluate_models.py多模型评估与detect_ultralytics.py缺陷检测并包含weld_dataset.yaml等配置可直接复现YOLO焊缝缺陷识别流程帮助使用者快速理解训练-验证-部署的完整链路。对需要现成标注数据、可运行代码和算法验证样例来支撑毕业设计或项目展示的读者这份资源提供了实用、完整的实操参考。1. 焊缝缺陷识别为什么选YOLO先看能不能跑再谈精度聊到基于YOLO的焊缝缺陷识别研究设计很多同行手里已经攥着一个 .zip 交付包满怀期待地解压、配环境、跑训练然后被数据集路径、显存不足、loss 变成 nan 轮番教育。焊缝缺陷检测这件事难点从来不在「要不要用深度学习」而在于工业场景里缺陷小、对比度低、样本又少传统机器视觉靠灰度阈值和形态学只能对付固定光源下的标准件换一条焊缝、换一种光照就得重新调参。YOLO 这类单阶段检测器把定位和分类合并成一个回归问题训练和部署链路短一张 640 分辨率的图上小目标也能有可观召回率这才成了机器人焊接、管道检测、压力容器探伤里最常见的落地方案之一。这篇笔记适合两类人一类是从 CV 转过来做质检项目想快速跑通一个可用 demo 去跟客户谈需求另一类是已经在用 YOLO 做通用目标检测但第一次碰焊缝这种低对比、高噪点、小目标的场景。我会按一份研究设计 zip 包的常见内容把数据准备、训练参数、指标分析、踩坑记录和打包复现讲透。先别急着追求 99% 的 mAP先让训练过程稳定跑通再看指标怎么一点点扣出来。2. 把焊缝缺陷标注成 YOLO 格式数据准备与目录约定2.1 标注工具、输出格式与目录结构无论你拿到的是原始焊缝 X 光片、红外热图还是可见光焊缝余高图第一步都是把标注统一成 YOLO 格式。常见做法是先用 LabelImg 或 Labelme 做人工标注Labelme 输出 JSONLabelImg 直接输出 txt。很多交付包会直接给你 txt但如果你是接手别人的半成品往往只有 JSON需要自己转换。下面这段脚本把 Labelme 的 JSON 转成 YOLO 训练用的 txt注意坐标要归一化到 0~1类别要从名称映射成数字import json import os from glob import glob # 类别映射按实际标注名称修改 class_map {pore: 0, slag: 1, crack: 2, lack_fusion: 3} def labelme_to_yolo(json_path, output_dir, img_width, img_height): with open(json_path, r, encodingutf-8) as f: data json.load(f) lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue points shape[points] # [[x1,y1], [x2,y2], ...]多边形 xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # YOLO 要求 cx, cy, w, h 全部归一化 cx (x_min x_max) / 2 / img_width cy (y_min y_max) / 2 / img_height w (x_max - x_min) / img_width h (y_max - y_min) / img_height lines.append(f{class_map[label]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) txt_path os.path.join(output_dir, os.path.basename(json_path).replace(.json, .txt)) with open(txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) # 示例调用转换 images 目录下所有 json for jp in glob(labels_json/*.json): labelme_to_yolo(jp, labels_txt, 1024, 1024)逐段逻辑说明先读入 JSON遍历每个标注形状取多边形外接矩形转成中心点加宽高的表示这是 YOLO 标签的标准做法。参数里最容易被忽略的是img_width和img_height如果原图尺寸写错所有坐标都会偏移训练时 loss 能降但检测框永远贴不准。另外注意多边形的凹形和旋转框焊缝缺陷大多是气孔、条状裂纹、夹渣用外接矩形会引入背景噪声工程上可接受但如果缺陷细长且倾斜严重建议先做旋转框标注再用对应算法不要硬塞进 YOLO 的 axis-aligned 框。2.2 数据划分、样本均衡与脏数据过滤焊缝缺陷数据的典型问题是正负样本失衡和同一张图被反复裁剪导致的数据泄漏。很多研究设计包里会把一批原始大图切成多个 patch切完直接随机分配 train/val结果同一缺陷的多个 patch 同时出现在训练集和验证集mAP 虚高换到现场就露馅。我一般会按原始图像维度划分而不是按 patch 划分。先按原始文件 ID 分好组再在组内切 patch并把同源 patch 全部放进同一个集合。下面这段脚本是稳妥的划分方式import random from pathlib import Path images list(Path(images).glob(*.png)) random.seed(42) random.shuffle(images) # 按原始文件名前缀比如 X 光片编号分组 groups {} for img in images: group_id img.stem.split(_)[0] # 形如 weld_001_023.png - weld_001 groups.setdefault(group_id, []).append(img) group_ids list(groups.keys()) random.shuffle(group_ids) split_idx int(len(group_ids) * 0.8) train_groups group_ids[:split_idx] val_groups group_ids[split_idx:] train_files [p for g in train_groups for p in groups[g]] val_files [p for g in val_groups for p in groups[g]] print(ftrain images: {len(train_files)}, val images: {len(val_files)}) # 再写文件列表供后续使用这段代码的核心是「先分组再随机」避免同源 patch 泄漏。参数上split_idx控制训练验证比例工业小样本场景 80/20 偏激进我建议至少留 15% 做验证如果总样本不足 200 张考虑用 K 折交叉验证而不是单次划分。脏数据过滤是另一个容易翻车的地方。焊缝图像里经常出现弧光、飞溅、探伤标记字符这些都会被误标成缺陷。一个实用的过滤方法是训练前先画一遍所有标注框的尺寸分布把宽度小于 3 像素的框直接剔除。焊縫缺陷的物理尺寸是有一个范围的小于 3 像素的「缺陷」大概率是标注误差。用下面几句脚本就能定位import os def check_labels(label_dir): for txt in os.listdir(label_dir): with open(os.path.join(label_dir, txt)) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f格式错误: {txt}) continue x, y, w, h map(float, parts[1:]) if w 0.003 or h 0.003: print(f疑似小框: {txt} - w{w}, h{h}) check_labels(labels_txt)这个脚本的价值在于把「看起来合理」的标注变成「统计上合理」。归一化后 w 小于 0.003在 1024 图上就是小于 3 像素基本不可能是有效缺陷。处理这类框时不要直接删建议回到原图看一眼很多情况下是圆弧形缺陷的端点没有闭合导致宽度塌缩。3. 用 YOLO 训练焊缝缺陷模型从预训练权重到参数调整3.1 数据集 YAML、预训练模型选择与最小训练命令数据准备好了下一步就是搭训练。这里的关键是数据集描述文件dataset.yaml它决定了训练器去哪个目录找图、找标签以及类别名怎么显示。常见的最小文件如下# dataset.yaml path: ./weld_dataset train: images/train val: images/val nc: 4 names: 0: pore 1: slag 2: crack 3: lack_fusion这里的path是数据集根目录train和val是相对路径。注意 YOLO 官方库对路径的处理在不同版本有差异老版本要求train是绝对路径新版本支持相对路径但会相对path解析。如果你把 zip 解压到中文路径或带空格路径这里就是第一个爆炸点后面避坑章会专门讲。预训练模型方面不要一上来就选最大的。焊缝缺陷是小目标但背景相对单一YOLOv8s 或 YOLOv8m 往往够用。常见做法是下载官方 COCO 预训练权重做迁移学习因为 COCO 里有大量物体边缘、纹理、明暗变化特征对焊縫这样的低对比目标初始化比随机权重好得多。最小训练命令如下yolo detect train \ datadataset.yaml \ modelyolov8s.pt \ epochs200 \ imgsz640 \ batch8 \ device0 \ projectweld_runs \ nameexp1逐项说明modelyolov8s.pt既是指定网络结构又是预训练权重来源训练器会先加载结构再从权重文件读参数。imgsz640是训练分辨率理论上提高分辨率对小目标友好但显存占用随平方增长8 张卡才敢跑 1280。batch8在单卡 11G 显存下比较安全如果你用 V100 或更大显存可以提到 16 甚至 32但注意 batch 变大后 BN 层统计会更稳定学习率也需要相应调大。device0指定第一张卡没有 GPU 就写devicecpu感受一下时间成本实际项目别干这事。3.2 损失函数构成与关键训练超参数含义YOLO 训练时大家嘴上常说的「loss」实际上是一个多任务加权和。以 YOLOv8 为例损失由三块组成边界框回归损失CIoU 或其变体、分类损失BCE、以及可选的 DFL 损失。很多教程会叫你去调box_loss、cls_loss、dfl_loss但实际训练命令里很少直接暴露这些权重你看到的是它们在每个 epoch 的打印值。理解损失函数的关键在于判断训练状态。正常训练时box_loss和cls_loss都应该是平滑下降趋势如果cls_loss下降很快但box_loss纹丝不动问题大概率在标签框质量上如果两者都降到平台期说明模型容量或数据多样性到头了。下面这张参数表是我在焊缝场景里的经验值不是标准答案但值得作为起点参数经验值说明imgsz640 起步若缺陷平均像素 10考虑 960/1280epochs200~300焊缝样本少早停和断点续训更实用batch8~16取决于显存BN 崩溃时先降 batch 排查lr00.01~0.02batch 大时适当加大lrf0.01最后几个 epoch 降到初始的 1/100patience50验证指标连续 50 轮不涨就停augment默认开启焊缝场景别开旋转缺陷会被旋到语义错误角度具体到焊缝有两个参数要特别小心。第一个是 mosaic 增强默认开启训练前半段能显著提升泛化但最后 10~20 个 epoch 建议关掉否则小缺陷因为拼接导致目标尺寸分布失真边界框回归不稳定。第二个是旋转和翻转增强焊缝缺陷有明确的物理方向性竖裂纹翻转成横裂纹就是完全不同的缺陷类型我一般把flipud0.0、fliplr0.5、degrees0.0显式写进超参。如果你在写研究设计文档这两条值得单独一段解释因为审稿人/导师最爱问「为什么不开旋转增强」。3.3 断点续训与日志保存焊缝数据量小训练周期长跑一半断电或者显存炸掉是常有的事。YOLO 的训练器默认会在runs/detect/train/weights/下存last.pt和best.ptlast.pt就是用来续训的。恢复命令只需要加一个resumeTrueyolo detect train resumeTrue modelweld_runs/detect/exp1/weights/last.pt注意resume时必须保证数据集路径、超参配置和原训练一致否则你其实是在开一个新训练。这个命令是「后悔药」也是「翻车之后不重头来」的关键。另外一个容易被忽略的点是权重文件本身要定期备份到其他目录因为runs目录默认在项目根路径下你解压的 zip 包如果带了只读权限或磁盘空间不足训练一半就写不进去了。4. 评估一次训练混淆矩阵、mAP 与数据泄漏识别4.1 从指标列表里快速定位模型状态训练结束后可视化结果在runs/detect/exp*/下。普通人先看results.png但那是训练曲线只能告诉你收敛没收敛。真正反映焊缝识别能力的是confusion_matrix.png、PR_curve.png和val_batch*.jpg。读取训练日志的推荐命令yolo detect val \ modelweld_runs/detect/exp1/weights/best.pt \ datadataset.yaml \ imgsz640 \ projectweld_val \ nameval1验证完成后留意三个输出文件confusion_matrix.png横纵轴是类别对角线越亮越好。看焊缝缺陷尤其注意「未熔合」和「裂纹」之间是否互相混淆这两类形状相似是自然混淆的重灾区。PR_curve.pngPrecision-Recall 曲线下的面积就是 mAP。曲线偏左上说明阈值选择稳健曲线突然掉头说明某个置信度区间里误检爆炸。val_batch_pred.jpg带预测框的验证图。这里看的是「框有没有把缺陷整个包住」如果框总是只包围缺陷一部分说明回归头没学好属于标签框不准确或损失权重问题。很多刚接触 YOLO 的同行会纠结「混淆矩阵总合不唯一」其实这是正常的。混淆矩阵分归一化和非归一化两种非归一化版本里每个格子的数值是绝对个数行/列之和取决于该类别的真实样本数归一化版本通常按行归一对角线之和不等于 1 是正常的因为有背景类background和漏检FN。看论文时如果作者没写清楚归一化方式你完全可以自己重新算一遍这个不是 bug。4.2 mAP 之外焊缝缺陷特有的评估陷阱对焊缝缺陷来说mAP 这个综合指标容易掩盖两类问题。第一类是类别极不均衡气孔可能占 70% 的样本裂纹只占 5%mAP 被气孔带动裂纹的 AP 却低得可怜。第二类是尺度问题焊缝缺陷尺寸跨度极大有的裂纹横跨整张图有的气孔只有 5 像素宽mAP 是跨 IoU 阈值和跨尺度的平均一个数字很难表达「小目标全漏、大目标全中」的真实状态。更实用的做法是分缺陷类型、分尺寸段看 AP。用官方库的metrics可以拿到每个类别的 APfrom ultralytics import YOLO model YOLO(weld_runs/detect/exp1/weights/best.pt) metrics model.val(datadataset.yaml, imgsz640) # 每个类别的 AP50 和 map50 for i, name in model.names.items(): ap50 metrics.box.ap50[i] print(f{name}: AP50{ap50:.3f})说明metrics.box.ap50是 numpy 数组按类顺序存放。如果是类别顺序和dataset.yaml对不上结果就张冠李戴了。拿到分类型 AP 之后如果发现裂纹 AP 只有 0.1 而气孔有 0.9就不要急着调模型结构先去统计裂纹样本数量和标注质量。焊缝裂纹常有非常细长的形态如果标注框是方形而不是细长矩形模型学到的先验形状就是错的。另外一个值得做的事是人工复查验证集预测图。常见做法是每次训练完从val_batch_pred.jpg里挑出 10 张包含误检的图把推理置信度阈值调低到 0.1 重新跑一遍把「模型其实看到了但被阈值卡掉的框」和「模型压根没画框的地方」分开统计。前者可以通过降低 conf 阈值召回后者是真正的盲区需要通过加数据或调整锚框解决。这个步骤虽然是土办法但比盯着曲线猜要高效得多。5. 焊缝缺陷 YOLO 训练容易踩的 5 个坑从数据路径到 BN 崩溃5.1 中文路径和空格路径导致数据加载失败现象解压 zip 后按正常命令训练报FileNotFoundError或者AssertionError指向某张图片路径但路径明明存在。把中文路径改成英文 alias 后一切正常。原因YOLO 官方库依赖某些底层文件读取库在 Windows 下对中文路径和带空格路径的兼容性很差尤其是通过 glob 展开时路径拼接中的空格会被当成多个参数。很多研究设计 zip 包是中文用户打包的目录名直接就叫「焊缝数据集」跑不动非常常见。解决解压后统一改成纯英文小写路径不要放桌面不要放带空格的文件夹。如果路径已经写死在代码里可以做一个软链接映射而不是改代码。以 Windows 为例把D:\我的资料\焊缝\data映射到C:\weld_data代码里路径写C:\weld_data。5.2 BN 层崩溃loss 变成 nan 或剧烈震荡现象训练开始几轮正常到某个 epoch 后box_loss或cls_loss变成nan监测 GPU 利用率发现没崩但 loss 已经不更新。原因最常见的是学习率过大导致梯度爆炸其次是 batch 太小导致 BN 层统计量不稳定。焊缝数据里目标小、背景接近梯度本身就比通用目标检测更敏感。另一个隐性原因是输入图像里存在全黑或全白的坏图这种图会让 BN 层的均值方差计算产生极端值。解决先设batch4跑 10 轮看是否稳定稳定后再逐步加大 batch。同时排查数据集中有没有纯色图。用一段脚本扫一遍所有训练图的像素方差from PIL import Image import numpy as np from pathlib import Path for img_path in Path(weld_dataset/images/train).glob(*.png): arr np.array(Image.open(img_path).convert(L)) if arr.std() 1.0: print(f低对比度图: {img_path} std{arr.std():.2f})这段脚本只做一件事找灰度标准差小于 1.0 的图。正常焊缝 X 光片即使暗背景也有噪声std 不会接近 0。如果发现这样的图建议直接删除或替换它们是 BN 崩溃的定时炸弹。5.3 小目标缺陷漏检严重现象mAP50 看着有 0.8但实际部署时 20 像素以下的气孔全部漏检验证集上小目标 AP 极低。原因模型输入分辨率不够加上训练时 mosaic 增强把缺陷缩得更小导致小目标特征在下采样层被抹掉。另一个原因是预训练模型在 COCO 上的锚框尺寸偏好对极端小目标不友好。解决先把imgsz提到 960 或 1280代价是训练时间增加和显存压力。如果显存不够就把大图切成 640 patch 训练但注意要在推理时用滑窗拼接而不是直接对整张大图缩放到 640否则小目标丢失。另外把mosaic0.0在最后 20 个 epoch 关掉让模型回到真实的小目标尺寸分布。这类问题不要指望通过提高 epoch 数来解决数据尺度和模型输入分辨率不变跑再多轮也是白搭。5.4 权重文件拷给别人后推理结果完全不同现象本地验证 mAP 0.8把best.pt发给同事对方加载后对同一张图输出完全不同的框有时一张图一个框都没有。原因很少人意识到 YOLO 权重文件里不存储训练时的超参配置但best.pt和last.pt里会附带训练时的数据配置和类别信息。如果对方代码路径下没有对应的dataset.yaml或者他把权重文件单独拿出来放到另一个项目里库会尝试从权重内嵌的配置加载一旦路径失效类别映射就会错乱或默认成 COCO 80 类。解决给对方模型时把best.pt、dataset.yaml、简单推理脚本三个文件打包在一起。推理时显式指定类别文件不要用一个通用的coco.yaml。同时保存一个args.yaml里面记录了训练时的 imgsz、conf、iou 等参数部署时按它来设置推理阈值。你的研究设计 zip 包里一定要有这个文件它能省掉大量「本地跑得好、别人跑不出来」的沟通成本。5.5 zip 包伪加密或损坏导致交付物打不开现象用户解压研究设计 zip 时提示需要密码输入空白或常见密码都失败用 WinRAR 能解但 Windows 自带解压工具报错有的包打开后训练脚本能跑但weights/目录是空的。原因网上流传的很多 zip 包是伪加密状态zip 的 general purpose bit 里加密标志被置位但实际数据并未加密这是打包工具或人为操作造成的元数据错乱。另外有部分工程交付包为了防误改故意把权重文件单独打了一个没有注释的压缩层目录里留下的是占位文件。解决先不要硬猜密码用解压工具修复功能处理伪加密。命令行工具解法# 尝试用 zip -FF 修复损坏的 zip zip -FF damaged.zip -O repaired.zip # 修复后查看文件列表确认无缺失 unzip -l repaired.zip | grep weights如果zip -FF仍然提示有加密则用 7-Zip 打开若 7-Zip 能直接列出文件且不需要密码说明只是伪加密把文件直接拖出来即可。这里提一个反向经验做研究设计 zip 包交付时不要图省事设置加密或者篡改 zip 标志位诚实标注压缩包大小和解压方法比任何防拷贝小动作都更有效。读者如果是自己打包建议统一用zip -r标准压缩别用自解压格式自解压在 Linux 服务器上很容易当成普通 zip 处理失败。6. 把研究设计打包成可复现的 zip目录规范与一键验证6.1 交付包目录设计与一键训练脚本一份能让别人复现的焊缝缺陷识别研究设计不应该只塞一个best.pt和几张曲线图。我见过太多包解压后里面是一个最终版目录里面又有一个最终版2点上三天找不到训练脚本。规范的做法是把训练、验证、推理、数据说明拆成四个子目录weld_defect_detection/ ├── README.md ├── requirements.txt ├── config/ │ └── dataset.yaml ├── scripts/ │ ├── train.sh │ ├── val.sh │ └── inference.py ├── weights/ │ ├── best.pt │ └── args.yaml └── docs/ ├── 数据标注说明书.md └── 实验记录.md一键训练脚本可以写成这样#!/bin/bash # train.sh set -e cd $(dirname $0)/.. # 检查权重文件是否存在避免预训练下载失败导致中断 MODELyolov8s.pt if [ ! -f $MODEL ]; then echo 缺少预训练权重 $MODEL请先下载后放回项目根目录 exit 1 fi python -m venv .venv source .venv/bin/activate pip install -r requirements.txt yolo detect train \ dataconfig/dataset.yaml \ model$MODEL \ epochs200 \ imgsz640 \ batch8 \ projectruns \ nameweld_final脚本里的set -e保证任何一步失败就停止不会出现「训练脚本跳过了某个命令但用户没发现」的假成功。检查预训练权重的逻辑很关键因为在没有外网的环境里YOLO 会自动下载yolov8s.pt下载失败就卡住。把权重提前放在项目根目录再在脚本开头检查就能保证离线可用。6.2 用一条全局验证命令确认包完整可复现打包之前我建议先运行一个全局合理性测试。这个测试不追求精度只验证「数据和模型能不能对上」。# scripts/sanity_check.py from ultralytics import YOLO import os model YOLO(weights/best.pt) # 确认类别数与 dataset.yaml 一致 assert len(model.names) 4, f类别数异常: {model.names} # 生成一张纯灰图跑一次推理 import numpy as np from PIL import Image dummy Image.fromarray(np.full((640, 640, 3), 128, dtypenp.uint8)) results model.predict(dummy, imgsz640, verboseFalse) print(sanity check passed, detections:, len(results[0].boxes))这个脚本的价值在于用最小成本把环境、权重、数据配置串起来跑一遍。如果纯灰图上都能输出框说明模型和代码链路正常如果直接报错那用户就没必要继续往下读实验记录了。打包时把这一条命令写进 README作为「拿到包后的第一件事」。我给自己的项目做 zip 交付时有个习惯先在干净虚拟机里解压、按 README 从零跑通一遍再改名为已验证版本打包。这套流程帮我在交付前抓出过三个问题依赖版本缺失、中文路径报错、预训练权重没有内置。最后说一句YOLO 焊缝缺陷识别这个方向真正难的不是调参而是把你走过的每一步变成别人也能走的路希望这些经验能帮到你。本文还有配套的精品资源点击获取
返回列表