搞工业缺陷检测这几年,我最大的感受是:算法层面很少把人逼到死角,真正让人头疼的永远是小样本和漏检这两个问题。你手里可能只有几十张缺陷图,模型倒是能跑通,可一上产线就原形毕露——漏检压不下去,阈值稍微调严一点,误报又铺天盖地,现场工人直接把你辛辛苦苦部署的系统当摆设。这篇文章我就把最近做的工业缺陷检测项目完整复盘一遍,重点讲小样本训练和漏检控制的全流程思路,包括数据怎么处理、模型怎么选、阈值怎么定、产线反馈怎么闭环。内容偏实战,适合正在做机器视觉项目的算法工程师、自动化工程师,也适合那些被“样本量不够”和“漏检率下不来”反复折磨的同行。
1. 缺陷检测先想清楚模型选型与数据底线
1.1 别急着选模型,先搞清楚你的缺陷长什么样
很多项目一开始就纠结用YOLOv8还是用分割模型,其实这个问题应该放到后面。第一步要做的是把产品缺陷的种类和形态吃透。同样是金属表面缺陷,划痕和凹坑在图像上的表现完全不同:划痕是长条形、方向性强,凹坑则是小面积、低对比度的区域。缺陷的形态直接决定了模型的检测难度,也就决定了你该走检测框路线还是分割路线。
我的经验是分三种情况来看:
- 缺陷是明显的独立目标,比如缺件、脏污、明显裂纹,用标准的目标检测模型(YOLO系列、RT-DETR)就够了,标注速度快,训练也稳定。
- 缺陷边界模糊、形状不固定,比如表面纹理异常、细微划痕、压伤,检测框很难框准,这时候用分割模型(比如U-Net或DeepLabV3+)反而更合适,因为分割模型能输出像素级区域,对边界不规则的缺陷更友好。
- 缺陷类别多且样本奇缺,正常样本倒是管够,那就别死磕检测模型了,先考虑无监督异常检测路线,利用大量正常样本建立“正常”的分布,偏离分布的区域就是异常。
这里有个很关键的判断:你的项目到底是“找已知缺陷”还是“发现未知异常”。如果是外贸订单要求“表面不得有任何异常”,这类需求本质上是异常检测,你根本不可能把所有缺陷种类都提前列全。用有监督检测模型硬做,样本永远不够,而且新缺陷一出现就漏检。遇到这种需求,优先级最高的方案是重建类模型或特征嵌入类模型,用正常样本建模,让模型自己发现异常。
1.2 “小样本”到底有多小,数据底线怎么定
小样本训练面临的第一个现实问题是:多少样本才算“小”?这个数值没有标准答案,但我基于多个项目经验总结了下面这张底线参照表:
| 场景 | 每类缺陷样本数 | 建议路线 |
|---|---|---|
| 每类少于10张 | 极小型 | 优先无监督异常检测+规则复核,暂缓训练检测模型 |
| 每类10~50张 | 小型 | 迁移学习+强数据增强,检测头用小模型,主干预训练 |
| 每类50~200张 | 中小型 | 常规检测模型,分层学习率微调,配合半监督扩充 |
| 每类200张以上 | 正常偏小 | 标准训练流程,数据增强重点防过拟合 |
我见过最极端的一个项目,某五金件的外观检测,其中“磕碰伤”这类缺陷一共只有7张样本。这种量级你指望训练一个YOLO模型去稳定检出,基本是做梦。后来方案改成了先用无监督异常检测把可疑区域圈出来,再针对可疑区域做纯规则的灰度梯度复核,反而是这个项目里表现最稳定的模块。
所以我的建议是:项目启动前,先统计每一个缺陷类别的样本数量。如果大量类别低于30张,你就要认真评估是否具备直接训练检测模型的条件。数据底线不是拍脑袋拍出来的,它决定了你后续所有技术路线的走向。
2. 小样本训练:不是堆数据,而是“榨”数据
2.1 数据增强的工程级实践
很多同行一提到小样本就想到数据增强,这个方向没错,但做法经常跑偏。工业缺陷检测里的数据增强,核心原则是模拟真实拍摄条件的变化,而不是无中生有。翻转、90度旋转、随机亮度、轻微噪声这些基础增强可以放心用,但对于依赖方向性的缺陷要格外小心。例如塑胶件的“拉伤”缺陷具有明确的方向性,你随便做了个垂直翻转,缺陷形态就被改造成了现实中根本不存在的样子,模型自然会被带偏。
我自己在项目里常用的增强组合是这样一套流程:
- 先做几何增强:水平翻转、垂直翻转(前提是产品本身没有方向要求)、小角度旋转(±5度以内)。
- 再做光度增强:亮度扰动、对比度扰动、轻微高斯噪声模拟不同曝光条件。
- 最后做局部遮挡或仿射变换,模拟零件位置偏移导致的形变。
色彩类增强我踩过坑。有一次做反光表面的划痕检测,原始缺陷的本质特征是高光区域内的灰度跳变,我加了随机颜色扰动之后,模型反而学到了“偏红色块”这种与真实缺陷毫无关系的伪特征,上线后误报暴涨。从那以后,色彩扰动我基本只在彩色产品检测里用,灰度场景一律关闭。
2.2 迁移学习:小样本场景下的主力武器
小样本训练最可靠的手段,我至今认为还是迁移学习。但迁移不是简单地把ResNet的权重拿来初始化,而是要有策略地控制哪些层参与训练、哪些层保持冻结。
常规做法分三步:
- 加载预训练主干权重(ImageNet预训练模型也好,自监督预训练模型也好),先用冻结主干的方式只训检测头,让模型快速收敛到一个可用的初始状态。
- 解冻主干最后两到三个block,使用较小的学习率(比如主干学习率设为检测头的十分之一)继续微调。
- 等loss平稳后,再全部解冻做最后几轮的精细调整。
这套做法的好处是:预训练主干已经学到了通用的纹理、边缘、形状特征,你的几十张样本只需要微调高层语义特征就够了,大大降低了过拟合风险。我在一个轴承端面缺陷项目里,每类缺陷只有40张左右,使用预训练模型之后测试集mAP达到了0.85左右,而不加载预训练从头训练,mAP直接掉到0.5上下,差距就是这么明显。
另外一个容易被忽视的细节是预训练数据本身和你的工业场景差异很大。ImageNet里的图像是自然图像,工业表面是均匀纹理或金属拉丝,语义域差距不小。如果条件允许,优先选择用工业场景的自监督预训练模型,或者用你们自己工厂的历史大量正常图片做一次自监督预训练(对比学习或掩码重建),效果会更好。
2.3 半监督和自监督辅助训练路线
小样本训练不等于所有数据都小。工厂里大量正常品的图片通常是几十万张管够的,这些数据不该浪费。两条辅助路线值得一试。
第一条是半监督学习。用少量缺陷样本先训练一个初版检测模型,然后用这个模型对无标注的大批次产线图片做伪标注,挑选置信度高的缺陷预测加入训练集,迭代几轮。这里有个前提:伪标签的质量控制很关键。我会设定一个比正常推理更高的置信度阈值(比如0.95),宁可漏选也不把噪声引入训练。另一招是只在候选区域的重叠度高、且形态符合该缺陷类型特征的情况下才采纳伪标签,逻辑上更安全。
第二条是自监督辅助训练,利用大量正常样本训练一个重建网络或对比学习编码器,然后再把编码器特征接到缺陷分类头上。正常样本多、缺陷样本少的情况下,这个自监督编码器能学到非常丰富的表面纹理特征,缺陷特征在这个表征空间里会显得更突出。实际效果上,我对比过同一批数据:直接用检测模型训练,漏检率在3%左右,加了自监督预训练编码器做辅助特征提取后,漏检率能压到1%以内。
2.4 合成数据:样本不够,造也要造出来
合成数据在小样本缺陷检测里是一把双刃剑。做得好了能大幅补足样本量,做得糙了不仅没帮助,还会让模型学到渲染器的“审美”。
合成数据最常见的有两种路线:三维渲染合成和二维图像拼接。三维渲染适合做复杂形貌的缺陷,比如铸造件的缩孔、砂眼,用建模软件模拟三维形貌加不同光照条件渲染出图片。这条路线技术门槛高、周期长,但效果最逼真。二维图像拼接就简单很多:把从不同产品上截取的缺陷纹理通过泊松融合等算法贴到正常产品图上。这个方案实现快,但要特别注意融合边界不能太明显,否则模型学会了检测“贴图的边界”,而不是缺陷本身。
关于合成数据,我的建议是:能用二维拼接解决就别上三维渲染,同时合成数据一定要和真实数据混合训练,并且最后以真实数据做验证集来评估。如果模型在合成数据占比过高的情况下训练,测试集表现会比较好,但一到实际产线就会走样,因为合成数据和真实拍摄的图像始终存在域差距。
3. 漏检率控制:产线安全的第一生命线
3.1 阈值设定不能全信模型输出
很多项目组上线时只做一件事:把置信度阈值设为0.5,然后结束。这种做法在学术benchmark上说得过去,在产线上是绝对不行的。模型输出的置信度分数和真实的缺陷概率并不是一回事,特别在小样本训练的模型上,置信度往往存在系统性偏差。我见过一个模型,对明显缺陷的置信度输出普遍偏高,对基层误检区域也给出0.7的高分,单靠阈值根本分不开。
实际操作中,我先会用验证集统计每个类别的置信度分布,画出缺陷样本的置信度直方图和误检样本的置信度直方图,找到两个分布的重叠区间。然后在重叠区间里,根据产线能接受的误检上限来选阈值。如果缺陷样本和误检样本的分数区间几乎完全重叠,那说明模型本身能力不足,调阈值解决不了问题,得回到模型层面去优化。
3.2 置信度校准与输出校准方法
如果模型存在系统性置信度偏差,一个很有效的补救手段是置信度校准。最简单的做法是温度缩放(Temperature Scaling),为模型学到一个温度参数T,把输出的logits除以T后再过softmax。T>1会让概率分布更平滑,T<1则更尖锐。我用验证集做了一次网格搜索,找到最优温度值后,模型对“低置信度缺陷”的区分能力有显著提升。
校准之外,我还会对模型输出做“软阈值+规则复核”的双层兜底。第一层用较低的阈值(比如0.3)先保住召回率,宁可多圈几个候选区域;第二层对这些候选区域提取形状、灰度、纹理等手工特征,再用简单的规则或一个小分类器做二次确认。这套“粗检+精查”的思路,比单模型硬调阈值要稳定得多,也是漏检控制里性价比最高的手段之一。
3.3 产线反馈与漏检复盘闭环
漏检控制真正做好的关键不在阈值,而在反馈闭环。我认为一个上线超过一个月的检测系统,如果运行逻辑里没有“漏检样本回流机制”,那它迟早会出问题。
具体操作也不复杂:在产线检测工站旁加一个“人工复检站”,所有被模型判为NG的产品和随机抽检的一部分OK产品都要过一遍人工复检。人工复检发现的漏检样本,系统自动留存图片并打上标签,每天晚上自动汇总成当天的漏检分析报告。这个报告会列出所有漏检图片的置信度分布、缺陷区域特征,周期性回到训练集里做增量更新。模型会越用越准,而不是越用越偏。
这个环节我吃过亏,早期一个项目没有做漏检样本回流,系统上线两周后,产线换了批次原料,新批次表面有一层轻微水渍,模型完全没有见过这种形态的干扰,漏检率从1%一路飙到8%,现场质量人员差点把设备砸了。后来加了回流机制,当天发现的漏检图片第二天就进入训练,三天后漏检率就回到了正常水平。
3.4 漏检评估:生产级指标怎么拆
漏检率这个词在产线上很模糊,不同人说的并不是同一件事。我做项目的习惯是先把指标拆清楚:
- 漏检率(FNR):缺陷样品中被模型判为OK的比例。
- 误检率:正常品中被模型判为NG的比例。
- 复检率:被模型判为NG但人工复核后为OK的比例,这个指标直接反映了给产线增加的工作量。
- 过杀率:产线上实际NG品中被模型漏掉的比例,这个才是质量部门真正关心的。
质量部门关心的永远是“过杀率”而不是“漏检率”,这个区别非常重要。因为缺陷样品本身就是稀有事件,你在测试集上算出来的漏检率再低,也抵不过产线上缺陷基数大的情况——1%的漏检率可能意味着每天有一百个NG品流出,而质量部门的容忍度往往是零。所以每次项目汇报我都会先把这几个指标的关系讲清楚,避免后续扯皮。
4. 全流程落地细节:从数据收集到产线稳定运行
4.1 数据采集阶段最容易忽略的三个点
很多团队拿到一批图片就开始标数据,这个习惯需要改。数据采集阶段最值得花时间确认的是场景覆盖度:
第一,光源条件是否覆盖完整。工业检测的成像条件非常固定,但不同批次的相机、光源老化程度会造成亮度差异,数据采集阶段要把不同亮度水平下的图片都收一些,增强才能有的放矢。
第二,产品变体是否全覆盖。同一个型号的产品可能有不同颜色的外壳、不同的表面处理工艺,缺陷在视觉表现上差异很大。采集阶段漏了某个变体,后面模型上线就会漏检这个变体上的缺陷。
第三,NG品的获取渠道要提前搭好。缺陷样本不能全部等产线自然产生,那要等太久。我会主动和产线沟通:能否在换料、调试阶段人工制造一些缺陷?比如划痕可以通过标准载荷的划针划出,压伤可以用固定能量的冲击器打出来。这样制作的缺陷虽然和自然缺陷有一定差距,但能显著扩充样本库,也让模型提前见到更多形态。
4.2 标注质量:边界样本才是决定成败的细节
小样本训练的所有努力,在劣质标注面前都会归零。缺陷检测标注最容易出问题的地方是边界争议。
一线标注员经常犯的错是“能圈就圈”,把模糊区域也标进缺陷框里,这就直接污染了正样本的质量。我的解决办法是写一份缺陷标注规范文档,把每种缺陷的“确定性分级”写清楚。标注员对不确信的区域,不要直接标注,而是标注成“待确认”,由算法工程师和质量工程师一起复核后再决定是否纳入训练。这套流程看起来繁琐,但能省下后面大量的误检返工时间。
另外一个经验是标注的“最小尺寸”要提前约定。小于多少像素的缺陷算不算缺陷?考虑到模型的实际分辨率和产线要求,我会在项目启动阶段和质量部门达成一致:比如“小于5×5像素的缺陷不检测”。这个约定不写清楚,后面就会发现标注员把大量微小区域标出来了,导致模型把精力浪费在芝麻大的地方,反而漏掉真正的大缺陷。
4.3 数据划分的防泄漏技巧
训练集、验证集、测试集的划分,在小样本场景下稍不注意就会出大问题。前文提到,增强后样本不能和原始样本同时出现在训练集和验证集里。同一个缺陷样本经过增强生成的多张图片,它们的底层信息是共享的,如果增强图和原图被随机分到了训练集和验证集,验证集的指标会虚高,看起来模型表现很好,上线后就露馅。
正确的做法是:先按图片分好组,同一缺陷原始图片以及由它生成的所有增强图片必须全部放进同一个集合。如果缺陷样本来自同一个产品批次,也要尽量按批次划分,避免同一产品在不同位置拍摄的图片被拆散。
4.4 部署与推理性能优化
工业检测是实时任务,推理速度往往决定了方案的可行性。部署前先算一笔账:产线节拍是每分钟多少件,每个相机拍几张图,每张图的推理允许时延是多少。举个例子:某产线节拍是每秒一件,每个工位拍两张图,那单张图推理必须控制在400毫秒以内,这还没算图像采集和上下料的时间。
模型选型和部署平台是强耦合的。GPU部署的话模型选择比较自由,但很多现场只有工控机,只能跑CPU或轻量级加速卡。这种场景下,模型轻量化就很重要。我一般会把YOLO系列的backbone换成轻量结构,比如用ShuffleNetV2、MobileNetV3之类,再用TensorRT或OpenVINO做加速。精度会掉一些,但速度能提升三到五倍。实测下来,MobileNetV3结合TensorRT在CPU上的推理速度能跑到约60fps,精度下降大约在2到3个百分点,完全够用。
还有一个很常见但经常被忽略的点:相机成像参数在部署后要和训练时保持一致。如果训练时用的是自动曝光,上线后自动曝光把图像亮度调偏了,模型表现就会大打折扣。我的习惯是,训练前把相机的曝光、增益、光源亮度全部固定,并把这组参数写在检测方案文档里,部署时逐一核对。
4.5 上线后的持续迭代机制
模型上线不是终点,而是迭代的起点。我在项目里固定了一套节奏:每周做一次模型表现回顾,每月做一次模型增量训练。
每周的回顾重点看两个数据:漏检样本的分布变化和误报样本的分布变化。漏检样本里如果出现了新形态的缺陷,就要及时把这些样本补充进训练集。误报样本里如果某种干扰反复出现(比如固定位置的光斑、夹具反光),且人工确认是系统性干扰,就要考虑加针对性规则过滤。
增量训练要控制频率,不要上线第一天就开始天天训练,会引入不稳定性。我一般会攒两到三周的漏检样本和误报样本,进行一次增量微调。微调时要把之前模型的权重作为初始权重,而不是从头训练,避免模型“遗忘”之前学到的缺陷特征。
5. 避坑指南与经验沉淀
5.1 高频踩坑场景排查速查
| 现象 | 排查思路 | 解决方案 |
|---|---|---|
| 验证集指标好,上线后漏检率高 | 检查数据划分是否泄漏;检查成像参数是否一致;检查产品变体是否覆盖 | 按批次划分数据;固定相机参数;补充变体样本 |
| 误报集中在某个固定区域 | 大概率是光源反射或夹具遮挡 | 加区域性掩码规则;调整光源角度;排除该区域检测 |
| 训练loss降不下去 | 检查标注一致性;检查增强是否过度破坏特征 | 复核标注;减少干扰性增强 |
| 新批次产品上线后漏检率飙升 | 产品表面工艺改变或光源老化 | 快速收集新批次正常样本做对比;增量训练 |
| 模型对缺陷和正常品置信度重叠 | 模型特征区分度不足 | 改用分割模型;加入自监督预训练;加二次复核 |
5.2 判断模型是否真正“学到”缺陷特征的土办法
有时候模型指标看起来不错,但我心里没底,会做一个简单测试:把一幅正常图片,手动在软件里画一个模拟缺陷区域,看看模型能不能检测出来。如果模型连合成的模拟缺陷都检不出,那说明它真的没有学到缺陷的本质特征,只是记住了训练集上那几个样本的像素模式。这个测试不能代替正式评估,但能快速验证模型的泛化能力,我几乎在每次模型验证周期里都会跑一遍。
5.3 团队协作与流程文档
最后说一个偏软但影响极其深远的点:工业缺陷检测项目不是纯算法项目,它是算法、光学、机械、质量、产线五方协作的系统工程。我发现凡是做失败项目,最普遍的原因是漏检和误检的指标定义没有在项目初期对齐。算法团队觉得召回率已经很高了,质量团队却觉得过杀率不可接受,两边对数据口径的理解都不一样,后续所有优化都成了无效沟通。
我的做法是在项目启动第三天就拉一场评审会,把“漏检率”“误检率”“过杀率”“复检率”这四个指标的定义和计算方式白纸黑字写下来,并让质量、生产、算法三方签字确认。后续每次迭代都以这套指标口径去评估,避免后面做无用功。
在这个项目里,我最深刻的体会是:小样本训练看起来是个技术问题,但真正决定成败的是你是否愿意花时间去把数据策略、标注规范、阈值校准、反馈闭环这些细节落实。模型迭代的速度取决于漏检样本回流的速度,而漏检样本回到训练集的时间越短,系统就越安全。这也是我在后续每个项目里都坚持的第一原则——先把闭环建起来,再谈算法调优。