资讯动态

基于深度学习的钢铁表面缺陷检测:从成像数据到产线落地

发布时间:2026/10/27 11:26:33 来源:尧图企业网站定制
钢铁表面缺陷检测这件事我从头到尾踩了一年多的坑。最早接手这个需求的时候想法特别朴素不就是给钢板拍张照片扔进网络里分出个类别来吗后来真正站到产线边上看着钢板以每秒一米的速度从眼前呼啸而过、头顶的冷却水雾糊住镜头、白天和晚上的光照完全不是一个样子才知道这件事的难点根本不在于选哪个网络结构而在于你有没有能力把“工业现场”这四个字翻译成一个能训得动、跑得起的深度学习任务。基于深度学习的钢铁缺陷识别说到底是把一条高速运转的金属加工产线上那些肉眼都未必看得清、看久了还会漏判的表面异常交给一套稳定可复现的视觉系统去判读输出缺陷的有无、类别、位置和尺寸。它解决的问题很明确人工目检的漏检率高、一致性差、疲劳度高而且缺乏可追溯的结构化数据。这篇文章主要写给三类人看——刚接触到工业视觉检测、想把深度学习真正落地到产线上的算法工程师负责产线质量管控、需要评估这套方案可行性的工艺人员以及正在做相关课题、想了解工程侧会碰到哪些真实问题的同学。文中涉及的具体参数、相机配置和缺陷类别我做了合理虚构与抽象处理但推导逻辑和踩坑经验是我真实趟过来的。1. 方案整体设计与技术路线拆解1.1 钢铁缺陷到底难在哪些地方先别急着建网络。我在动手写第一行训练代码之前花了两周时间只是看图片、跟着班组去现场看实物。有不看这些的同行模型在测试集上跑到 0.9 的 mAP到了现场直接掉到 0.4回头就怪数据集不够大。真正的原因是没理解缺陷的成像特性。钢铁表面缺陷的难点我总结成下面四条每一条都直接决定了后面模型怎么设计。第一是类内差异巨大、类间差异极小。同样叫“划痕”有几十毫米长的细线也有一小片磨花的区域而“氧化铁皮压入”和“麻点”在低分辨率下几乎是一个灰度斑块。这意味模型的判别能力不能只靠低频的纹理信息必须保留足够的局部细节输入分辨率的选择就成了第一道关卡。第二是缺陷尺寸跨越三个数量级。最小的针孔类缺陷宽度不到 0.5 mm最长的边裂可以贯穿整个视场。同一套感受野去吃两端目标会很吃力这是我后来采用多尺度输入、并在推理时做切片的原因。第三是极端的样本不均衡。一整卷钢带出缺陷的比例大概在千分之一量级一张 2000×2000 的图上可能一条划痕都没有。类别之间的分布也极不均衡常见缺陷占了七八成剩下几类每类只有几十个样本。这种数据分布下任何用普通交叉熵、普通随机划分训出来的模型都只是在拟合类别先验。第四是成像条件不稳定。反光、水渍、氧化色差、辊子转动带来的周期性明暗条纹全都会被网络当成特征学进去。我见过一个模型在训练集上对“辊印”这类缺陷识别极好结果一换班灯光角度变了 3 度全部漏检。这不是模型的问题是数据覆盖问题。注意如果你的任务里出现了周期性的条状纹理规律先怀疑是产线本身的辊道或光源造成的假特征而不是缺陷本身。判断方法很简单把这块区域裁出来看它是否在整幅图上等间距重复出现。1.2 为什么这套场景最终选了“检测”而不是“分类”最开始我确实想用分类网络解决问题——一个钢板表面图片二分有缺陷、没缺陷。跑得很快效果看着也不错99.8% 的准确率。但这个数字是骗人的因为如果缺陷样本只占 0.2%模型全部输出“无缺陷”就能达到这个准确率。更要命的是分类模型给不出位置产线要的是缺陷在哪、多大好决定是切掉这一段还是降级处理。分割方案我也想过语义分割或者实例分割理论上信息量最全但在工业现场有两个绕不开的门槛一是标注成本像素级标注需要熟练质检员用多边形一点点抠一张图常常要十几分钟做三千张的数据集成本已经很难接受二是推理速度全分辨率分割模型的耗时在产线节拍面前很难交代。最终落点是目标检测理由很清楚矩形框标注的成本可控能提供位置与尺寸的近似估计可以量化出缺陷长度和宽度同时推理速度快可以做实时。代价是稠密小目标、细长裂纹的框回归不好所以我们把“极细长裂纹”和“粘连缺陷”单独做了切片分检和后处理拆分这部分后面细说。方案标注成本输出信息推理速度适配性图像分类低仅有类别最快只能做初筛目标检测中类别位置尺寸快主力方案语义分割高像素级区域中小缺陷、复杂形状实例分割很高逐实例掩码慢仅做研究验证1.3 整体链路是怎么串起来的整套系统我拆成五段成像采集、数据治理、模型训练、推理加速、产线集成。很多人喜欢只盯着第三段实际上真正决定成败的是第一段和第五段。成像采集决定了下限。你采回来的图本身信噪比不够、对比度不够后面再怎么调模型都是徒劳。这一段的核心是光源方案和相机参数1.3 之后的第四章会专门算一遍。数据治理决定上限。包括标注规范、类别体系、抽帧去重、困难样本回捞。模型训练是常规工程选型、增强、损失、调参。推理加速决定能不能上产线通常要考虑半精度、图优化、批处理、切片调度。产线集成是所有人最容易低估的一段——报警要不要联动执行机构、NG 图片存多久、模型更新怎么灰度、误检由谁来复检这些都是代码之外的活。我习惯把每一段的验收标准先写出来再动手。比如成像段的验收标准是“在正常工况下最小可检缺陷在图像上不少于 8 个像素跨度”数据段的验收标准是“每一类缺陷在验证集中至少有 50 个实例且覆盖至少 3 个不同批次”。2. 数据集构建与标注核心细节2.1 类别体系怎么定才不自找麻烦类别体系这件事我建议开工第一天就找懂工艺的人一起定不要自己拍脑袋。我第一版定了 12 类训了两周发现有三类样本加起来不到 40 个且相互之间工艺上本来就难区分最后不得不合并回 8 类前面的标注全白做。我的做法是按“工艺上是否需要区分处理”来定类别而不是按“视觉上看起来不一样”。如果两类缺陷的处理方式完全一样——都是切掉、都是降级那模型上就没有区分它们的必要合并成一类反而能显著提升样本量。反过来如果工艺上要区别对待哪怕它们长得像也得分开并在标注规范里写清楚判定依据。最终落地的类别大概是这样一副骨架类别典型形态处理方式样本稀缺度划伤线状、有方向性降级或切除中压入氧化皮不规则块状、边界模糊降级高麻点密集小凹坑降级中夹杂深色不规则斑切除很高裂纹细长、常沿轧向切除最高优先级高辊印等间距周期性条纹观察、溯源设备低边裂板边开口切除中镀层异常色差型片状区域降级高类别定完之后还有一个容易忽略的事给每一类写上“不是这一类的样子”。比如“夹杂”和“深色氧化斑”的边界我当时在标注规范里补了一句判定规则——低于某个灰度且边界锐利、内部无纹理延伸的算夹杂边界逐渐过渡的算氧化斑。这一句话让三个人标注的一致性从七成多提升到了九成以上。2.2 标注质量的坑比想象中深标注这件事我建议宁慢勿快。真实经验是一个模型效果上不去九成情况先回头查标注别急着改网络。踩过的几个具体坑说给你听。框贴边的问题。有的标注员习惯把框画得紧贴目标边缘有的留一圈余量。这两种风格混在一起模型学出来的回归目标就是矛盾的。我的规范是统一向外扩 2 到 3 个像素理由是卷积特征在目标边界处本来就存在扩散稍大一点的框能让正样本采样更稳。长裂纹的框怎么画。一条沿轧向延伸 800 像素、宽度只有 6 像素的裂纹如果用一个大框把整条裂纹框住框内 90% 都是背景回归目标的宽高比极端任何基于 IoU 的匹配策略都会出问题。我的处理是把长裂纹分段标注每段控制在宽高比不超过 1:8 的范围内推理时再做线段合并。这个改动让裂纹类的召回率提升了十几个点。模糊区域的处理。产线上总有水雾、失焦、反光造成的模糊图。这些区域如果有疑似缺陷标注员会犹豫。我的规定是无法确认的一律不标但整张图打一个“低质量”标签训练时做降权采样。反过来如果低质量图里一个框都没有也不要直接当负样本用否则模型会学到“模糊无缺陷”这个错误关联。重复帧去重。产线是连续采样的相邻两帧差别极小。如果不做去重同一个缺陷会在训练集和验证集里同时出现指标虚高得离谱。我用感知哈希做粗去重再用图像相似度做二次过滤阈值调到能过滤掉同卷相邻帧但不误杀不同批次里长得像的正常图。这件事做完验证集指标掉了一大截但那是真实指标。2.3 数据增强怎么做才有效增强策略这块抄袭图像分类的通用配方在钢铁缺陷上会翻车。我一个个说。几何变换要谨慎。水平翻转一般没大问题但垂直翻转要慎用——很多缺陷有明确的轧向垂直翻转会制造出现实中不存在的方向性。大角度旋转更危险90 度旋转对纹理类缺陷麻点、氧化皮可能还行对划痕类会引入不真实的分布。我的取值是随机旋转限制在 ±10 度翻转只用水平翻转且只对不敏感类别开启。色彩扰动要克制。钢板的整体色调由氧化程度决定不是一个可以随便改的属性。亮度、对比度的小幅抖动是可以的色相的大范围偏移会破坏缺陷与基体的相对关系。我的参数是亮度 ±0.15、对比度 ±0.15、饱和度 ±0.1超过这个范围我实测过会把“深色夹杂”改造成看起来像“氧化斑”。MixUp 和 Mosaic 要分场景。Mosaic 对检测任务很有帮助它强行让模型在一张图里见到多尺度目标对小目标召回提升明显这个我一直在用。MixUp 混合是把两张图线性叠加对钢铁这种强纹理图会叠出根本不存在的灰度假象我验证过反而掉点直接关掉。我加了一个自造的增强光照模拟。做法是把图像转到与亮度无关的通道空间只对亮度分量做不规则的非线性映射模拟现场光照不均造成的明暗带。这个增强比任何通用增强都管用因为它对付的正是“换班后模型崩掉”这个问题。import numpy as np import cv2 def uneven_illumination(img, strength0.25): 模拟产线光照不均沿随机方向生成低频明暗梯度 h, w img.shape[:2] # 随机方向的低频条纹模拟光源角度变化 angle np.random.uniform(0, np.pi) xs np.linspace(0, 1, w)[None, :] ys np.linspace(0, 1, h)[:, None] proj np.cos(angle) * xs np.sin(angle) * ys freq np.random.uniform(1.0, 3.0) grad np.sin(proj * np.pi * freq) * strength grad np.clip(1.0 grad, 0.55, 1.45) img_f img.astype(np.float32) out img_f * grad[..., None] return np.clip(out, 0, 255).astype(np.uint8)这段代码我放在训练管线的最后一步概率设 0.3。它不改变标注框位置所以对检测任务完全安全实测能把现场换班后的掉点幅度压掉一半以上。3. 模型选型与训练实施要点3.1 主干与检测头的选型逻辑选型我一直遵循一个原则能在同等精度下把推理耗时压下来的方案优先因为产线的节拍是不等人的。所以我从单阶段检测器出发先把基线跑通。主干网络方面工业缺陷检测的特征主要是中等尺度的纹理异常和细长的边缘结构。轻量级主干在高层语义上够用但浅层的细节响应偏弱。我的做法是保留轻量主干在浅层引出额外的高分辨率特征分支并把检测头挂到更浅的层级上代价是算力增加有限收益是对针孔、细线类目标的召回。这里有个具体的取舍我印象很深。早期我用了一个很轻的主干参数量不到 3M模型体积很小推理飞快但“麻点”这一类的召回一直在 0.6 附近上不去。我后来对比了特征图可视化发现麻点在浅层响应其实很清楚但经过几次下采样之后特征被稀释掉了。解决办法不是换大模型而是把输入分辨率提高一档并在特征融合时给浅层加权重。召回直接跳到 0.82推理耗时只涨了不到 20%。注意力机制我试过几类结论是坐标注意力类同时建模长宽方向对细长裂纹有效通用通道注意力收益有限。原因是细长缺陷在空间上的响应是沿一个方向延展的只做通道加权捕捉不到方向性。但这个模块一定要放在融合层而不是主干里堆堆在主干里参数一起涨性价比很差。3.2 正负样本分配与损失函数这部分是很多教程略过的但对不均衡数据影响最大。正负样本分配。If 你用的是基于 IoU 阈值的分配策略在钢铁缺陷上要小心大片背景区域里的小缺陷IoU 天然偏低容易分不到足够正样本。我改成动态分配之后依赖每个目标的统计特征决定分配数量小目标的召回明显改善。这个改动我建议所有人都试一下尤其你的数据里小目标占比超过三成的时候。分类损失。极端不均衡下普通二值交叉熵会被海量简单负样本主导。我用的是带聚焦系数的交叉熵把易分样本的权重压下去让梯度集中在难样本上。参数我用的 1.5试过 2.0太激进会导致训练后期震荡。同时配合一个正样本采样比例控制每张图输入到损失里的正负比例在 1:3 左右。回归损失。定位损失我用了带距离惩罚的形式因为裂纹这类极窄目标纯 IoU 形式的梯度在框不重叠时会消失训练容易卡住。距离惩罚项能在框完全不重叠时仍然提供有效梯度这一点对快速收敛帮助很大。还有一个容易被忽略的处理目标尺寸回归要做归一化。钢铁缺陷的宽高比分布极其极端从 1:1 到 1:50 都有。如果不对宽高做对数空间的建模回归目标会被少数巨大目标主导。我把宽高的回归放在对数空间里做同时给极小目标的宽高加了一个最小值约束防止训练早期框宽收缩到 0 导致数值问题。3.3 训练参数与调参记录参数这块我按实际跑过的配置说但你要理解为什么这么设直接抄数值意义不大因为硬件和分辨率不同。批次大小我定在 16输入分辨率 640这样一张卡24G 显存刚好可以开混合精度训练显存占用在 80% 上下。我试过开到 32学习率线性放大之后收敛更陡但小批次那种“噪声带来的正则效果”反而更好验证集更稳所以我留在了 16。学习率用分段加余弦退火的组合。初始值 0.01前 3 个 epoch 做线性预热——这一步很重要钢材图像输入分辨率高、浅层特征响应剧烈不预热的话前几百步很容易把 BN 统计量带偏后面一路都拉不回来。预热之后进入余弦退火最小学习率设到初始值的 1%。训练轮数我先跑 300 轮看曲线实际收敛点大概在 220 到 260 之间。早停我设的是验证集上主要指标的滑动均值 15 轮不涨就停不要用单轮最优点噪声太大。参数取值设定理由输入分辨率640 训练 / 1024 推理训练省显存推理补细节批次大小16显存与正则效果的折中初始学习率0.01配合预热与余弦退火预热轮数3稳定浅层 BN 统计量训练总轮数300实际约 240 早停按验证曲线确定权重衰减5e-4抑制过拟合正负采样比1:3缓解极端不均衡聚焦系数1.5聚焦难样本避免震荡训练过程中我盯的指标不止一个是 mAP。我加了两个自建指标按尺寸分层的召回小、中、大分开看和关键类别的单类漏检率裂纹这类必须单独看因为它在总样本里占比小容易被平均值掩盖。裂纹的单类漏检率如果超过某个阈值这次训练成果我是不认的哪怕总体指标再漂亮。3.4 轻量化的边界在哪部署前总有人问能不能再小一点。我的判断标准是先把耗时预算算清楚再决定压到什么程度而不是盲目追求小模型。真实的教训是这样。我一开始做了一版特别轻的模型延迟只有 6 毫秒特别得意。结果集成到现场一张全分辨率大图要切成几十个切片全跑一遍总耗时接近 400 毫秒根本满足不了产线节拍要求。这时候才发现瓶颈不在单次推理而在切片数量。后来我改成了两阶段策略先用下采样图做一遍快速粗检分辨率降到原来的一半切片数减少四分之三只在粗检报出疑似区域的切片上做全分辨率精检。整体耗时降到一百多毫秒精度几乎没掉因为绝大多数切片本来就无缺陷没必要精检。这个思路我强烈建议所有做大画幅工业检测的人思考它比换更小的模型有用得多。4. 成像与产线集成的工程细节4.1 相机与光源参数怎么算这一段很多人写方案时会跳过但它直接决定了后面所有指标的天花板。我把我的算法过程摊开讲。先定像素精度。设最小需要稳定检出的缺陷特征宽度为 1 mm经验上要求这个特征在图像上至少跨越 8 到 10 个像素才能保证检测网络有稳定的响应。取 10 像素则像素精度 1 mm / 10 0.1 mm/pixel。再定横向分辨率。设视场宽度为 1.0 m则需要的横向像素数 1000 mm / 0.1 mm 10000 像素。市面上单台线阵相机常见的横向像素在 4K 到 16K 之间选 8K 的话需要两台拼接覆盖拼接处要做标定对齐和重叠裁剪。接着算行频。产线速度取 60 m/min 1 m/s像素精度 0.1 mm则行频 1 m/s / 0.0001 m 10000 行/秒也就是 10 kHz。这个行频在主流线阵相机的能力范围内但要注意此时单帧的数据量如果每帧取 2048 行单帧就是 10000×2048 像素约两千万像素需要 16 位深度的话就是 40 MB 一帧。存储和传输都要提前规划。像素精度 最小缺陷特征宽度 / 最小像素跨度 1.0 mm / 10 px 0.1 mm/px 横向像素数 视场宽度 / 像素精度 1000 mm / 0.1 mm/px 10000 px 行频 产线速度 / 像素精度 1 m/s / 0.0001 m/px 10000 Hz 单帧数据量 10000 × 2048 × 2 Byte ≈ 40 MB光源方案上我踩过的坑主要在两个地方。一是明场和暗场的取舍。明场照明下划痕类缺陷因为改变了反射方向往往表现为暗线对比度很好但麻点这类凹陷在明场下几乎看不出来。暗场照明确实能把凹陷和边缘凸起照得非常明显但对平面色差类缺陷又不敏感。我最终的方案是同工位两套光源交替频闪采集得到明场图和暗场图两路输入在特征层做融合而不是简单地拼通道。代价是硬件成本翻倍收益是麻点类的检出率提升非常显著。二是反光控制。钢板表面本身就是镜面光源角度稍微不对就会在图像上打出一片白。我用的是漫射穹顶加偏振片组合把镜面反射压下去。这里有个细节偏振片的方向必须和光源匹配装反了等于没装我第一次装的时候就犯了这个错排查了半天。4.2 推理加速与现场部署推理加速这块我按优先级排了个序实际做下来收益最大的排在最前。第一是图级优化。把模型导出成标准的中间表示后做算子融合、常量折叠这一轮通常是零精度损失的耗时能降两三成。第二是半精度推理。显卡支持的情况下直接开速度提升明显。有个坑要注意半精度下极小的数值容易出现溢出尤其你的回归头里如果有除法或者指数运算建议在关键位置强制回到单精度计算或者对这些环节做数值保护。第三是批处理与流水线重叠。切片推理天然可以并行把切片凑成批次送进去比逐张推效率高得多。同时把图像预处理缩放、归一化放到独立线程里和推理重叠执行能再省一截。第四是量化。整数量化收益很大但精度风险也大。我的做法是只用一部分真实产线数据做校准校准集要覆盖各种光照条件和各类缺陷不能只用验证集。校准完之后一定要在完整的验证集上重测一遍尤其盯住小目标召回量化对小数精度敏感小目标的回归损失最容易崩。工程上还有几件不那么“算法”、但更影响落地的事。报警联动要设防抖。单帧误检就触发切除产线会被误动作搞崩。我的做法是要求同一个物理位置在连续 N 帧里被判定为缺陷或者缺陷面积超过阈值才触发动作同时保留人工复检窗口。NG 图片要落盘但要有策略。全存很快就把磁盘塞满。我存的是裁剪后的缺陷区域加周边余量连同上下文信息和模型版本号一起落库方便后面回捞做增量训练。模型更新要灰度。新模型先只跑影子模式输出结果不参与控制只和现役模型对比差异样本人工确认后再切。这个流程建立起来之后迭代节奏会稳很多。5. 常见问题与排查实录5.1 问题速查表下面这张表是我这一年多里频繁翻出来的东西大部分问题都能在里面找到对应方向。现象首要怀疑排查动作处理办法训练集指标很高现场大幅掉点数据分布覆盖不足对比训练集与现场图的光照、色温、速度分布补充现场数据加入光照模拟增强某一类召回始终偏低样本量或标注规范问题单独统计该类样本数、框尺寸分布补齐样本分段标注细长目标小目标大量漏检特征被稀释可视化浅层与深层响应提高推理分辨率浅层加权重误检集中在周期条纹位置产线本身纹理被当特征检查误检框是否等间距重复裁剪时避开固定位置或在后处理中过滤训练损失震荡不收敛学习率或批次问题观察前 500 步损失曲线加预热降低初始学习率验证集分数虚高训练验证数据泄漏检查同卷相邻帧是否重复相似度去重后重新划分量化后精度明显下降校准集不具代表性分类型、分光照重测扩充校准集关键层保精度推理延迟不稳定切片数波动或资源争抢记录每帧耗时与切片数量两阶段策略预处理与推理并行5.2 几条不方便写进文档的经验说几条我真正吃过亏才明白的事。不要相信第一次划分的数据集。我最初随机划分训练验证集指标漂亮得不像话。后来发现同一卷钢带上的相邻帧被分到了两边等于拿训练数据的近亲去测试。改成按卷、按批次划分之后指标掉了近二十个点但那个才是真的。划分单元一定要选“产线物理上独立的单元”卷、批次、班次都可以唯独不能是单张图。类别不平衡不要在采样层面硬怼。我试过对稀缺类做过采样重复采样到和其他类一样多结果是模型对这几类过拟合现场稍微变个样子就崩。更稳的做法是在损失层面做加权同时适度提高这几类的采样概率不超过三倍并且给这几类单独留一份困难样本集做验证。验证集里必须有一份“脏数据”。干净的验证集只会给你虚假的安全感。我专门留了一份从现场抓的、有水渍、有反光、有轻微失焦的验证子集每次迭代都在这份数据上单独看指标。这份数据上的表现才更接近现场。离线指标和现场表现之间有个换算系数。我实测下来在充分去重的验证集上 mAP 达到某个水平后现场首月的实际检出率大约要打八折到八五折。这个折损来自数据分布差、成像差异、阈值设定。所以在做验收标准的时候我会把目标定得比工艺要求高一截留出这个折损余量。别忽略负样本的质量。所有人都盯着缺陷样本其实无缺陷样本如果全是“干净得不像话”的图模型就会把任何一点纹理波动都判成异常。我特意混入了大量“工艺正常但外观有轻微色差、有轻微辊纹”的负样本让模型学会区分“正常的不完美”和“真正的缺陷”。这一步做完误检率下降得非常明显。阈值不是拍脑袋定的是按代价算的。漏检一条贯穿裂纹和误报一个麻点代价完全不同。我的做法是把现场的业务代价折算成权重在验证集上扫描阈值找到一个总代价最低的点而不是简单取 0.5。这个点往往不是 0.5而且不同类别应该用不同阈值。6. 我对这套方案后续扩展的几个想法如果这套东西还要往前走我个人认为优先级最高的不是换更强的模型而是把数据闭环搭起来。现场每次人工复检的结果、每次误检和漏检的图都要能自动带着上下文回流到训练池里。工业场景的数据分布是会漂移的——换了供应商、换了轧辊、换了季节成像和缺陷形态都会变。没有闭环的系统上线三个月就开始慢慢退化。其次是多模态融合。现在只用了可见光其实产线上还有测厚、测宽、温度这些信号如果能和视觉结果做交叉验证很多疑难样本的判定会稳得多。比如某块区域同时出现了温度异常和视觉异常那这条告警的可信度就完全不同了。最后是缺陷尺寸的精确量化。检测框只能给个大概但工艺侧真正关心的是“这条裂纹到底多长、深度大概多少”。这一块需要和实际的测量手段结合做标定把像素尺寸换算成物理尺寸并且要处理透视和板面弯曲带来的误差工作量不小但价值很大。我在实际推进这个项目的过程里最深的体会是模型只占整件事的三成剩下七成是成像、数据和流程。那些在论文里看起来很关键的结构改进落到现场往往不如把光源角度调对一度来得实在。所以如果你刚开始做这件事我的建议是先花时间去现场看两百张真实的图再决定你的第一个网络长什么样。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑