工业缺陷检测这个方向,做过的朋友都知道,最折磨人的往往不是模型选型,而是你坐在电脑前,对着甲方发来的一个压缩包,里面躺着一百多张图片,其中带缺陷的只有四十几张,还要检测七八种不同类型的瑕疵。训练集比验证集还小,分类任务里有的类别就三五张图,这种项目如果直接套用常规的深度学习训练流程,结果基本可以预料:训练集上loss根本降不下去,验证集上指标忽高忽低,到了现场一跑,漏检率直接让产线负责人脸色发青。
这几年我陆续做了几个类似的案子,从3C屏幕划痕到金属件表面缺陷,从纺织物瑕疵到电池极片露箔,总结下来,小样本条件下的工业缺陷检测,真正要解决的不是某一个模型多聪明,而是整套流程里怎么把有限的数据用出最大价值,同时在"漏检"这个红线上做好兜底。这篇文章就把这套完整流程拆开来讲,包括我在实际项目里踩过的坑、反复调整过的方案,以及最终稳定落地的一套做法。
1. 为什么小样本在工业缺陷场景里是常态而不是意外
很多从公开数据集入门的朋友,对缺陷检测的第一印象是数据量大、标注充分,像是工业检测领域常用的公开数据集,一个类别动辄几千张图。但真实产线根本不是这么回事。我之前接过一个连接器端子外观检测的项目,甲方给的初始样本是两百多张良品图和三十几张不良品图,不良品里又分了毛刺、压伤、镀层不均、偏移四类,最多的类别十几张,最少的类别只有六张。
这种情况不是个例,而是工业缺陷数据的基本盘。
1.1 工业场景下缺陷样本天然稀少的三个原因
第一个原因是缺陷本身就是低概率事件。正常产线的缺陷率控制在百分之一以内,甚至千分级,这意味着要收集几千张真实缺陷图,你得连续盯产线跑很久,而且中间还伴随着产品型号切换、工艺参数调整,收集到的样本分布还未必稳定。
第二个原因是缺陷类型高度碎片化。同样是划痕,不同深度、不同方向、不同光源角度下呈现的形态差异很大;同样是气泡,直径从0.1毫米到2毫米都有。每一类缺陷的样本内部差异大,但类间样本数量却很少,这让模型很难学到稳定的类内共性。
第三个原因是标注成本被严重低估。工业缺陷的标注不是画个框就完了,很多缺陷需要像素级分割标注才能支撑后续的检测精度,比如锂电池极片上的露箔区域、织物上的断经纬,边界模糊、对比度低,一个有经验的标注员一天能精标两百张已经算快了,而一个项目动辄需要几千张,时间和人力成本大部分项目扛不住。
1.2 小样本情境下传统训练流程为什么必然翻车
直接用常规流程训练目标检测网络,在小样本下会面临三个连环问题。首先是数据增强的边际效应递减——旋转、翻转、裁剪这些基础增强确实能增加样本量,但工业缺陷对几何变换的容忍度有限,比如一个特定方向的划痕翻转之后在真实产品上可能根本不存在,模型学到了一个物理上不成立的模式。其次是类别不平衡被放大,少数类的损失在总损失里占比太低,网络倾向于把所有目标都预测成多数类,表现在结果上就是某个缺陷类型的召回率极低。第三是验证集本身就不靠谱,三十几张测试图里有一两张误检,指标波动就能达到三到五个点,你很难判断模型是真的变好了还是碰运气。
所以,小样本工业缺陷检测的第一步,不是急着调模型,而是先想清楚:我们能不能通过改变问题定义方式,让这个小样本问题本身变得更"大"、更"好"。
2. 把问题重新定义:从目标检测到语义分割的降维打击
我在几个项目里做过的效果最显著的一个调整,是把问题定义从目标检测切换为语义分割,配合经典图像处理算法做前置筛选。这个思路听起来反直觉——分割不是比检测更复杂吗?但在某些特定缺陷场景下,分割反而更简单。
2.1 为什么切换任务定义能缓解样本压力
以金属表面的压伤缺陷为例。一个压伤区域和周围正常表面在纹理、反光特性上有明显差异。如果做目标检测,你需要告诉模型"哪里是一个完整的缺陷目标",模型需要学习的是缺陷的完整边界和形状语义,这在样本少时很难学准。但如果你换成语义分割,模型只需要逐像素判断"这个像素是不是缺陷",这是一个二分类问题,特征判别空间比完整目标检测小得多。
更关键的是,二分类语义分割可以利用大量的良品图参与训练——甚至可以说,良品图就是一种天然的负样本。在很多项目里良品图是不缺的,产线随便一拍就是几千张,而且不需要标注。我们只需要用无监督方式让模型学习正常样本的分布特征,然后检测异常偏离。我之前的连接器端子项目,最终稳定运行的主模型就是这条路线:用两百多张良品图训练一个重建模型,缺陷区域因为偏离良品分布而被高亮标出,效果出奇地稳定。
2.2 工业场景里两种主流的小样本技术路线对比
实战中我能拿出手推荐的技术路线主要有两条,它们的适用场景、成本和效果差异很大,我建议根据实际缺陷特征来选择,而不是一味追新。
| 对比维度 | 经典图像处理+统计特征 | 深度学习(分割/重建) |
|---|---|---|
| 样本需求 | 无需缺陷样本,只需良品基线 | 数十张缺陷图即可启动 |
| 可解释性 | 高,每个检测规则可追溯 | 低,需要额外的可视化与分析手段 |
| 环境适配性 | 对光照、角度变化敏感,需要严格固定环境 | 通过数据增强和归一化,具有一定泛化能力 |
| 缺陷多样性 | 只能检出"已知形态"的缺陷 | 可学习"偏离正常"的抽象特征 |
| 落地维护成本 | 规则调整简单,现场可改 | 需要模型迭代,现场改规则依赖工程团队 |
在连接器端子的项目里,我最开始用纯传统算法做了一套压伤检测——基于局部灰度方差和梯度方向的统计规则,准确率还行,但换了料号之后规则就要重新标定,非常痛苦。后来改成深度学习重建方案,一个模型扛住了三个料号,泛化性完全不一样。
2.3 一个容易捡漏的中间方案:经典算法做候选区挖掘
深度模型在小样本下还有一个容易被忽视的痛点——正负样本极度不平衡导致初始训练不稳定。一个非常实用的土办法是:先用经典图像处理算法在每张图上挖出候选缺陷区域,然后只对这些区域做分类或分割训练。这样做有三个好处:一是大幅减少了背景干扰,模型学的每一块区域都是"有可能出问题"的区域;二是可以将逐像素分类问题退化为区域块分类问题,对标注精度的要求降低了;三是数据量虽然没变,但每个样本的有效信息密度提高了,模型收敛速度快了不止一个量级。
3. 小样本训练全流程实操:从数据策略到模型收敛
说完了思路,下面进入硬核实操环节。我直接以一个小样本钢材质表面划痕检测项目为例(样本情况:30张划痕图,200张良品图),完整串一遍数据准备、训练配置和收敛调优,所有参数都是实际跑过的,可直接参考。
3.1 缺陷样本增强的伪命题:先保真,再数量
很多人拿到30张划痕图,第一反应是疯狂做数据增强。但我必须泼一盆冷水——数据增强不是越多越好,尤其是工业缺陷。划痕方向和材质纹理之间存在物理相关性,比如钢材在轧制方向的划痕才是真实缺陷,垂直方向的划痕在实际产线上根本不会出现,模型学了就等于学了错误先验。
我实际用的增强策略分两层。第一层是保真性增强,只用小角度旋转(±10°以内)、轻微缩放(0.9到1.1倍)、亮度扰动(±15%),因为这些变换不会破坏缺陷的物理结构。第二层是多样性增强,通过人工合成新缺陷样本来补充数量——比如对已有的划痕分割掩膜做局部扭曲、拼接、融合到良品图上。这里分享一个个人比较推荐的经验比例:真实缺陷图和合成增强图的比例控制在3比7以下比较合适,合成图的物理保真度有限,如果占比过高,模型容易形成错误的纹理先验。打个比方,数据增强就像给模型喂"仿真食材",你可以用合成材料来填饱肚子,但如果全是仿真的,模型就会把"仿真味"当成"食材本味",上了真实产线一碰到真实光线就露馅。
3.2 模型选型与骨干网络初始化策略
小样本场景下,模型选型的核心原则是"容量适中、初始化可靠、收敛快速"。以分割网络为例,Unet这类结构在小样本下比DeepLabV3+这类大容量模型更稳,因为参数少,不容易在小数据上快速过拟合。
这里还涉及一个很多新手容易忽视的细节——backbone的初始化方式。如果直接用随机初始化,几十张样本根本撑不住骨干网络的收敛;用ImageNet预训练权重初始化,又面临工业图像和自然图像领域差异大的问题。我的做法是分两段走:先用无监督对比学习在项目自己的良品图像上做一次自监督预训练,让骨干网络先学会"看清楚钢材表面长什么样",再加载到分割模型里,用标注数据做有监督微调。这一步在白话里就是:让模型先在没有标签的数据里"看熟"自己将要工作的环境,再从几十张带标签的图里学"什么样的变化算缺陷"。经过自监督预训练的模型,比直接用ImageNet权重初始化的模型,在少样本下的收敛速度和最终精度都有明显优势,实践下来mIoU能提升三到五个百分点左右。
3.3 损失函数组合与收敛判定的实操配方
小样本分割训练中,单一损失函数经常出问题:
- 样本里前景像素可能只占全图的1%(甚至不到),直接用交叉熵,模型会学成"全图都预测为背景",因为这样损失就已经非常小了。
- Focal Loss能缓解类别不平衡,但和Dice Loss配合使用时,训练初期的梯度波动会比较大。
我最终稳定下来的方案是:主损失用Focal Loss(gamma=2.0,alpha=0.75),辅助损失用Dice Loss(权重系数0.3到0.5),两个损失相加作为总优化目标。这样Focal Loss负责对困难像素进行聚焦训练,让模型优先学习那些"像缺陷又不太像缺陷"的像素;Dice Loss则直接优化目标区域的重叠度,相当于让模型从全局结构上去逼近真实缺陷的轮廓。训练策略跟着配套调整:batch size设置到最大(我用4到8),学习率初始1e-3,搭配余弦退火调度。尤其要强调的是,不要在半途轻易降低学习率突然微调,小样本模型的训练曲线本身就抖,频繁调学习率容易让模型陷入局部振荡。
另外还有一个判断模型是否收敛的独特经验:在验证集上不能只看mIoU,还需要额外看"小目标召回率"这个指标。很多模型mIoU看着还行,但细小的缺陷(比如小于20像素的划痕区域)全漏了,因为它们在损失里占的比重太小。建议在训练过程中单独统计这一类指标的曲线,如果连续二十个epoch没有提升,那就该考虑调整损失权重或引入辅助分割头了。
3.4 常用的两个"作弊级"样本补充技巧
除了模型和数据增强,这里聊两个实操中效果非常大的样本补充技巧,虽然上不了台面,但确实解决问题。
第一个是"背景抠图融合"。取一批真实的良品图,将缺陷掩膜区域从原始缺陷图里精细地提取出来,然后以随机位置、随机角度、随机光照扰动的方式融合到这些良品图上。这就相当于在物理规律允许的范围内,让缺陷样本的多样性呈几何级增长。我当时给钢材划痕项目做了五百多张合成样本,配合30张真实样本一起训练,模型在真实划痕上的召回率直接翻了一倍。需要注意的细节是:融合时缺陷区域要加羽化边,且颜色和阴影过渡要尽量自然,不然模型学会的判别特征是"这有一块边界生硬的区域",而不是"划伤纹理本身",现场一换光照就失效。
第二个是"切图扩样"。很多工业相机拍出来的图像分辨率非常高,比如一张500万像素的图里,缺陷只占据中间一小块。直接把整图resize到模型输入尺寸(一般是512x512或640x640),缺陷会被缩得很小,本质上是人为增加了检测难度。正确做法是:用滑动窗口把大图切割成多张512x512的小图,每个小图独立参与训练,缺陷分布在不同的子图里。这样做既增加了有效样本数量,又保留了缺陷在原始尺度下的特征细节。实践下来,切图带来的收益经常比复杂的网络结构改动更明显。
4. 漏检控制的闭环:阈值、级联、回归测试与现场迭代
小样本模型练得再怎么好,也不可能达到100%召回。在工业现场,"漏检"不只是指标不好看,而是实打实的客诉和损失。所以控制漏检必须上升为整个系统的核心设计目标。这一章我分享一下怎么从流程机制上把漏检率压到最低。
4.1 置信度阈值不是拍脑袋定的:从代价矩阵反推
很多团队定阈值时,习惯把置信度设到0.5或者0.8,觉得"分数高才判定为缺陷更安全"。但从实际业务视角看,这是混淆了"误杀"和"漏检"的代价关系,而且是完全相反的。
在缺陷检测场景,漏掉一件缺陷品的代价非常高(客户投诉、批次召回、退货),而把良品误判为缺陷的代价相对低一些。因此系统的检测阈值,应该根据漏检代价和误杀代价的相对高低来调节。我习惯用代价矩阵的思路来推阈值:
设M为漏检一件缺陷品的损失(包括客诉、返工成本),O为误杀一件良品导致的损耗(包括补货成本、停线检查成本)。如果M远大于O,那么阈值应该向下调,宁可多一些误检,也尽量不让缺陷漏过。极端情况下,比如医疗器械检测、航空航天部件检测,阈值甚至可以调到0.1乃至更低——这样带来的高误检率通过后续人工复检来消化,这是工业现场常用的"先抓取、再确认"思路。
我建议做决策曲线分析来定阈值:把模型在验证集上的置信度从低到高扫描一遍,画出一条"漏检率-误杀率"的变化曲线,然后结合产线对两种代价的承受能力,选择曲线上的最优点。有次我做PCB板缺件检测,最初把阈值定在0.85,跑到产线上连续三天都出现漏检。后来我把阈值降到0.55,误杀率从0.3%涨到1.2%,但漏检率直接降到了零,配合端头工位的复检流程顺畅跑了下来。这个案例里,轻视代价平衡而执着于高阈值,是很多算法工程师在现场容易犯的错位。
4.2 级联模型结构:用轻量初筛保证不漏,用精修模型控制误杀
工业缺陷检测还有一个常见矛盾:要保证低漏检,单模型的召回策略就得放得很宽,结果误检也直线飙升。解决这个矛盾我非常推荐用级联结构,这是我在多个项目里验证过的、经济效益最明显的系统框架。
第一级是粗筛模型,目标只有一个:把可疑区域全部捞出来,宁可错杀一千,不可放过一个。这个模型不追求像素级精确,只需要输出候选框或候选区域,所以可以用分辨率较低、速度快的模型,对光照变化不敏感、对小目标召回率高的模型来承担。这一步的目的是保证召回率没有被任何信息损失掉。
第二级是精修模型,对第一级输出的所有候选区域再进行精细分类/分割,目标是剔除误检、精确定位缺陷。因为第二级只看小块候选区域,输入分辨率可以放大,分类信息更充足,精度可以做得比较高。
我碰到过一个铸件气孔检测案例,第一级用了一个经典的局部阈值分割算法(配合形状规则过滤),虽然会挨个把气泡痕、脏污等当成潜在的"气孔"挖出来,但确实没有任何漏检;第二级用一个小型卷积分类器,对第一级给的候选块做"是否真实气孔"的二分类,最后整体误检率压在0.05%以内,且缺陷召回率达到99.7%。这套方案不需要在同一个模型里同时兼顾高召回和低误杀,任务解耦后两边各自都能发挥上限。
4.3 回归测试集是漏检控制的最后防线
控漏检还有一件非常重要的工程化的事情,就是建立回归测试集。注意,这个回归测试集必须和验证集分开,专门用于上线前后做系统性回归检查。
回归测试集的建立标准:
- 覆盖产线跑过的所有缺陷类型,包括历史漏检样本、实际产线上出现过的疑难缺陷。
- 包含不同光照条件、不同来料批次、不同机台震动状态下的图像,因为工业现场的成像环境经常变化。
- 持续补充:每出现一次新的漏检,立刻把该样本加入回归测试集,确认修复后重新跑一遍完整回归。
我习惯每次上线前跑一遍回归测试,输出的指标不只看整体mIoU,还要逐类看召回率。尤其在模型更新、参数调整之后,哪怕其它类别指标涨了,某一类缺陷的召回率掉了一个百分点,我都不会让这个版本上线。有没有想过,一个看似无害的模型改进,可能会悄悄牺牲掉某一类罕见缺陷的召回率?在实际产线上,这类罕见缺陷反而往往是最致命的风险点。
4.4 现场漏检样本的闭环迭代机制
最后是一个必须在流程上落实的机制:从现场持续收集漏检样本,回到训练集做增量迭代。
车间里的情况总是和离线数据集有差异——新物料批次、新工艺、新光源角度,都会产生模型没见过的缺陷形态。很多团队把模型部署上线之后就当完成了,然后过了两三周接到产线反馈说"最近漏检变多了",才重新回来救火。正确做法是针对每次漏检做根因分析,是模型判断失误,还是本来就不在检测定义范围内?是成像条件变了,还是缺陷形态是新的?根据根因定向补充训练数据或调整流程,然后回归测试、重新上线。
在这个环节里,一个更聪明的做法是设计一个"漏检挖掘"的在线策略:在产线上定期跑一个独立的、低阈值的高召回模型,把所有可疑目标都标出来让人工复检,其中被确认为缺陷但被主模型漏掉的样本,全部回流到训练集。我最近的电池模组焊缝检测项目就用上了这个策略,上线一个月后,通过持续回流迭代,主模型在原有缺陷类型上的召回率提升了将近两个百分点,还顺带学会了识别两种新形态的焊缝气孔——这个成长速度,靠纯离线开发是不可想象的。
5. 验收指标的设计陷阱:别让离线指标欺骗了你
小样本工业缺陷检测项目,还有一个特别容易翻车的环节——验收。经常出现的情况是:离线测试集上Recall、Precision都很好,模型一到现场就拉胯。这背后的原因值得专门立一个章节来讲。
5.1 离线测试集和现场真实分布之间的三大鸿沟
第一大鸿沟是背景分布漂移。离线测试图是白天拍的,现场是夜班灯光下;离线测试的产品来料批次是A供应商,现场已经切到B供应商。这些变化对图像分布影响极大,尤其在小样本下,训练集覆盖不了真实的背景多样性。
第二大鸿沟是缺陷形态分布不匹配。离线数据里常见的缺陷形态在真实产线上可能只占50%,剩下50%都是模型没见过的变体。小样本训练出来的模型,对"见过形态"能识别,对"形态偏移"往往彻底失效。
第三大鸿沟是置信度校准失效。小样本模型的置信度输出往往不可靠,模型可能对某个真实缺陷给出了0.4的低置信度——但从业务角度看,它的特征已经完全符合缺陷定义了,低的置信度反映的是数据稀缺带来的不确定性,而不是"它不是缺陷"的证据。
5.2 一套我实际在用的验收指标体系
基于这些教训,我建议在验收项目时使用下面这套指标体系,而不是只盯着mIoU和Precision/Recall:
| 指标维度 | 具体指标 | 验收目标 |
|---|---|---|
| 缺陷召回率 | 分类型召回率(每类都要看) | 每一类都不低于业务要求的阈值 |
| 小目标召回率 | 像素数小于50的缺陷召回率 | 单独统计,目标不低于大目标召回率的90% |
| 误杀稳定性 | 每千件产品误杀数 | 低于产线容忍上限 |
| 跨批次稳定性 | 不同来料批次分别统计指标 | 各批次间指标波动不超过20% |
| 置信度分布 | 真实缺陷的置信度分布直方图 | 不应出现"大批真实缺陷集中在阈值附近"的情况 |
这套指标的核心逻辑是:验收不能只看平均成绩,必须看极端情况和分布情况,因为小样本模型的短板恰恰体现在"低资源类别"和"边界案例"上。平均分再漂亮,都掩盖不了某一类缺陷的召回率只有五成的问题。
5.3 一个关于"置信度分布"的独门观察技巧
这里分享一个比较独门的观察技巧。模型训练完成后,把验证集里所有真实缺陷的置信度做成一张直方图,如果大量真实缺陷的置信度集中在0.3到0.6之间,说明模型对缺陷判定其实很犹豫,哪怕当前阈值恰好能筛掉它们,只要环境稍有变化,这些样本就会大量静默进入漏检区间。这种情况就需要谨慎上线。
反过来,如果真实缺陷的置信度大多集中在0.9以上,和误检样本(通常在0.2以下)之间有明显的间隔带,说明模型学到的特征区分度好,此时哪怕小样本,部署底气也会足很多。我会根据这个分布特点决定是否要让模型上线,以及是否需要调整数据策略,这比单纯看分数靠谱太多了。
6. 其他实战经验杂谈:从数据标注到现场部署的提醒
最后再聊一些散装经验。虽然题目叫全流程,但很多细节没办法展开,这部分就当是补充贴士,都是我真实碰过的。
数据标注阶段,尽量不要直接画矩形框。生产环境中建议用分割掩膜标注,多花一点时间,但在小样本训练里,掩膜标注带来的信息量远大于矩形框。在合成样本阶段,如果标注了分割掩膜,做背景融合、切图、畸变增强都会灵活很多。如果一个项目已经画完了矩形框但没掩膜,也可以用分割一切这种通用模型辅助生成掩膜,再由人工校对——这招我用到过不少项目里,效率提升明显,但注意要人工检查小缺陷区域,这类通用模型对细微缺陷经常丢细节。
训练阶段,class weight不要按样本数量反比来设置,这样对极少数类会设置过高的权重,容易导致过拟合。推荐的做法是把权重上限设在一个范围内,比如1到5之间,宁可让少数类欠拟合也不让它过拟合。
部署阶段,记得在推理前端做一个图像质量预检——现场经常会有镜头脏污、光线突变、传输抖动的情况,一张模糊图进模型,输出结果本身就是噪音。加上一个简单的清晰度和亮度判别模块,把质量不合格的图直接拦下来报警,可以让整个系统的稳定性上一个档次。
还有一个容易被忽略的工程点:模型更新机制。小样本项目不可能做一次就一劳永逸,所以部署架构上务必设计好版本管理和灰度发布。我习惯的做法是保留旧版本模型做AB对比,新版本先在一条产线跑一周,用前面说的回归测试集比对两版的差异,确认新版有明确优势后才全量切过去。有些团队图省事直接热更模型,出了问题想回滚都找不到老权重,现场会很被动。
最后说一个认知上的调整。小样本工业缺陷检测没有那种"一套方案搞遍所有项目"的银弹,最好的状态是:对经典图像处理和深度学习的边界有清晰认知,对不同任务重新定义问题的能力足够灵活,并且始终守住"系统级防漏检"的底线。做到这三点,即便手头只有几十张缺陷图,也能做出让产线真正信任的检测系统。