ARTICLE DETAIL

资讯详情

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

YOLOv3焊缝质量检测实战:从标注数据集到权重训练与产线部署

YOLOv3焊缝质量检测实战:从标注数据集到权重训练与产线部署 简介本资源面向工业质检方向的算法工程师、深度学习学习者与焊接缺陷检测研究者提供一套可直接复现的YOLOv3焊缝质量好坏检测方案。包内已包含训练完成的检测模型权重并附PR曲线、loss曲线等训练过程记录便于评估模型性能与调参参考。资源共3403个文件以1134张jpg焊缝图像、1134个xml标注文件和1135个txt标签文件为主xml与txt分别存放于两个文件夹兼容LabelImg标注格式与YOLO训练格式压缩包整体约456.53MB。数据集覆盖钢材缺陷检测场景可直接用于模型训练、验证与二次开发。目前已有874人学习下载适合希望快速搭建焊缝缺陷检测基线、对比不同检测策略或开展课程设计、毕业设计的读者参考使用。1. 焊缝质检为什么值得用 YOLOv3 重做一遍焊缝质量检测在车间里是个老问题但真正落地成自动化的并不多。我见过不少产线还在靠老师傅拿放大镜盯焊缝一天看几千条眼睛先扛不住。漏检一条气孔或者咬边后面装配、打压、探伤全得返工代价远高于检测本身。YOLOv3 焊缝质量检测这套方案核心就是把「缺陷在哪、是什么、多大」这三件事交给模型用标注好的数据集训练出权重再部署到工位旁边做实时判定。它适合两类人一类是手里已经攒了一批焊缝图像、想跑通检测闭环的工艺或设备工程师另一类是刚接触目标检测、想拿一个真实工业场景练手的学习者。标题里提到的权重和标注好的数据集意味着你不需要从零采集和标注直接进入训练和调参环节这对想快速验证方案可行性的人来说省掉了最耗时的前置工作。焊缝缺陷的形态相对固定气孔、夹渣、未熔合、裂纹这几类在图像上有明显纹理差异YOLOv3 的多尺度检测头刚好能覆盖从几毫米的小气孔到贯穿性裂纹的不同尺寸目标这也是它在工业缺陷检测里一直被沿用的原因。2. 焊缝数据集长什么样标注格式、类别划分与权重加载2.1 焊缝缺陷的类别定义与标注边界拿到一份标注好的焊缝数据集第一件事不是急着训练而是把标注规范看清楚。焊缝缺陷通常分四到六类气孔、夹渣、未熔合、未焊透、裂纹、咬边。不同标准体系下类别名可能不一样但核心逻辑是按缺陷成因和形态分。标注时最容易出问题的是边界框的松紧程度。气孔是圆形或椭圆形框稍微大一点影响不大裂纹是细长条框太松会把周围正常焊缝纹理也包进去模型学到的特征就糊了。我一般要求标注框边缘距离缺陷实际边缘不超过 5 个像素裂纹类缺陷如果长度超过图像宽度的三分之一建议分段标注而不是一个超长框否则 YOLOv3 在 13×13 特征图上的感受野覆盖不住。标注格式方面YOLOv3 原生用的是 Darknet 格式每张图对应一个 txt 文件每行是类别索引 中心x 中心y 宽 高坐标全部归一化到 0 到 1 之间。如果你拿到的数据集是 VOC 的 XML 或者 COCO 的 JSON需要先转换。转换脚本不难写但有几个边界坑后面会专门讲。2.2 从 VOC/COCO 转到 Darknet 格式的脚本与参数假设你手里的标注是 VOC 格式的 XML下面这个 Python 脚本可以直接转成 YOLOv3 需要的 txtimport xml.etree.ElementTree as ET import os # 类别映射顺序必须和训练时 .names 文件一致 classes [porosity, slag, lack_of_fusion, crack, undercut] def convert_annotation(xml_path, output_dir, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() # 用文件名做 txt 名和图片同名 txt_name os.path.splitext(os.path.basename(xml_path))[0] .txt with open(os.path.join(output_dir, txt_name), w) as f: for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(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) # 归一化并转为中心点宽高 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 # 边界裁剪防止标注超出图像范围导致训练报错 x_center max(0, min(1, x_center)) y_center max(0, min(1, y_center)) w max(0, min(1, w)) h max(0, min(1, h)) f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n)这段代码的逻辑很直接读 XML取类别名映射成索引把绝对坐标转成归一化的中心点加宽高。参数上要注意classes列表的顺序必须和后续.names文件完全一致否则模型学出来的类别会错位。img_w和img_h是原图尺寸不是网络输入尺寸YOLOv3 在训练时会自己做 letterbox 缩放。最后那个边界裁剪是血泪经验有些标注工具导出的框会超出图像边界不裁剪的话训练时 loss 会直接变成 nan。2.3 权重文件怎么用预训练权重与迁移学习策略标题里的「权重」通常指两种一种是 Darknet 官方在 COCO 上训练的darknet53.conv.74用来做 backbone 初始化另一种是别人已经在焊缝数据集上训好的.weights文件可以直接推理或者继续微调。我一般会先用darknet53.conv.74做迁移学习因为焊缝缺陷和 COCO 里的通用物体在底层纹理上有共性边缘、角点这些特征可以复用。加载方式是在.cfg文件里把burn_in和max_batches调好训练命令里加-clear参数表示从预训练权重开始而不是从零初始化。如果你拿到的是已经训好的焊缝权重想直接跑推理命令大概是./darknet detector test cfg/weld.data cfg/yolov3-weld.cfg backup/yolov3-weld_final.weights test.jpg这里weld.data里要写对names、train、valid的路径yolov3-weld.cfg里的filters要改成3*(classes5)classes改成实际类别数。很多人直接拿 COCO 的 cfg 改个权重就推理结果类别全乱就是因为filters和classes没同步改。3. 训练自己的焊缝模型cfg 参数、anchor 调整与训练命令3.1 针对焊缝缺陷修改 yolov3.cfg 的五个关键位置YOLOv3 的 cfg 文件很长但真正需要改的只有几个地方。以yolov3.cfg为基础按下面这张表逐项核对配置项原值COCO焊缝场景建议值说明classes805按实际类别出现在三个 yolo 层里都要改filters25530公式3*(classes5)三个 yolo 层前一个卷积层都要改max_batches50020020000 起焊缝数据集通常几千张2 万到 4 万足够steps400000,45000016000,18000取 max_batches 的 80% 和 90%burn_in10001000保持默认让学习率预热filters是最容易翻车的地方。三个 yolo 层前面各有一个[convolutional]每个都要把filters改成3*(55)30。只改一个或者改错位置训练时直接报维度不匹配。max_batches不要设太小焊缝缺陷特征比通用物体细收敛慢我一般先跑 2 万 batch 看 mAP 曲线如果还在涨就继续加。3.2 用 k-means 重新聚类 anchor 的完整流程YOLOv3 默认的 9 个 anchor 是在 COCO 上聚类出来的对焊缝这种细长裂纹和小气孔不一定合适。重新聚类能明显提升召回率。流程分三步先把所有标注框的宽高提取出来再用 k-means 聚成 9 类最后按面积排序分配到三个尺度。import numpy as np def kmeans_anchors(bboxes, k9, iterations100): # bboxes: N x 2 的数组每行是归一化的宽和高 np.random.seed(42) # 随机选 k 个框作为初始聚类中心 centers bboxes[np.random.choice(len(bboxes), k, replaceFalse)] for _ in range(iterations): # 计算每个框到各中心的 IoU 距离 distances 1 - iou_matrix(bboxes, centers) labels np.argmin(distances, axis1) # 更新中心为同类框的均值 for i in range(k): if np.sum(labels i) 0: centers[i] bboxes[labels i].mean(axis0) # 按面积从小到大排序 areas centers[:, 0] * centers[:, 1] centers centers[np.argsort(areas)] return centers def iou_matrix(boxes, clusters): # 计算框与聚类中心的 IoU n boxes.shape[0] k clusters.shape[0] ious np.zeros((n, k)) for i in range(n): for j in range(k): w min(boxes[i, 0], clusters[j, 0]) h min(boxes[i, 1], clusters[j, 1]) inter w * h union boxes[i, 0] * boxes[i, 1] clusters[j, 0] * clusters[j, 1] - inter ious[i, j] inter / union return ious聚类完得到 9 个 anchor按面积从小到大排前三个给 13×13 的大感受野中间三个给 26×26后三个给 52×52。在 cfg 里找到三个[yolo]层把anchors后面的数字按这个顺序替换。注意 anchor 是相对于网络输入尺寸的绝对像素值不是归一化值所以聚类前要把宽高乘以 416 再算。3.3 启动训练与日志观察loss 曲线怎么看训练命令本身不复杂./darknet detector train cfg/weld.data cfg/yolov3-weld.cfg darknet53.conv.74 -gpus 0,1-gpus 0,1表示用两张卡单卡就去掉。训练开始后终端会持续打印 loss 和 mAP。重点看几个信号前 1000 batch 的 loss 从几百降到几十是正常的如果一直卡在几百不降大概率是filters或classes没改对。Region 85 的 loss 反映的是分类和置信度Region 85 后面的 IOU loss 反映框的准确度。如果 IOU loss 震荡厉害把learning_rate从 0.001 降到 0.0005 再试。每 1000 batch 会在backup目录存一个权重我一般保留最近三个和最好的那个防止过拟合后没有后悔药。4. 焊缝检测落地避坑从标注到推理的五个翻车现场4.1 标注框超出图像边界导致 loss 变 nan现象训练跑了几百 batch 后 loss 突然变成 nan终端刷屏。 原因部分标注框的xmax或ymax超过了原图宽高归一化后宽高大于 1YOLOv3 在计算坐标损失时开根号出现负数。 解决在转换脚本里加边界裁剪把所有坐标 clamp 到 0 到 1 之间。已经训到一半的用-clear从最近的备份权重重新开始不要从 nan 那个权重继续。4.2 类别不平衡导致小缺陷被模型忽略现象气孔和裂纹的 mAP 正常但夹渣和未熔合的召回率极低几乎检不出。 原因焊缝数据集中夹渣样本可能只有几十个而气孔有上千个YOLOv3 的损失函数对多数类倾斜。 解决两个方向。一是对少数类做数据增强旋转、亮度扰动、加噪声把样本量拉到和其他类一个量级。二是在 cfg 里调classes前面的scale参数但 Darknet 原生不支持类别权重更稳妥的做法是过采样少数类图片在train.txt里重复列几次。4.3 推理时置信度阈值设太高漏检、设太低误检现象产线上要么漏掉真实缺陷要么把正常焊缝纹理当成缺陷报警。 原因thresh和nms两个参数没根据场景调。默认thresh0.5对焊缝偏严很多真实缺陷置信度在 0.3 到 0.5 之间。 解决先用验证集跑一遍画出不同thresh下的 precision-recall 曲线选 F1 最高的点。我一般把thresh设在 0.3 到 0.4nms设在 0.45。如果误检还是多检查训练集里有没有把正常焊缝的纹理误标成缺陷这种脏数据比参数问题更致命。4.4 图像分辨率与网络输入不匹配导致小目标丢失现象原图是 2000×1500 的工业相机图缩到 416×416 后小气孔只剩几个像素模型完全检不出。 原因YOLOv3 的输入尺寸固定直接 resize 会丢失小目标细节。 解决把width和height改成 608 或 832牺牲推理速度换精度。另一个做法是切图推理把大图切成 512×512 的小块分别检测再合并适合缺陷密集的焊缝。切图时注意重叠 20% 到 30%防止缺陷被切在边界上。4.5 权重文件加载后类别数不匹配报错现象用别人训好的焊缝权重推理终端报Cannot load weights或类别输出全乱。 原因权重文件对应的classes数和当前 cfg 不一致或者filters没改。 解决先确认权重训练时的类别数把 cfg 里三个 yolo 层的classes和前面的filters同步改好。如果只是类别名不同但数量一样改.names文件即可。数量不一样就只能拿这个权重做初始化重新训练不能直接推理。5. 把焊缝检测推到产线推理加速与误检抑制的两个技巧训练出 mAP 满意的模型只是第一步真正上产线还要解决速度和稳定性。我一般会做两件事一是把 Darknet 模型转成 TensorRT 或者 OpenVINO推理速度能翻三到五倍具体选哪个看工控机是 N 卡还是 Intel 核显。转换时注意 YOLOv3 有三个 yolo 层输出节点要全部指定漏一个就会丢尺度。二是加一个后处理逻辑对连续多帧都检出的缺陷才报警单帧偶发的置信度波动直接过滤掉。这个逻辑用 Python 写个环形缓冲区就行成本极低但能压掉大部分误报。还有一个容易被忽略的点是相机曝光。焊缝表面反光严重曝光时间固定的话不同工件之间亮度差异很大模型在暗图上召回率会掉。我习惯在推理前加一步自适应直方图均衡用 OpenCV 的CLAHEclipLimit 设 2.0tileGridSize 设 8×8对焊缝这种高对比度纹理效果明显。这一步不改变模型结构纯预处理但能让同一套权重在不同光照下稳定不少。最后说个我自己的习惯每次训完一个新权重不要只看 mAP 数字一定拿产线上最难的几张图跑一遍看看漏检和误检具体长什么样。mAP 高不代表产线能用焊缝检测的玄学就在这儿数据分布稍微偏一点指标和实际表现能差出百分之十几。希望帮到你。本文还有配套的精品资源点击获取
返回列表