工业视觉实战:Mask R-CNN结合RegNetX实现钢水罐及未知异物实例分割
做工业视觉这几年我最怕听到的一句话就是模型在测试集上效果挺好一到现场就翻车。最近在做的钢水罐及未定义物体目标检测系统正好把这几个坑全踩了一遍。钢水罐是炼钢环节的核心容器承载一千多度的高温钢水需要自动监控罐体的位置、轮廓和附近是否出现不明异物。车间里粉尘大、光照乱、罐体表面还会因为高温氧化不断变色传统机器视觉的固定阈值和模板匹配根本招架不住。所以这个项目把方案换成了基于 Mask R-CNN 与 RegNetX 的实例分割思路——RegNetX 负责提取更高效、更稳定的特征Mask R-CNN 负责对钢水罐做像素级的分割并留出对训练阶段没见过的未定义物体的预警通道。这篇文章把整个过程从选型、标注、训练到部署的经验和教训都梳理一遍适合做工业视觉落地、实例分割或开放场景目标检测的同行参考。1. 项目背景为什么钢水罐检测不能靠传统视觉1.1 钢水罐监测场景的真实难点钢水罐看似是一个巨大、轮廓清晰的容器实际拍摄条件远比想象中恶劣。罐体在吊运、浇铸、返回的过程中位置不停变化角度也不断转换现场还会有钢水飞溅、水雾升腾、红外辐射干扰。传统视觉方案常用固定 ROI、模板匹配或灰度阈值只要罐体换一个角度或者高光区域盖住罐口特征就完全对不上漏检和误检非常严重。另一个麻烦是罐体本身的外观并不稳定。新的钢水罐表面有清晰的漆面和结构但用一段时间后氧化皮会成片脱落罐沿会挂渣高温会让局部区域变成亮红色甚至白热色。这种情况下任何依赖颜色特征的视觉算法都会失效。深度学习目标检测虽然对颜色变化更鲁棒但如果只是输出一个矩形框依然很难满足后续的安全判断因为安全逻辑需要知道“异物是否侵入罐口区域”或者“罐体轮廓是否完整”。1.2 “未定义物体”到底指什么工业现场的目标检测通常只关注预先定义好的类别比如钢水罐、鱼雷罐、渣罐、天车吊钩。但真实风险往往来自“没有提前定义”的物体比如遗落在轨道上的扳手、断裂的渣块、掉落的耐材甚至是误入作业区域的人。需求方不可能在项目初期把这些物体全部枚举清楚即使枚举了样本也很难收集。未定义物体指的就是模型训练阶段没有见过、但在运行时需要被发现的异常目标。实现上有两种思路一种是把“未定义物体”直接当成一个额外的类专门收集形态各异的异物样本去训练另一种是借用模型的背景类概率和特征距离对不属于任何已知类别的区域做开放集识别。两种方法不冲突甚至可以叠加。我们在项目中先采用“额外类别”的方式因为落地最快、解释成本最低后续再引入特征距离计算对模型判定为“未定义物体”的可信度做二次校验。1.3 为什么选了 Mask R-CNN 而不是纯检测框如果只做钢水罐定位用 Faster R-CNN 或 YOLO 就够但项目里不仅要“框住”还要“圈出轮廓”。钢水罐带有耳轴、罐沿、罐底等不规则结构普通检测框会框入大量背景下游的报警逻辑很难判断框内区域到底有没有异物。一个像素级 mask 可以精确表达目标占用的空间范围这样当异物出现在罐口上方、罐沿附近时系统能通过 mask 区域重叠度做更准确的判断。Mask R-CNN 和纯语义分割的区别在于实例级表达。钢水罐作业区域可能同时出现多台罐体和多个未定义物体语义分割会把同类目标糊成一个连通域很难区分“哪一个罐体出了问题”。Mask R-CNN 的输出天然自带实例编号每个目标都有独立的 mask后续和天车定位、罐体 ID 做关联时非常方便。这也是我最终放弃 DeepLab 这类语义分割模型的核心原因。2. 模型选型拆解RegNetX 为什么会出现在这种任务里2.1 Mask R-CNN 骨架选择的前因后果Mask R-CNN 本身是一个框架真正决定特征上限的是骨干网络。最常用的骨干是 ResNet50 和 ResNet101相关资料多、调参经验丰富但在钢水罐检测这个任务里我的体会是 ResNet 的“计算效率配比”不够理想。钢水罐在画面里经常处于中远距离目标和相机之间隔着大量烟尘需要网络在相同算力下提取更细腻的特征。RegNetX 正是在这种诉求下被引入的。用 RegNetX 做骨干需要配合 FPN 多尺度特征金字塔。钢水罐的大小在不同工位差异很大有的视角下罐体几乎占满整个画面有的视角下罐体只占画面的十分之一。FPN 可以把高层语义特征和低层细节特征融合起来保证大小目标都能被检测到。RegNetX 生成的多尺度特征有一个特点它的各个 stage 宽度和通道比例是经过设计空间搜索的比人工设计的 ResNet 更均衡所以喂给 FPN 之后小目标的召回率通常表现更稳。2.2 简单聊聊 RegNetX 的设计思路RegNet 系列的核心不是某一组具体网络结构而是提供了一套“设计空间”。设计空间里包含 depth、initial width、width slope、group width 等参数通过统计模型在这些参数组合上的表现找到性能与算力之间的帕累托前沿。RegNetX 就是这个设计空间里带 group conv 的一族网络结构它的宽度不是像 ResNet 那样逐 stage 简单翻倍而是按一定函数规律增长。这种设计的实际价值在于同样的 FLOPs 预算下RegNetX 能获得比 ResNet 更低的误差。对工业侧来说算力是硬约束。现场的工控机可能只有一张中端显卡选一个计算量不过度膨胀、但特征表达足够的骨干比一味追求大模型更实际。RegNetX 的不同档位正好覆盖从轻量到重量的需求比如 RegNetX-1.6GF 适合老旧显卡RegNetX-4GF 适合当前主流的推理卡RegNetX-8GF 则适合离线分析。2.3 与 ResNet / EfficientNet 的对比骨干网络特征提取能力训练成本推理成本调参成熟度ResNet50中规中矩稳定低中最高RegNetX-4GF同级算力下更优中中略低EfficientNet-B4强但结构复杂高高低单看 mAP 指标EfficientNet 系列往往能刷出更好看的数字但把它接进 Mask R-CNN 的 FPN 结构时需要额外适配 stride 和通道数而且在工业现场的工控机上推理延迟明显偏高。EfficientNet 的深度可分离卷积在部分硬件上优化得并不好实际部署速度常常达不到理论预期。ResNet50 最省心资料多、问题少但精度上限偏低尤其是在未定义物体这种组织形态差异很大的类别上特征区分度不够。RegNetX 处在中间档不需要像 EfficientNet 那样做大量结构适配又能在同算力下比 ResNet 多拿一点精度。我在项目里最终选了 RegNetX-4GF 作为骨干主要是结合了现场显卡的显存和帧率要求。如果现场只有老一代显卡我更建议退到 RegNetX-1.6GF然后适当降低输入图像分辨率而不是硬上大模型。2.4 选型结论选型这件事不能只看测试集精度还要看模型在“脏数据”下的表现。钢水罐场景里最不缺的就是光斑、粉尘、蒸汽遮挡骨干网络如果太深太宽很容易在训练集上记住那些高光噪声。RegNetX 的设计空间搜索其实隐式地加入了正则化效果使网络不会在个别特征上过度自信。这是我实际训练后感受最明显的一点同一批数据RegNetX 的验证 loss 和训练 loss 之间的差距通常比 ResNet 更小过拟合压力更小。反过来也要提醒一句RegNetX 在开源社区里的现成 Mask R-CNN 配置不如 ResNet 那么多自己改配置时容易踩到 backbone 输出 stride 对不上 FPN 的坑。第一次接入时建议先把骨干改成 RegNetX 但不改其他模块跑一遍单张图确认 channel 对齐再继续调参。3. 数据集构建钢水罐和“未定义物体”的标注策略3.1 现场图像采集设备怎么放模型效果的上限由数据决定这个道理在工业场景里尤其明显。钢水罐图像的采集点位不能只放在一个固定视角至少要覆盖三个典型机位钢包回转台俯视位、浇铸跨侧方位、返回轨道末端位。相机高度和角度会影响罐体在图像中的尺度只用一个视角训练出来的模型换到另一个工位后检测精度会明显下降。采集时段要跨白天、黑夜、凌晨覆盖晴天和阴天。很多项目容易犯只采白班的错误但钢厂里钢水罐是 24 小时连续运转的夜间厂房灯光的色温和亮度变化比白天更极端。帧采样不要做连续视频帧的密集抽取因为相邻帧高度相似会造成训练集信息冗余。我的做法是每隔 3 到 5 秒抽一帧同时观察钢包旋转台的动作确保罐体前后左右各个角度都有覆盖。3.2 标注规范哪些东西该标成“未定义物体”标注规范是整个项目里最容易扯皮、也最影响模型质量的部分。已知类别这一侧钢水罐建议单独成一类罐体附属的耳轴、罐沿属于同一个实例的一部分不需要单独拆出来。未定义物体那一侧要明确一个原则必须是空间上可定位的实体异物比如工具、残钢、渣块、防堵料不能把火光、反光、水雾这些非持久现象标成未定义物体。如果视野里一个物体被遮挡超过一半无法判断真实类别就统一标为“未定义物体”。这样标注看似简单实际执行时会遇到大量边界情况。比如一个扳手半截插在渣土里露出来的部分非常小标还是不标我的经验是只要人眼能明确判断它不是一个固定设施就应该标出来哪怕面积很小。因为未定义物体的样本本来就稀缺漏标一个模型就少一次学习机会。另外同一张图里的多个互相接触的未定义物体标注时要用语义边缘仔细切开不能直接把一大片东西画成一个 mask否则模型学到的是“一团杂物”而不是“独立异物”。这个细节直接影响 mask 边界的质量也是后来排查误报时最容易翻车的地方。3.3 数据增强与负样本处理工业环境的数据增强不能照搬通用目标检测的套路。除了常规的随机亮度、对比度、饱和度调整还要专门模拟两类现场干扰一类是飞溅的火花表现为图像里随机出现的高亮短线条和小亮斑另一类是蒸汽和粉尘表现为局部区域的模糊和对比度下降。我在增强管线里加入了一个随机叠加高光噪声的算子用一些可在运行时生成的圆形亮斑覆盖到图像随机位置发现能明显提高模型在高光区域的稳定性。负样本同样不能忽略。所谓负样本就是完全没有钢水罐和未定义物体的背景图比如空荡荡的轨道、墙面、地面。加入负样本可以让模型学会抑制那些看起来像目标但实际不是目标的区域减少部署现场的无意义误报。负样本不需要太多占训练集的 10% 左右就够并且要覆盖不同光照条件和不同机位。注意不要对标注好的 mask 做大幅旋转增强尤其是超过 45 度的旋转。钢水罐在实际场景里虽然有不同角度但不会倒立。过度旋转增强会让模型学到不符合物理规律的特征反而损害真实场景表现。3.4 不要忽略的类间相似度钢水罐的检测还有一个天然难点它与渣罐、中间包、废钢斗在外形上高度相似。如果标注时只关心“是不是罐子”模型很容易把这些相似设备都识别成钢水罐。实际标注时要把这些常见干扰物单独列出哪怕不参与最终评估也要作为背景负类或者单独类别放进训练集让模型学会区分“钢水罐”和“长得很像钢水罐但不是的东西”。另外钢水罐在高温状态下的颜色变化极大特别是满罐和空罐时温差造成的红外辐射差异会让视觉特征发生偏移。我在项目里没有简单地只喂 RGB 图像而是同时用传统图像处理估计整体色温并在输入模型前做一次白平衡归一化。这个操作的目的是减少不同炉次之间的颜色漂移让模型更多关注罐体的几何结构而不是被颜色带偏。4. 训练细节与调参记录4.1 环境和依赖整个训练环境基于 PyTorch 搭建使用开源的实例分割框架骨干网络替换为 RegNetX。具体版本不展开说了因为这类框架迭代很快。但有一点建议训练前把环境锁死用 conda 创建独立环境避免因为依赖库版本不一致导致复现结果漂移。conda create -n industrial_ins python3.8 -y conda activate industrial_ins pip install torch1.10.0cu113 torchvision0.11.0cu113 pip install opencv-python pip install pycocotools我用的是单卡训练显存 11GB 左右。如果显存不够优先降低 batch size而不是急着换更小的骨干因为 RegNetX 在显存占用上已经比同精度的 ResNet 更理想。4.2 迁移学习与冻结训练策略钢水罐的数据集规模通常不会太大从头训练 Mask R-CNN 很难收敛。我的做法是加载在公开数据集上预训练好的 RegNetX 骨干权重然后分阶段微调。第一阶段冻结骨干网络的前两个 stage只训练 RPN、分类头和 mask head让模型先学会钢水罐的基本位置和轮廓第二阶段再解冻骨干网络用较低的学习率微调所有层。这个顺序很关键。如果一开始就全部放开训练骨干网络受到小数据集的干扰预训练学到的通用特征会被快速破坏后面再想恢复正常很困难。解冻骨干的时机我一般以分类 loss 的下降曲线为准等到第一阶段 loss 明显收敛再进入第二阶段整体训练会稳定很多。4.3 关键超参数输入图像尺寸使用短边 800、长边 1333 的默认配置但钢水罐远距离时比较小所以我额外增加了数据增强里的随机缩放让同一张图在训练时既有大尺度版本也有小尺度版本等于变相让模型适应不同距离的罐体。超参数方面批量大小设 4学习率从 0.001 开始采用余弦退火策略。如果显存紧张只能跑 batch size 2学习率要同步降到 0.0005这个对应关系容易被忽略。RPN 和 ROI Head 的 loss 权重保持默认但我在 mask loss 上稍微加重因为项目更看重轮廓精度mask 质量直接决定后续区域重叠判断是否可靠。迭代数不要太死板。我一般设置最大 20k 步同时配合早停验证集上的 mAP 连续 1000 步不涨就停。钢水罐这类目标相对单一训练到后期很容易出现过拟合早停比盲目多跑更有效。4.4 训练遇到的问题和曲线解读第一次训练时验证集上的未定义物体召回率特别低loss 却一路下降。后来检查发现标注里未定义物体的样本数量只占全部目标的 8%类别严重不均衡。解决办法是把缺少未定义物体样本的图片做重复采样让模型每个 epoch 都能充分看到未知类别而不是靠运气撞上。另外训练曲线中 mask loss 出现明显的周期性抖动通常是因为同一个钢水罐在不同帧里的标注边界不一致。标注人员在罐口结渣位置经常产生分歧有的人把渣块画进钢水罐 mask有的人把渣块画成未定义物体。这类标注噪声会让 mask head 无所适从。后来我们重新制定了标注规则罐体表面附着的、与罐体接触的渣块一律归入钢水罐独立掉落在罐外区域的渣块才标成未定义物体。规则明确后mask loss 的抖动明显减小。5. 部署与系统集成实操重点5.1 推理流程设计检测、分割、报警的三段式部署不是把模型跑起来就完事而是要把模型输出变成现场能用的决策结果。我设计的推理流程分三段第一段是模型推理输出钢水罐和未定义物体的 bbox、mask、类别和置信度第二段做后处理过滤去掉置信度过低、面积过小的碎片区域第三段做规则判断根据目标区域和报警区域的重叠关系生成信号。# 伪代码推理后的目标过滤示例 valid_objects [] for obj in predictions: if obj[score] 0.5: continue if obj[score] 0.7 and obj[mask_area] 500: continue valid_objects.append(obj)这套过滤逻辑的意义在于减少单帧偶发误报。钢水罐和异物的置信度阈值不能一刀切因为钢水罐结构清晰置信度通常很高未定义物体形态复杂置信度天然偏低。如果统一要求 0.7可能把真正的异物全部过滤掉。我的做法是钢水罐阈值 0.7未定义物体阈值 0.4并且再配合 mask 面积下限来排除噪声。5.2 与现场控制系统对接时的取舍现场控制系统需要的是简单的开关量或者结构化消息而不是一张图片。所以模型服务端只输出 JSON包括目标类别、置信度、归一化坐标和 mask 简化后的多边形点集。报警决策不在模型服务端做死而是交给上层规则引擎方便现场工程师调整逻辑。模型推理的速度和现场要求的响应时间存在矛盾。检测钢水罐漏包这种事故越快越好但一味的低延迟会牺牲精度。我在工程里做了两级处理关键区域用高分辨率、高帧率连续检测次要区域用低帧率轮询。这样既能保证关键报警的实时性又不至于让工控机长时间满负荷跑模型。5.3 光照变化、粉尘干扰、模型抖动怎么处理现场最大的坑不是模型而是相机。钢水浇铸过程中钢水辐射会让相机的自动曝光来回跳图像亮度一会儿过曝一会儿过暗模型输出开始剧烈抖动。解决办法是把相机曝光时间固定光圈固定关掉自动白平衡。然后在图像进入模型前用统计量做一次归一化把亮度和对比度拉到一个稳定范围。粉尘和水雾会附着在镜头保护罩上图像逐渐发白模型精度断崖式下降。我在部署方案里加了一个图像清晰度检测任务计算梯度能量低于阈值就触发吹扫装置并暂时把该相机的检测结果标记为低可靠避免误报警。这个细节若干预不及时整个系统会变成“每天报警全是误报”。注意多帧投票可以抑制随机噪声但不能盲目用于钢水罐场景。如果钢水罐正在快速回转多帧平均会让轮廓变成半透明拖影反而破坏 mask。我一般只对报警输出做连续 3 帧确认不对 mask 图像本身做时间平均。6. 常见问题与排查技巧实录6.1 钢水罐漏检率高的原因钢水罐漏检最常见的原因不是模型太弱而是目标尺寸和 FPN 特征层不匹配。罐体远距离成像时像素面积小锚框尺寸覆盖不到模型根本没机会把它当成一个候选框。排查时先看 RPN 阶段有没有输出包含钢水罐的 proposal如果 RPN 就漏了问题几乎可以锁定在锚框和输入尺寸上。解决思路有两个一是提高输入图像分辨率相当于把目标整体放大二是在 FPN 的 P2 层额外增加检测头P2 层的 stride 更小对小目标更友好。但如果现场算力有限增加 P2 层会带来明显延迟上升所以我更推荐优先调大输入尺寸再观察漏检情况。6.2 Mask 边界不干净怎么修钢水罐的 mask 边界经常出现锯齿和孔洞尤其是罐沿附近有火光遮挡的时候。产生原因一方面是标注时罐口边缘不齐另一方面是 mask head 对局部纹理过度敏感。直接在训练层面解决最彻底用边缘更平滑的标注重新修正训练集但投入很大。部署层面可以先试用形态学闭运算把细小的孔洞补上再用腐蚀去掉孤立噪点。不过形态学操作参数不能拍脑袋定。kernel 大小取 3 到 5 就够了太大容易把两个本应分开的目标粘连在一起。我踩过这个坑为了补齐 mask 孔洞把闭运算 kernel 调到 7结果罐体和旁边的渣块直接连成一片区域重叠判断全部失灵。6.3 未定义物体误报成已知类未定义物体最让人头疼的问题是误报成钢水罐。原因通常很简单未定义物体样本太少模型没有学到足够强的“它不是一个钢水罐”的证据。另一个原因是钢水罐本身形态变化大模型对罐体的特征描述过于宽松导致异形耐材、工具等物体被划进罐体类别。我的处理方法是做难例挖掘把验证集中所有误报样本挑出来重新标注成对应的未定义物体子类然后追加到训练集中继续训练。这个循环重复两到三轮后误报会明显下降。如果时间紧张也可以在决策层加入特征距离判断对模型预测为已知类别但特征向量离类别中心很远的样本打上低可靠标签。6.4 一个排查实例从误报样本反推数据问题有一次系统上线后频繁把浇铸区域的反射光斑识别成未定义物体。反射光在空间上不固定亮度高形状不规则和未定义物体样本很像。我导出近一周的误报图片按特征聚类后发现训练数据里所有“高光小区域”几乎都被标成了未定义物体因为标注人员把飞溅钢花和反光也框了进去。模型学到的是“这里有一片亮的东西就是未定义物体”。修正很直接把训练标注中属于非实体光源的标签全部删除只保留空间上可定位的异物同时新增一批包含强反光但没有任何异物的负样本。重新训练后这类误报减少了大约一半剩下的再通过决策层的时间连续性判断过滤。这个案例说明数据标注的错误会原封不动地变成模型的行为不要一上来就怀疑网络结构。7. 指标解读与实际收益7.1 用哪些指标判断项目成功工业项目不能只看 mAP。mAP 是一个综合指标但安全系统更关心两类错误漏报和误报。漏报指的是真正出现异物但没有被检测到这是安全底线误报指的是现场没有异常却频繁报警这会让操作人员失去信任。我建议把评价指标拆成钢水罐检测召回率、未定义物体检测召回率、每班次误报次数和平均处理延迟四个维度。在模型调优阶段我会额外关注每个类别的召回率和置信度分布。未定义物体的召回率通常低于钢水罐因为形态差异太大不能只看总 mAP 掩盖这个短板。如果钢水罐 mAP 已经不错但未定义物体召回率很低这个项目依然不能上线因为漏掉一个异物就可能是重大事故。7.2 实际效果与局限从我们的实地测试来看换成 RegNetX 骨干后钢水罐的 mask 边界稳定性比之前用 ResNet50 时更好尤其是罐口高温区域附近的轮廓更完整。未定义物体的检测也能满足基本预警需求但距离“完全开放集识别”还有差距遇到全新的、和训练样本差异极大的物体时模型仍然会漏。这个局限不是 Mask R-CNN 或 RegNetX 单独能解决的本质上是封闭集分类和开放世界识别之间的鸿沟。想要进一步提高需要在决策层引入额外的鲁棒性判断比如深度特征分布建模而不能指望只靠分类层输出概率就能覆盖所有未知情况。7.3 后续可以扩展的方向这个项目后续最大的扩展空间是引入深度相机或激光雷达点云。钢水罐和异物在二维图像里容易受高光和遮挡影响但在三维空间里物体的几何轮廓要稳定得多。用 Mask R-CNN 先做二维实例分割再把分割结果投影到点云上做三维校验能够大幅降低误报。另一个方向是把检测系统从“识别已知未知”升级为“跟踪已知未知”。当前只在单帧图像上做检测没有利用多帧之间的关联。如果加入轻量级目标跟踪就能根据物体运动轨迹判断是否是持久异物过滤掉一闪而过的火光。这样既保留 Mask R-CNN 实例分割的精度又多了时间维度的鲁棒性。最后分享一个我在这个项目里最有感触的经验不要急着换更复杂的模型先把标注一致性、数据增强覆盖度和现场图像质量这三件事做扎实。钢水罐检测的绝大多数问题最后都指向数据而不是模型。RegNetX 给了我更好的起点但真正让系统稳定跑在车间的是一遍又一遍修正标注规则、调整拍摄参数、观察误报样本的这些基础工作。如果你也在做类似的工业检测项目建议从错误样本出发反推问题而不是盲目堆算力。