深度学习焊接缺陷检测落地实战:从数据标注到产线部署的完整指南 在制造项目里看过同一个画面的人都知道灯光昏暗的焊缝质检工位上老师傅拿着放大镜一条焊缝从头扫到尾遇到可疑点还要擦一下表面再看一遍。人力成本高、漏检率随疲劳程度上升、判读标准因人而异这些问题在焊接场景里特别突出。后来我参与的一个制造项目引入了基于深度学习的焊接缺陷检测系统用 Python 实现从数据标注、模型训练到产线推理的完整链路。这篇文章不是跑通一个玩具 Demo 就结束而是把整个落地过程复盘一遍缺陷类型怎么定义、网络怎么选型、训练有哪些关键参数、最终部署会遇到哪些坑尽量做到让读过的人能直接照着搭出一套可用的检测系统。1. 先从工艺标准聊起焊接缺陷有哪些检测难点在哪1.1 常见焊缝缺陷的类型与视觉特征焊接缺陷不是一个笼统的概念它是一大类形态完全不同的问题。在制定深度学习方案之前必须先把“要检什么”定义清楚否则后面标注、训练、判定全都会乱套。我做项目时习惯参考国标和行业通用的焊缝缺陷等级标准把缺陷分成下面几类来对待缺陷类别形成原因视觉特征检测难度气孔熔池凝固时气体未及时逸出圆形或近圆形暗点单个或成群出现尺寸从零点几毫米到几毫米中夹渣焊剂、氧化皮未排出熔池形状不规则灰度较暗边缘不锐利中高未熔合/未焊透母材与填充金属未完全结合线状或条状常藏在焊缝根部对比度低高裂纹应力集中或冷却速度不当细长线状可能带分叉浅裂纹极易漏检高咬边焊接参数不当导致焊趾处母材熔化下凹焊趾处的条状凹槽有方向性中焊瘤、飞溅熔池溢出或飞溅物明显凸起或散落颗粒形状变化大低这里要特别提醒不是所有缺陷都能靠视觉直接看到。内部气孔、深层未熔合往往需要超声或射线检测深度学习视觉方案主要负责表面及近表面可见缺陷。做一个系统前先把这个边界和客户讲清楚否则上线后验收会扯皮。1.2 人工目检与传统视觉方案卡在哪人工目检的问题不是“不认真”而是物理上的极限。一条焊缝的合格判定需要在几十秒内完成检验员盯久了小尺寸气孔和浅裂纹很容易从眼皮底下滑过去。而且一个工厂如果有多个检验员他们对“轻微咬边算不算不合格”的判断很难完全统一。我在现场见过同一块样件被三个人判出三种结论这种不一致在质量追溯时会非常麻烦。传统图像处理方案我也试过。阈值分割、边缘检测、模板匹配这类方法对背景干净、光照稳定的规则零件还勉强能用但焊缝表面天然有鱼鳞纹、飞溅、氧化皮光照一打上去到处都是边缘响应。用边缘检测算子去抓裂纹抓出来的大多是纹理伪边缘根本没法当判定依据。深度学习方法不一样它直接从像素级学习缺陷的语义特征不需要手工设计特征算子对反光、纹理、形态变化都有更强的鲁棒性。这也是为什么焊接缺陷检测可以算作深度学习在工业视觉里最有代表性的落地场景之一。2. 方案定好再动手目标检测路线的选型逻辑2.1 分类、目标检测、分割三种任务的取舍同样是深度学习第一步要定的是任务范式。选错了后面每一步都别扭。如果只用图像分类网络只能回答“这张图有没有缺陷”回答不了“缺陷在哪”“是什么类型”。在产线上这几乎没法用——你连缺陷位置都不知道后续返修和工艺追溯无从谈起。实例分割能输出像素级轮廓对计算缺陷面积、引导机械臂打磨很有价值但标注成本高得惊人一个像素级掩码的标注时间是边界框的几倍而且焊接缺陷边缘往往模糊标注员自己都很难画准边界。目标检测输出的是边界框加类别已经能支撑 NG 判定、缺陷统计、位置标记这些核心需求推理速度也更快。我的建议是第一版系统优先考虑目标检测先让产线跑起来如果后续有精确面积或轮廓需求再在 ROI 区域内补做分割。2.2 检测框架与模型的对比检测框架层面主流的 YOLO 系列依然是工业落地最稳的选择。我做选型时对比过几个方向Faster R-CNN 这类两阶段检测器在小目标上的精度潜力高但推理速度慢、部署重基于 Transformer 的端到端检测器不需要锚框设计和 NMS思路很干净但对小目标优化不够成熟训练收敛也更慢YOLO 系经过多代迭代生态完整、训练推理链路顺、部署工具多对小物体有专门优化。在具体版本选择上我习惯用中小体量的模型做基线比如 YOLOv8s 这一档。焊接缺陷类别通常不超过十类不需要追求超大模型的拟合能力中小模型训练快、推理快、更容易迭代。先把基线跑通再根据漏检情况决定要不要换大模型或者加检测头这是比较务实的路径。2.3 Python 做主力的合理边界有人会质疑工业现场最终交付是不是应该用 C我理解这个顾虑但我的经验是原型验证、数据联调、参数调试阶段用 Python 效率最高没有之一。Python 胶水能力强相机的 SDK、PLC 的通信库、数据库的接口都有现成封装几天就能把整个链路串起来。真正的问题只在推理性能瓶颈这个瓶颈不在 Python 本身而在模型计算解决方法是把模型转成 ONNX 再用厂商推理引擎做 FP16 量化由底层 C 完成张量计算Python 只负责调度和数据流转。所以我的结论是Python 做控制面底层推理交给高性能引擎这套组合既能保证开发效率也能满足产线节拍。3. 数据决定精度上限采集、标注与增强的实操细节3.1 现场图像怎么拍焊接缺陷检测的数据来源比想象中更复杂。我见过不少人拿实验室样件拍了几百张图就开始训练结果到现场一测精度立刻崩。原因很简单实验样件太干净现场实际工件有油污、灰尘、锈迹、反光这些干扰项严重影响模型的泛化能力。采集时需要注意几个点相机选型上焊缝是长条状要么用高分辨率面阵相机一次拍全要么用线阵相机扫过去我建议根据产线节拍选择一次成像的面阵方案更容易部署光源角度要专门调低角度环形光能很好凸显咬边和未熔合的阴影纹理而同轴光容易被鱼鳞纹干扰。我在项目里踩过一个坑光源挂高了几厘米咬边的阴影方向彻底变了之前训好的模型漏检率直接翻倍。光源支架必须做防松动设计每次调试完把位置参数固定记录下来。3.2 缺陷标注规范得写到文档里标注这件事最怕几个标注员各标各的。我后来定了一条规矩标注前先开会对着工艺标准把每一类缺陷的判定边界讲清楚并输出一份标注规范文档。比如气孔和密集气孔群怎么区分孤立点一个点一个框密集型气孔群合并成一个区域框线状缺陷用最小外接矩形框要完整包住缺陷两端夹渣和未熔合容易混标注时如果拿不准先找工艺工程师确认不要凭感觉。标注工具的对比度调节功能一定要用起来。很多焊接缺陷在原始亮度下几乎看不见拉一下对比度或者做一次局部增强边界立刻清晰。低对比度的浅裂纹不借助工具辅助直接标注大概率会漏标。另外我强烈建议每个类别的标注量做一个简单统计比如气孔 800 个框、裂纹只标了 30 个框这种数据直接进训练模型基本就废了。3.3 针对小目标的数据增强焊接缺陷的数据增强不能只做翻转、旋转、亮度扰动这些基础操作得针对“小目标”这个痛点做额外设计。Mosaic 拼接增强值得开。把四张图拼成一张相当于让模型在训练时看到更多小尺寸目标对小目标召回率提升明显。但注意一个问题mosaic 合成图的背景拼接痕迹比较重训练后期如果一直用模型对真实图像的适应性会变差。所以我在配置里把 mosaic 开到 1.0又在训练最后十几个 epoch 关掉它让模型回到真实分布上精调。频域增强也很有用。焊缝表面纹理在不同光照下的响应差异很大我在训练时随机对图像做高频或低频滤波模拟不同打光环境带来的纹理变化。这个操作能显著提升模型对光源变化的容忍度比单纯加高斯噪声有效得多。3.4 验证集划分的一个常见错误很多人训练深度学习模型时验证集是直接从所有图像里随机抽的这在焊接缺陷检测里是一个很隐蔽的坑。同一批焊件的多张照片内容高度相似如果随机划分模型在训练时已经见过同一个焊件的“克隆样本”验证集精度虚高一到全新批次就现原形。正确做法是按焊件 ID 或生产批次划分数据集。一个焊件的所有图像要么全部进训练集要么全部进验证集保证验证集里的样本来源完全独立。要么更进一步按工况分层抽样不同母材、不同焊接工艺、不同焊接位置都要在验证集里有代表。我在项目里重建过一次数据集划分模型在验证集上的 mAP 降了五个百分点以上这说明之前的精度确实是被“数据泄漏”撑起来的。4. 把模型训练到能上线关键参数与小目标优化4.1 迁移学习的配置焊接缺陷数据集的规模通常只有几千张从零随机初始化训练几乎注定欠拟合。正确姿势是加载在 COCO 这类通用数据集上预训练过的权重把网络前几层已经学会的纹理、边缘、形状特征迁移过来。这样做收敛快最终精度也更高。数据配置文件和训练脚本的思路是这样# data.yaml 核心内容 train: ./data/train.txt val: ./data/val.txt nc: 6 names: [porosity, slag, lack_of_fusion, crack, undercut, spatter]# train.py 核心思路 model load_yolo_model(yolov8s, pretrainedTrue) model.train( datadata.yaml, epochs200, imgsz640, batch16, lr00.01, optimizerSGD, mosaic1.0, close_mosaic10, device0 )训练结束后不要只看总 mAP重点看每一个类别的 AP 和混淆矩阵。焊接缺陷类别之间的混淆非常经典夹渣和未熔合、气孔和飞溅经常互相误判。如果总 mAP 很高但裂纹 AP 很低这个模型一样不能上线。4.2 训练参数背后的逻辑几个关键参数我单独解释一下因为很多人调参只是照抄别人的配置不理解为什么容易出问题。学习率初始值设为 0.01配合 warmup 机制前几个 epoch 用小学习率让网络平稳起步避免前期梯度爆炸。这是 SGD 系优化器比较成熟的组合方式。输入分辨率默认 640但如果你的缺陷目标非常小比如某些气孔在图中只有十几个像素建议把分辨率提高到 1024 再微调一轮。分辨率提升对小目标召回率的作用立竿见影代价是训练和推理时间明显变长。实际操作里我会先拿 640 跑一版基线再在 640 训练的基础上用 1024 微调不要从头训省时间。批次大小设置要考虑显存。工业项目常见用消费级显卡显存 8G 到 24G 不等batch 设成 16 需要看显存是否能放下。显存不够就先降 batch不要硬撑否则训练过程频繁 OOM 会崩溃。4.3 小目标漏检的针对性处理焊接气孔这种小目标漏检原因很明确小目标在图中的像素占比太少经过网络多次下采样后特征在深层特征图里几乎消失。针对这个问题有几个组合手段。第一提升输入分辨率这个是性价比最高的手段第二如果框架支持可以增加浅层特征图参与检测相当于让模型在更高分辨率的特征图上对小目标做预测第三采用切片辅助推理把大图切成若干小块分别推理再合并结果适合微小缺陷检测代价是推理时间上升。我在项目里先试了前两个手段效果不错切片辅助推理只在需要极高召回率的关键工位才启用。4.4 类别不平衡怎么办焊接缺陷数据天然不平衡。气孔可能占了 60% 以上的样本而裂纹往往只有几十个实例。模型为了降低整体损失会倾向于把所有可疑目标都预测成气孔导致裂纹召回率极低。我处理这个问题的方法有三个一是对少数类做过采样把裂纹、未熔合这些稀缺样本反复参与训练但要注意配合数据增强避免过拟合二是给损失函数做难样本加权聚焦那些被当前模型分错的困难样本让模型被迫关注少数类三是在后处理判定里单独给关键缺陷类设置更低的置信度阈值哪怕它只有 0.4 的概率是裂纹也要报警让人工复核而气孔这种低风险缺陷要 0.6 以上才报。关键指标永远是每类别的召回率尤其是裂纹和未熔合这两个高风险类别总 mAP 只能作为参考。5. 工程化落地代码架构、推理链路与产线对接5.1 项目目录与模块划分训练完模型只是开始工程化落地才是大头。我把项目结构拆成几个清晰模块方便不同人协作维护weld-defect-detector/ ├── configs/ │ ├── data.yaml │ └── inference.yaml ├── data/ │ ├── images/ │ ├── labels/ │ ├── train.txt │ └── val.txt ├── src/ │ ├── preprocess.py │ ├── infer.py │ ├── postprocess.py │ └── plc_client.py ├── weights/ │ └── best.pt ├── exports/ │ └── best.onnx ├── logs/ └── requirements.txt这种拆法最大的好处是算法工程师只管模型和推理上位机工程师只管 PLC 和数据库互不干扰。配置文件单独放现场调试改参数不需要动代码对后期维护非常友好。5.2 推理链路的完整实现推理链路的设计要特别注意坐标还原这一步。模型训练时图像被缩放填充成正方形推理结果里的框坐标是相对于缩放后图像的必须变换回原图坐标系否则标注画偏人眼复核时完全对不上位置。核心推理代码的参考实现# infer.py 核心逻辑 import cv2 import numpy as np def preprocess(raw_img, target_size640): h, w raw_img.shape[:2] scale min(target_size / h, target_size / w) nh, nw int(h * scale), int(w * scale) resized cv2.resize(raw_img, (nw, nh)) canvas np.full((target_size, target_size, 3), 114, dtypenp.uint8) x0, y0 (target_size - nw) // 2, (target_size - nh) // 2 canvas[y0:y0 nh, x0:x0 nw] resized return canvas, scale, x0, y0 def detect(model, raw_img, conf_thres0.25, iou_thres0.45): canvas, scale, x0, y0 preprocess(raw_img) outputs model(canvas) # 返回检测框、置信度、类别 boxes, scores, class_ids postprocess( outputs, conf_thres, iou_thres, scale, x0, y0 ) return boxes, scores, class_ids后处理里除了 NMS还要做两个过滤面积过滤把小于一定像素面积的检测结果丢掉因为那大概率是噪点边界过滤如果检测框严重贴边可能是切图产生的残缺目标标记为待人工复核而不是直接 NG。5.3 判定逻辑与产线对接算法输出检测结果之后还要转化成产线能执行的判定信号。这个判定逻辑不能只靠模型置信度需要结合缺陷类型和工艺标准来设计检出裂纹或未熔合不管置信度多低一律 NG宁可错杀不可放过。检出气孔数量超过设定值或总面积超过阈值才 NG。检出咬边要根据深度和长度换算等级轻度咬边可能只是降级而非报废。判定结果通过网口或串口发给 PLCPLC 控制分拣气缸把不合格品推到复检区。同时把结果写成本地 JSON 日志再按需同步到 MES 数据库方便后续质量追溯。图像和时间戳一定要一起保存不然后面返修时连缺陷照片都找不到。6. 实测与排坑上线之后暴露的问题6.1 更换光源后精度滑坡这个坑我印象太深了。产线调试阶段现场工程师觉得环形光源高度挡住了工件装夹直接往上挪了几厘米。结果同一个模型咬边漏检率从 3% 涨到 15%。原因不复杂咬边的视觉特征是焊趾处的阴影纹理低角度光源下的阴影方向是模型学到的关键特征光源角度一变特征就变了。解决思路是双管齐下。首先把光源支架做机械限位参数固定后不允许随意改动其次在训练数据里加入不同光照条件下的样本提高模型对光照变化的容忍度。这个坑的教训是深度学习模型并没有那么“智能”它学到的可能是某种打光条件下的纹理模式而不是抽象的咬边概念。6.2 误报集中在鱼鳞纹和水渍上线初期最大的抱怨是误报。合格焊缝表面的鱼鳞纹在图像里呈现周期性弧形纹理模型经常把它当成咬边或未熔合。水渍和油污的反光区域又是一类高频误报源因为它们的灰度和形状特征与气孔很像。我把误报图像全部拉出来统计过发现鱼鳞纹误报集中在低置信度区间。针对这个现象做了两个调整一是大量增加合格焊缝负样本让模型见过足够多的鱼鳞纹形态二是在后处理里加了一个圆度过滤规则真实气孔通常具有较好的圆对称性而水渍边缘模糊且形态不规则圆度指标能滤掉相当一部分干扰。经过这一轮优化单张图像的误报数量降到了可接受水平。6.3 推理速度优化产线节拍要求一个工位几十秒内完成检测常规推理已经能满足但有些高频检测工位要求单张图像推理控制在几十毫秒内。我用 ONNX 导出模型再用推理引擎的 FP16 模式跑速度提升了不止一倍。模型本身也做了裁剪先用小模型验证精度损失在允许范围内再正式部署。Python 调度层的性能也别忽略。图像读取、坐标还原、结果回传这些环节如果用循环一个个处理会白白增加延迟。我改成了多线程流水线采集线程只管取帧推理线程只管算回传线程只管发结果三个线程之间用队列解耦。实际耗时集中在底层推理Python 的 GIL 问题在调用底层推理库时基本不受影响。优化项优化前优化后模型格式PyTorch 直接推理ONNX FP16单图推理耗时约 25ms约 8ms调度方式串行采集推理多线程流水线整体单工位节拍约 1.2s约 0.6s6.4 后续迭代方向这套系统上线稳定之后我一直在想怎么继续提升。一个可行的方向是半监督学习现场每天都在产生大量未标注的合格和不合格图像用模型预测结果加人工抽查的方式生成伪标签持续扩充训练集能不断降低长尾缺陷的漏检率。另一个方向是引入连续帧时序信息单帧图像偶发误检很难避免但同一缺陷在多帧中会连续出现综合多帧判定能显著降低随机误报。再往后可以尝试多光谱融合红外通道对未熔合和深层裂纹的响应明显优于可见光对高风险缺陷的召回率还能再上一截。最后聊一点我的真实感受。这个项目做下来最深刻的体会是焊接缺陷检测的瓶颈往往不在模型结构而在数据分布的覆盖度和现场工程稳定性。与其花很长时间刷模型结构不如先把采集、标注、验证集划分这些基本功打扎实。哪怕模型换来换去只要样本覆盖住现场的真实工况深度学习方案就能稳定输出。还有一个小建议上线后一定要留一个持续回流数据的通道每两周用新增的不合格样本做一次增量微调系统会越用越准。焊接场景千差万别但这套从数据到部署的流程放到其他工业视觉缺陷检测项目里同样适用。