
工业产线上的缺陷检测最让人头疼的从来不是能不能检出而是样本太少和漏检太多这两件事同时压过来。我做过几个落地产线项目客户给的正样本往往只有几十张甚至十几张缺陷形态还千奇百怪而产线对漏检的容忍度几乎是零一个划痕漏过去后面可能就是整批退货。这篇内容就是把我自己在小样本条件下训练检测模型、并把漏检率压到可接受范围的完整流程拆开讲清楚从数据构造、模型选型、损失函数调整到阈值策略和上线后的持续迭代尽量给到能直接抄作业的细节。不管你是刚接触工业异常检测的新手还是已经用过YOLO做目标检测、想把它搬到产线上的老手都能从里面找到能用的东西。1. 工业缺陷检测的真实难点为什么通用检测套路在产线会失灵1.1 小样本不是数据少这么简单很多人第一次听到小样本训练第一反应是那我多拍点不就行了。在实验室里确实可以但在真实产线上这句话基本等于废话。工业缺陷的出现本身就有很强的偶发性有些缺陷一批产品里可能就出现两三个你想凑够几百张正样本可能要等上几个月甚至更久。更麻烦的是缺陷的形态分布极不均匀——划痕有长有短、有深有浅凹坑有大有小脏污有各种形状你拍到的这几十张很可能只覆盖了缺陷形态空间里很小的一块。这就带来一个很隐蔽的问题模型在训练集上表现很好一到产线就疯狂漏检。原因不是模型不行而是它根本没见过那种形态的缺陷。我踩过最典型的一次坑是做一个金属表面的缺陷检测训练集里划痕基本都是横向的结果产线上出现了一条纵向划痕模型置信度只有0.2直接漏掉。后来复盘才发现数据增强里我压根没加旋转模型学到的划痕特征里隐含了方向先验。所以小样本训练的核心矛盾不是样本数量绝对值少而是样本覆盖的形态空间太窄。你要解决的不是怎么用少量数据训出一个模型而是怎么用少量数据让模型学到缺陷的本质特征而不是记住这几十张图的表面模式。1.2 漏检控制的本质是召回率与误报率的博弈产线场景下漏检把缺陷判成良品和误报把良品判成缺陷的代价完全不对称。漏检一个缺陷可能意味着整批产品流到客户手里后果是客诉、退货、甚至丢单误报一个良品最坏情况是人工复检一遍成本可控。所以工业检测里我们通常会把召回率Recall放在第一位宁可误报多一点也不能漏。但这里有个陷阱如果你无脑把置信度阈值调低来提召回误报会爆炸产线工人被大量误报淹没之后会开始习惯性忽略报警这时候漏检反而会以另一种形式出现——人不再信任系统了。所以漏检控制不是单纯调阈值而是一整套组合拳数据层面要让模型见过足够多的缺陷形态模型层面要让损失函数对难样本更敏感后处理层面要用合理的阈值和策略把召回和误报平衡到产线能接受的水平。我一般会先跟客户确认一个可接受的误报率上限比如每千件不超过5件误报然后在这个约束下把召回率做到最高。这个思路和纯学术里追求mAP最大化完全不一样落地的时候指标要跟着业务走。1.3 通用YOLO直接拿来用会遇到的三个具体问题YOLO系列在通用目标检测上确实强但直接搬到工业缺陷检测通常会遇到三个问题。第一个是缺陷目标太小。工业缺陷很多是像素级的一条划痕可能就几个像素宽YOLO下采样到一定层数之后这些小目标在特征图上几乎消失了。这也是为什么很多做工业检测的人会去看YOLO的neck结构和多尺度检测头甚至去改efficient head的设计目的就是保住小目标的特征。第二个是正负样本极度不平衡。一张工业图像里缺陷区域可能只占千分之几剩下全是背景。YOLO默认的损失函数在这种极端不平衡下容易被背景样本主导模型学到的更多是哪里有背景而不是哪里有缺陷。第三个是缺陷边界模糊。通用目标检测里物体的边界是清晰的但缺陷的边界往往是渐变的划痕从深到浅过渡你很难说清哪一像素是缺陷、哪一像素是背景。这会导致标注本身就有噪声模型学到的边界回归目标不稳定。这三个问题决定了你不能把YOLO当黑盒用必须在数据、损失函数、后处理上做针对性调整。2. 小样本条件下的数据构造把几十张图用出几百张的效果2.1 缺陷数据的采集与标注策略小样本场景下每一张图都很珍贵所以采集和标注必须讲究。采集阶段我一般会做两件事一是尽量覆盖不同的光照条件因为产线光照变化是漏检的一大来源二是对同一类缺陷刻意从不同角度、不同位置多拍几张哪怕看起来重复也要保证形态多样性。标注阶段有个经验缺陷标注不要追求像素级精确但要保证一致性。我见过团队里两个人标同一批图一个人把划痕标得宽一点一个人标得窄一点结果模型学出来的边界回归非常混乱。所以标注规范一定要统一最好先标十几张做交叉校验确认大家的标注尺度一致之后再批量标。另外对于边界模糊的缺陷我倾向于用矩形框而不是多边形标注。原因是小样本下多边形标注的噪声更大而且YOLO这类检测器本身就是基于框的用框标注反而更匹配。如果确实需要像素级分割那要考虑YOLO的实例分割分支但那是另一个复杂度级别的事了。2.2 针对工业缺陷的增强手段哪些有用哪些是坑数据增强是小样本训练的核心手段但不是所有增强都适合工业缺陷。我列一下我实际用过、效果比较明确的几类。增强手段适用场景注意事项随机旋转缺陷方向不固定旋转后要同步变换标注框且注意图像边缘填充亮度/对比度扰动光照变化大的产线扰动幅度要贴合真实光照波动范围高斯噪声相机噪声明显的场景噪声强度过大会淹没小缺陷随机裁剪缺陷位置不固定裁剪后要保证缺陷仍在图内马赛克增强小目标检测工业场景慎用可能引入不真实上下文复制粘贴缺陷缺陷样本极少效果明显但粘贴位置要合理这里重点说两个。复制粘贴缺陷是我在小样本场景下最推荐的增强方式把缺陷区域抠出来随机粘贴到正常图像的不同位置能快速扩充正样本。但要注意粘贴的位置不能太离谱比如你把一个表面划痕粘到产品边缘之外模型会学到错误的上下文。我一般会限制粘贴区域在产品表面范围内并且做一定的边缘融合避免出现明显的拼接痕迹。马赛克增强在通用检测里很火但工业场景我建议慎用。原因是马赛克会把四张图拼在一起引入大量不真实的上下文关系模型可能学到缺陷总是出现在图像某个角落这种伪特征。如果非要用建议降低使用概率比如只对20%的样本做马赛克。2.3 用异常检测思路补充正样本不足当正样本实在少到无法训练一个可靠的检测器时我会考虑引入异常检测的思路。异常检测的核心逻辑是只用正常样本训练一个正常模型然后任何偏离正常的区域都判为异常。这样就不需要大量缺陷样本了。工业异常检测算法里比较有代表性的思路是基于特征重建或特征分布建模的方法。简单说就是让模型学会正常样本的特征分布测试时如果某个区域的特征和正常分布差异大就判为异常。这种方法的优势是对缺陷形态没有先验假设任何没见过的异常都能检出来劣势是误报率通常偏高而且定位精度不如有监督检测器。我实际的做法是把异常检测和有监督检测结合起来用异常检测做粗筛把可疑区域找出来再用小样本训练的有监督检测器做精判。这样既能利用异常检测对未知缺陷的敏感性又能利用有监督检测器的高精度。这个组合在几个项目里都把漏检率压下来了。3. 模型与损失函数让YOLO对小缺陷和难样本更敏感3.1 为什么要在YOLO基础上做针对性改造前面说了通用YOLO直接用在工业缺陷上有三个问题所以改造是必要的。但改造不是越复杂越好我见过有人一上来就换backbone、加各种注意力模块结果训练不稳定、推理速度还掉了一半。我的原则是先定位瓶颈再针对性改。如果瓶颈是小目标检测那重点改neck和检测头保证高分辨率特征图上的信息不丢失如果瓶颈是正负样本不平衡那重点改损失函数如果瓶颈是边界模糊那可以考虑软化边界回归的目标。不要一次性全改改一处、验证一处这样出问题也好定位。3.2 损失函数调整让难样本的权重更高YOLO的损失函数一般由三部分组成分类损失、边界框回归损失、目标置信度损失。在小样本工业缺陷场景下我通常会做两个调整。第一个是提高正样本的损失权重。因为正样本太少如果不加权模型会倾向于把所有区域都预测成背景这样整体损失反而更低。具体做法是在置信度损失里给正样本一个大于1的权重系数我一般从2开始试根据训练曲线调整。第二个是用Focal Loss的思路处理难易样本不平衡。Focal Loss的核心是降低易分样本的损失权重让模型更关注难分样本。工业缺陷里那些边界模糊、对比度低的缺陷就是难样本用Focal Loss能让模型在这些样本上多花力气。不过Focal Loss的参数需要调我一般先设gamma2然后根据验证集上的召回率微调。还有一个细节是边界框回归损失的选择。CIoU、DIoU这些损失在小目标上表现不错但如果缺陷边界本身模糊回归目标就不稳定。我有时候会改用软化版本的IoU损失或者降低边界回归损失的权重让模型更关注有没有缺陷而不是边界多精确。这个取舍要看业务需求如果下游只需要知道有没有缺陷那边界精度可以适当放松。3.3 多尺度检测与efficient head的取舍工业缺陷的尺度跨度可能很大有的缺陷几个像素有的占半张图。YOLO本身是多尺度检测的但默认配置下小目标的检测能力有限。我一般会做两件事一是增加一个更高分辨率的检测头专门负责小目标二是调整anchor的尺寸让anchor更贴合实际缺陷的大小分布。关于efficient head我的看法是它在参数量和精度之间做了不错的平衡如果你的算力有限、又需要多尺度检测可以考虑。但要注意efficient head的设计初衷是通用检测搬到工业场景可能需要重新调anchor和特征融合方式。我试过直接套用效果一般后来还是根据自己数据的缺陷尺度分布重新设计了检测头。这里有个经验不要盲目追新结构先把你手头数据的缺陷尺度分布统计清楚。我一般会把所有标注框的宽高统计出来画个分布图看看缺陷主要集中在哪个尺度区间然后针对性地设计检测头。这个统计工作花不了多少时间但能帮你省掉很多试错。4. 训练流程与调参小样本下怎么把模型训稳4.1 预训练权重的选择与迁移策略小样本训练预训练权重几乎是必须的。但用哪个预训练权重、怎么迁移有讲究。我一般会选在大型通用数据集上预训练的权重因为它的底层特征提取能力已经很强了你只需要微调高层特征来适配你的缺陷。迁移策略上我通常分两步先冻结backbone只训练检测头让模型先适应你的数据分布然后再解冻全部层做微调。这样做的好处是避免一开始就全量微调导致预训练特征被破坏。冻结阶段的epoch不用太多一般10到20个epoch就够了看到检测头的损失下降趋缓就可以解冻。学习率方面冻结阶段可以用大一点的学习率比如1e-3解冻之后要降下来我一般用1e-4甚至更低。小样本下学习率太大很容易过拟合训练损失降得很快但验证集召回率上不去这就是典型的过拟合信号。4.2 训练过程中的监控指标别只看loss小样本训练最容易犯的错就是只盯着训练loss。训练loss降得很漂亮但验证集召回率一塌糊涂这种情况太常见了。我一般会同时监控几个指标验证集上的召回率、误报率、以及每个类别的AP。特别是召回率这是工业检测最关心的。还有一个容易被忽略的指标是难样本的召回率。我会把验证集里那些边界模糊、对比度低的缺陷单独拎出来看模型在这些样本上的表现。如果整体召回率不错但难样本召回率很低说明模型还没学到缺陷的本质特征需要继续调。另外我会定期把验证集的预测结果可视化出来看。有时候指标看着还行但一看可视化结果发现模型检出的位置偏了或者把一些明显不是缺陷的区域检出来了。这种问题光看指标是发现不了的。4.3 早停与模型选择什么时候该停小样本训练过拟合来得快所以早停很重要。我的做法是设定一个耐心值比如验证集召回率连续10个epoch没有提升就停。但这里有个细节召回率可能会有波动所以我会用滑动平均来判断趋势而不是看单个epoch的值。模型选择上我不一定选验证集指标最好的那个模型。因为小样本下验证集本身就有噪声指标最好的模型可能是过拟合到验证集的。我一般会选验证集指标在前几名、且训练轮数适中的模型然后拿到实际产线上做小批量测试用真实数据来最终确认。5. 漏检控制的工程手段从阈值策略到上线迭代5.1 置信度阈值与NMS参数的联合调优模型训练完之后后处理参数对漏检率的影响非常大。置信度阈值调低能提召回但误报会涨NMS的IoU阈值调低能减少重叠框但可能把相邻的缺陷框合并掉导致漏检。我的做法是在验证集上做网格搜索把置信度阈值和NMS IoU阈值组合起来试找到在误报率约束下召回率最高的组合。这个搜索不需要很精细粗粒度先找到大致范围再细调。我一般会先固定NMS IoU在0.5左右调置信度阈值找到合适的置信度之后再微调NMS IoU。还有一个技巧是对不同类型的缺陷用不同的阈值。比如划痕这种容易和正常纹理混淆的缺陷阈值可以设低一点保召回而脏污这种特征明显的缺陷阈值可以设高一点控制误报。这个需要你对每类缺陷的特性有了解。5.2 多模型融合与级联检测降低漏检如果单模型漏检率还是压不下去可以考虑多模型融合。我常用的有两种方式。一种是不同尺度的模型融合。训练两个模型一个专门检小缺陷一个专门检大缺陷推理时把两个模型的结果合并。这样能覆盖更广的缺陷尺度范围。另一种是级联检测。第一级用高召回、低精度的模型做粗筛把可疑区域都找出来第二级用高精度的模型做精判把误报过滤掉。这种级联结构在漏检控制上很有效因为第一级保证了召回第二级保证了精度。不过多模型融合会增加推理耗时上线前要评估算力是否够。如果产线节拍很紧可能需要在精度和速度之间做取舍。5.3 上线后的持续迭代把产线变成训练数据来源模型上线不是终点而是迭代的起点。产线运行过程中模型会漏检一些缺陷也会误报一些良品这些都是宝贵的训练数据。我一般会做一个难样本回流机制把模型置信度处于中间区间比如0.3到0.6的样本自动保存下来定期人工复核确认是缺陷还是误报然后加入训练集重新训练。这个机制的关键是闭环要快。如果回流周期太长模型迭代跟不上产线变化。我一般会做到每周回流一次产线稳定的话可以放宽到两周。另外回流的数据要标注规范不能随便标标就加进去否则会引入噪声。还有一个经验是定期做模型漂移检测。产线的光照、物料、相机状态都可能变化模型的表现会随时间漂移。我会定期用一批固定的测试样本跑一遍模型看召回率有没有明显下降如果下降超过阈值就触发重新训练。6. 几个实际项目里的踩坑记录与应对6.1 标注不一致导致的漏检有一次做塑料件表面缺陷检测训练集里有一批图是不同人标的结果模型上线后对某类缺陷漏检严重。复盘发现这批图里同一种缺陷的标注框大小差异很大有人标得紧贴缺陷有人标得松。模型学到的边界回归目标不一致导致对这类缺陷的置信度普遍偏低。应对方法就是前面说的标注前先做规范标一批做交叉校验。另外我后来加了一个标注质量检查步骤把标注框的宽高统计出来如果某个标注者的框尺寸明显偏离其他人就退回重标。6.2 光照变化导致的误报和漏检另一个项目是金属表面检测产线光照在不同时段会有变化早上和下午的光照角度不一样。模型在早上训练的下午就出现大量误报。后来我们在数据增强里加了更丰富的光照扰动并且在产线上加了补光把光照尽量稳定下来。同时后处理里对光照敏感的区域做了掩膜减少这些区域的误报。这个坑的教训是工业检测不能只关注模型产线的物理条件同样重要。如果光照不稳定再好的模型也扛不住。6.3 小缺陷在推理分辨率下消失有个项目缺陷非常小原图分辨率很高但为了推理速度我们把输入分辨率降到了640。结果小缺陷在降分辨率之后几乎看不见了漏检严重。后来我们改成用高分辨率做推理但速度掉下来了。最终的方案是用两级推理先用低分辨率做粗筛把可疑区域找出来再对这些区域用高分辨率做精判。这样既保证了速度又保住了小缺陷的召回。这个方案本质上和前面说的级联检测是一个思路只是级联的维度从模型变成了分辨率。7. 关于算力与部署的一点实际经验工业检测最终要落到产线上推理速度和稳定性是硬指标。我一般会在模型选型阶段就把算力约束考虑进去而不是训完再想怎么部署。如果产线节拍要求高比如每秒要处理几十帧那模型不能太大输入分辨率也不能太高。这时候可能需要在精度和速度之间做取舍比如用轻量化的backbone或者降低检测头的数量。我一般会先算一下算力预算产线节拍是多少、相机分辨率是多少、能接受的单帧推理时间是多少然后反推模型的大小和输入分辨率。部署方面我倾向于用成熟的推理框架把模型导出成通用格式再部署。导出的时候要注意算子兼容性有些自定义的损失函数或后处理算子可能不被支持需要提前验证。另外部署之后要做压力测试看长时间运行会不会有内存泄漏或性能下降。还有一点是模型版本管理。产线上可能同时跑多个模型版本或者需要快速回滚所以模型文件、配置文件、后处理参数都要做好版本管理。我一般会把每次上线的模型和对应的配置打包存档出问题能快速定位和回滚。8. 写在最后的一点个人体会做工业缺陷检测这几年我最大的体会是模型只是整个系统里的一环数据、标注、产线条件、后处理策略每一环都能决定最终漏检率。我见过太多团队把精力全花在调模型上结果数据标注一塌糊涂上线后漏检照样压不下去。小样本训练的核心不是用少量数据训模型这个技术动作而是如何用有限的数据让模型学到缺陷的本质。这需要你在数据增强、损失函数、迁移策略上做针对性的设计而不是套用通用检测的默认配置。漏检控制也一样它是一个系统工程从阈值调优到多模型融合再到持续迭代每一步都要围绕业务的实际容忍度来做。如果你正在做类似的项目我的建议是先把数据统计清楚把缺陷的尺度分布、形态分布、光照条件都摸透然后再决定模型怎么改、参数怎么调。不要一上来就追新结构、新算法把基础的数据和流程做扎实效果往往比换个模型来得明显。