恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
基于深度学习与熔池图像对的焊缝熔透状态识别
首页
资讯中心
/
基于深度学习与熔池图像对的焊缝熔透状态识别
基于深度学习与熔池图像对的焊缝熔透状态识别
发布时间:2026/10/19 4:08:21
焊接熔透状态识别这件事我刚接手的时候觉得挺简单——不就是判断焊透了没有嘛给两张图分类一下完事。真正干起来才发现现场数据脏、类别不平衡、模型老是被飞溅干扰一个看似二分类的问题硬是让我折腾了两个多月。这个项目最后做的是基于深度学习和熔池图像对的焊缝熔透状态识别。输入是一对同步采集的熔池图像——正面熔池画面和背面熔池画面输出是欠熔透、正常熔透、过熔透三个状态。整套流程从数据采集、标注、模型训练到部署都跑通了代码也整理成了可以直接复用的工程结构。这篇文章把思路、踩坑和关键代码都写清楚给正在做焊接视觉、过程监控或类似工业图像识别项目的朋友一个参考。1. 焊接熔透识别到底在解决什么问题1.1 熔透状态为什么比想象中难判断焊缝熔透程度直接影响焊接接头的力学性能。欠熔透意味着焊缝根部没完全融合承载时容易从根部起裂过熔透则可能形成焊瘤、烧穿背面成型一塌糊涂。传统靠焊后切片、射线探伤或者人工看背面试样又慢又滞后根本做不到实时反馈。很多人觉得可以看正面熔池形态来判断比如熔池宽度变大、下榻明显就说明焊透了。但实际上正面熔池受电弧力、保护气流、母材散热和装配间隙影响非常大同一个熔池宽度在不同焊接电流下对应的熔透状态可能完全不一样。尤其在全位置焊接和窄间隙焊接中正面看起来差不多的熔池背面可能已经过熔透。更麻烦的是熔池本身是剧烈波动的液态金属表面有电弧光照、氧化物漂浮、飞溅穿过画面仅仅靠单帧或单视角图像信息是不完整的。这也是这个项目一开始就决定做“图像对”而不是单张图的原因。1.2 单张图不够图像对才是完整信息所谓的图像对是在同一时刻采集正面熔池和背面熔池两张图像。正面相机能拍到熔池轮廓、熔池长度、液态金属流动方向、电弧形态背面相机能直接看到根部熔透宽度、背面成型是否连续、是否出现焊瘤。两者互相补充。举个例子正面熔池明显变宽、下榻但背面根部宽度只有一点点这说明熔透刚刚建立属于临界状态如果背面根部宽度已经达到板厚的1.2倍以上基本就是过熔透了。单看正面图很难把这个连续变化切准单看背面图又缺少对正面热输入状态的预判。图像对本质上是把一个时序物理过程压缩成了空间上的双视角快照给模型的信息量比单张图翻了一倍还不止。1.3 我最终锁定的技术路线技术路线经历过几次调整。最初用的双流 CNN两路 ResNet18 提取特征后直接拼接效果还行但对临界状态区分不够。后来加了跨注意力融合模块让两部分特征先交互再分类准确率和稳定性都上了一个台阶。这个方案的好处是结构不复杂训练成本可控部署也好做。类别定义上用三分类比二分类更贴近实际欠熔透、正常熔透、过熔透。三分类的好处是能给焊接工艺调整提供更明确的反馈信号——正常熔透保持当前参数欠熔透加电流或减速度过熔透降热输入。这个项目后来还输出了一路“置信度不够就继续观察”的连续帧滑动决策逻辑那是后话文章后面会提到。2. 数据是真正的护城河2.1 图像对采集与对齐数据来自一套模拟焊接工位。正面相机装在与焊枪同步运动的滑架上镜头前加了窄带滤光片和减光片避免电弧过曝背面相机固定在工件下方通过背面熔池的辐射光成像亮度比正面弱很多曝光参数完全不同。工业现场采集图像对最大的坑是同步问题。我们最初用软件触发两张图的采集时刻最多差几十毫秒结果模型训练时频繁出现“正面是熔池波动的高点、背面是低点”的错位样本准确率怎么调都上不去。后来改成硬件同步触发保证两路相机在同一时刻曝光这个问题才解决。采集节奏上焊接过程大概持续几十秒我们按 50 帧每秒保存但不每一帧都用而是每隔 5 帧抽一帧避免相邻帧高度相似导致数据冗余。每对图像保存为一个独立样本命名规则是“试板编号_焊缝编号_帧号_正面.jpg / _背面.jpg”。2.2 标注规则与类别定义标注是整个项目里最耗人力的一环。我们没有用估计的方式而是每拍完一条焊缝都保留试板焊后用金相切片和背面外观照片复核再回头给图像对打标签。三个类别的判断规则欠熔透背面根部未连续熔化或者根部宽度明显小于板厚。正常熔透根部宽度稳定背面成型连续、略有凸起。过熔透背面根部宽度过大出现明显下榻、焊瘤甚至烧穿。标注界面就是一个简单的文件打标工具负责人在正面图和背面图之间切换如果某一帧处在临界状态、判断不了就标记为“争议样本”并直接丢出训练集。实践下来争议样本虽然只占 5% 左右但对模型边界影响很大留着只会把模型搞糊涂。2.3 数据集划分与增强的实战处理这里必须提醒一句千万别按帧随机划分训练集和验证集。相邻帧几乎长得一样随机划分会让验证集里出现大量和训练集高度重合的样本指标虚高到 97%一上现场立刻崩。正确的做法是按焊缝/试板划分保证同一条焊缝的帧不会同时出现在训练集和验证集里这样的评估结果才有参考价值。数据增强方面常规的随机裁剪、翻转、颜色扰动都用但有两个特殊操作针对飞溅和弧光的随机遮挡模拟。真实采集时画面经常被飞溅划出一道亮线训练时用随机遮挡块模拟这种干扰模型对遮挡的容忍度明显提高。极亮区域的局部降低。正面图经常有强烈过曝区域训练时随机对局部区域做像素截断让模型不过度依赖某一个高亮像素。类别不均衡也是大问题欠熔透样本多过熔透样本少。我没有简单粗暴地复制少样本而是先对过熔透样本做更多几何增强同时配合后文说的加权损失函数效果比单用重采样好。3. 模型结构与融合策略3.1 主干网络怎么选主干网络我对比过 ResNet18、ResNet34、MobileNetV3-Large、EfficientNet-B0。数据集规模不算大每个类别也就几千对图太深的网络容易过拟合太浅的网络特征表达又不够。最终选了 ResNet18 做双流主干。原因很实际两层残差结构在中小数据集上表现稳定不容易训崩。提取的特征语义足够丰富不会像 MobileNet 那样为了速度牺牲太多精度。部署时转 ONNX 和量化非常顺ResNet 结构对推理框架的支持最好。如果以后数据量上到十万级可以考虑把主干换成 Swin Transformer 或 ConvNeXt但在这个体量下ResNet18 综合性价比是最高的。3.2 双流输入怎么融合从拼接升级到跨注意力双流模型的关键在融合层。最简单的方式是两个分支的特征向量直接拼接然后接全连接分类。我实测这种拼接方式在验证集上能到 91% 左右但对临界状态区分不好原因在于两路特征只是“并排摆放”没有交互。后来改成跨注意力门控融合。思路是这样正面熔池特征和背面熔池特征各出一个 512 维向量把两者拼接后分别经过一个全连接层得到两个 0 到 1 之间的门控权重用来加权各自的特征再拼接分类。用代码表示融合层的核心逻辑就是import torch import torch.nn as nn class CrossAttentionFusion(nn.Module): def __init__(self, in_dim512, out_dim512): super().__init__() self.fc_t nn.Sequential( nn.Linear(in_dim * 2, in_dim), nn.Sigmoid() ) self.fc_b nn.Sequential( nn.Linear(in_dim * 2, in_dim), nn.Sigmoid() ) def forward(self, feat_top, feat_back): # feat_top, feat_back: [B, 512] concat torch.cat([feat_top, feat_back], dim1) gate_top self.fc_t(concat) gate_back self.fc_b(concat) fused torch.cat([feat_top * gate_top, feat_back * gate_back], dim1) return fused为什么门控有用因为某些时刻正面特征可信度低比如熔池被飞溅遮挡这时模型应该更多依赖背面特征反过来背面图像偶尔会因为反光模糊需要正面特征主导。门控机制相当于让模型根据当前画面质量自适应调整两路信息的权重而不是固定五五开。后续我试过更复杂的双向注意力矩阵但提升只有 0.3 个点左右训练时间却翻了一倍。对这种工业识别任务来说复杂度收益比太差所以最终保留了这个轻量门控方案。3.3 损失函数与类别权重三分类任务默认用交叉熵但我加了两个改动一是标签平滑。把 one-hot 标签变成 0.9 和 0.05 的软标签避免模型对训练集过分自信对提升边界样本的泛化有帮助。二是类别权重。我们的样本天然不均衡欠熔透、正常、过熔透的比例大约是 5:3.5:1.5所以给损失函数传了类别权重让少样本类别的错误被放大强制模型更关注过熔透状态。核心训练损失大致这样criterion nn.CrossEntropyLoss( weighttorch.tensor([0.4, 0.5, 0.25]), label_smoothing0.1 )如果分类难度差别继续拉大可以考虑换 Focal Loss。我这里试过提升不算明显因为过熔透样本数量虽然少但特征其实很突出难点主要在“欠熔透和正常熔透交界处”加权重比加 Focal 更直接。4. 训练细节与代码实现要点4.1 图像对数据加载的代码骨架工程里数据加载这部分核心是保证一对图像以同一个随机种子做同步增强。如果正面图裁了左上角背面图却裁了右下角空间对应关系就乱了等于给模型喂错数据。正确的做法是先把两张图拼成一个整体再统一做几何变换或者像下面这样给变换函数传同一个随机种子import cv2 import torch from torch.utils.data import Dataset class WeldPairDataset(Dataset): def __init__(self, pairs, labels, transformNone, seed42): self.pairs pairs # [(top_path, back_path), ...] self.labels labels self.transform transform self.seed seed def __len__(self): return len(self.pairs) def __getitem__(self, idx): top_path, back_path self.pairs[idx] top_img cv2.imread(top_path, cv2.IMREAD_COLOR) back_img cv2.imread(back_path, cv2.IMREAD_COLOR) if self.transform is not None: # 保证两图使用同一个随机状态 state torch.random.get_rng_state() torch.manual_seed(self.seed idx) top_img self.transform(top_img) torch.random.set_rng_state(state) torch.manual_seed(self.seed idx) back_img self.transform(back_img) return top_img, back_img, self.labels[idx]实际项目里我更推荐在训练循环外部生成一份“变换索引”也就是每个样本预先分配好随机参数训练时按索引读取这样更容易调试。4.2 训练策略与关键参数训练流程分两步走先冻结两个 ResNet18 主干只训练融合层和分类头观察损失能降到什么程度等损失平稳后再解冻主干用更小的学习率整体微调。这种策略能避免一开始梯度就把主干权重冲乱。超参数方面参考我最终跑通的一组配置图像尺寸: 224 x 224 batch size: 32 优化器: AdamW, lr3e-4, weight_decay1e-4 学习率策略: cosine annealing, warmup 5 epochs 总轮数: 60训练大约 20 轮时融合层单独阶段就差不多了解冻主干后再跑 30 轮。单卡训练一轮大约 2 分钟整个训练过程大概一小时出头属于完全可接受的范围。4.3 训练过程中最常撞见的三个坑第一个坑是过拟合。因为按焊缝划分数据后验证集和训练集分布有差异模型很容易在训练集上冲到 99%验证集却卡在 90% 上不去。主要对策是增强、Dropout 和停在第 45 轮左右。第二个坑是 loss 震荡。这个项目里正面图和背面图的图像风格差异很大如果增强参数对两路不一致梯度会来回跳。后来我把增强强度下调了一个档震荡立刻缓和。第三个坑是输入尺寸。一开始用 256x256后面为了实时性降到 224发现准确率几乎没掉。后来又试着降到 160x160掉了一个点但推理快了很多。如果现场硬件紧张160 是性价比很高的选择。5. 评估结果与实战分析5.1 用对评估指标准确率只是个起点由于类别不均衡仅仅看准确率会严重误导。比如全部预测成欠熔透准确率也有 50%看着还行实际毫无用处。我做评估时主要看每个类别的精确率、召回率和宏平均 F1再用混淆矩阵辅助诊断。最终在按焊缝划分的独立验证集上模型整体准确率 94.3%宏平均 F1 0.93。听起来不算惊艳但放在实际工况里已经很够用了——因为现场真正难的是那 5% 的临界状态常规算法在这类样本上基本在瞎猜。5.2 混淆矩阵与典型误判案例这是我印象比较深的一份结果真实\预测欠熔透正常熔透过熔透欠熔透96.5%3.2%0.3%正常熔透2.8%92.1%5.1%过熔透0.4%3.6%96.0%分析误判样本后发现两类典型问题正常熔透被误判成过熔透多发生在背面根部宽度达到临界值的瞬间过熔透被误判成正常熔透是因为局部飞溅遮挡了背面图像模型看不到完整的根部形貌。这些都是物理上很难避免的信息缺失不是无脑改进网络结构能解决的。5.3 对比实验单张图、图像对拼接、跨注意力融合我把相同数据、相同训练策略下跑了几组对比输入方案宏平均 F1推理耗时只输入正面熔池图0.8910 ms只输入背面熔池图0.8610 ms图像对直接拼接0.9014 ms图像对 跨注意力融合0.9315 ms能看出跨注意力带来的净提升接近 3 个点这主要来源于门控机制对临界状态样本的纠偏能力。单看正面图或背面图都会在某些阶段失灵图像对加注意力融合之后相当于多了一套交叉验证机制。6. 部署与实时性优化6.1 模型导出与推理加速训练完的模型需要先转成 ONNX再进一步转 TensorRT才能跑出满意的实时性能。导出之前要固定输入尺寸同时把整个双流模型包成一个完整的模块避免图结构里残留动态维度导致转换失败。我的转换流程import torch from models.weld_model import WeldPenetrationModel model WeldPenetrationModel(backboneresnet18, num_classes3) model.load_state_dict(torch.load(best_model.pt)) model.eval() # 固定输入尺寸为 224x224 fake_top torch.randn(1, 3, 224, 224) fake_back torch.randn(1, 3, 224, 224) torch.onnx.export( model, (fake_top, fake_back), weld_model.onnx, input_names[top_img, back_img], output_names[logits], dynamic_axesNone, opset_version17 )在工控机上PyTorch 直接推理大约 28 毫秒转 ONNX 后 16 毫秒转 TensorRT FP16 后降到 9 毫秒如果把输入尺寸裁到 160可以跑到 6 毫秒以内。焊接过程本身是几十到几百毫秒级别的物理过程这个延迟完全够用。6.2 现场环境下的稳定性问题实验室跑得好不代表现场跑得好这是这个项目给我上过的最深刻一课。第一个问题是相机曝光漂移。现场环境光变化、弧光反射角度变化都可能导致两路图像亮度整体偏移。模型对绝对亮度有一定依赖所以部署代码里加了图像均值方差归一化同时要求现场定期做白平衡校正。第二个问题是时间同步丢失。只要有一帧正面和背面不是同一采集时刻融合阶段的“跨视角”就变成了“跨时间”误判率显著上升。部署时增加了时间戳校验发现错位帧直接丢弃等待下一对同步帧。第三个问题是生产节奏中的异常状态。焊接起弧阶段、熄弧阶段、保护气未开阶段画面和稳定焊接时完全不同。这类样本不在训练分布里模型可能给一个很高的置信度但完全错误。我们最后的处理是给模型加了一个“低置信度”输出门当 softmax 输出最大概率低于 0.75 时不输出状态而是标记为“待观察”交给下一帧继续判断。7. 常见问题与排查技巧实录问题现象可能原因排查与解决验证集指标虚高现场完全不行数据划分泄漏同一焊缝帧出现在训练和验证集按焊缝/试板划分不要按帧随机划分训练 loss 降到很低但验证 loss 高模型过拟合或增强强度太弱增强增强加 Dropout提前停止正面图和背面图特征不对齐软件触发不同步画面差一帧改硬件同步触发加时间戳校验过熔透样本召回率低类别不均衡少样本特征未学充分加重该类损失权重扩充少样本采集量推理延迟超标输入图太大ONNX 结构未优化降输入尺寸到 160转 TensorRT用 FP16飞溅遮挡正面池时误判模型对遮挡不鲁棒训练时加入随机遮挡模拟部署时降低置信度阈值还有一个容易被忽略的小技巧训练时不要在每一帧上做实时预测而是对连续 3 到 5 帧的预测结果做滑动投票。焊接熔透状态不会在几毫秒内跳变用时间一致性清洗掉单帧噪声效果比单纯调模型参数更明显。这个机制实现简单却把现场误报率降了将近一半。这个项目里我最大的体会是工业视觉项目真正难的从来不是把模型准确率从 90 搞到 95而是数据是否可信、评估是否公平、部署是否经得起现场折腾。熔池图像对识别这条路走通之后后续可以往更多方向扩展比如把熔池图像序列当视频做时序建模或者把预测结果直接接到焊接参数闭环控制里。先把手上的数据工程做到位再谈更高级的模型这个顺序一定不会错。