制造业的产线上“漏检”和“误检”这对冤家一直是视觉工程师的心病。传统方案调来调去往往按下葫芦浮起瓢。最近我在一个结构件表面检测项目里彻底扔掉了“画框”这个拐杖做成了一套不需要标注目标框的AI视觉检测系统效果反而出奇的好。这套思路不是我的原创但落地过程中的一些经验和踩过的坑我觉得值得拿出来聊聊特别是对于那些还在为标注成本发愁、或者被复杂规则折腾得焦头烂额的朋友应该会有直接的帮助。1. 为什么我决定“不画框”来检测缺陷1.1 传统缺陷检测的别扭之处框在哪质量就死在哪儿先说个扎心的现实。很多刚接触AI视觉的工程师以为缺陷检测就是把照片丢给模型模型自动告诉你“这里坏了”。结果一做项目才发现第一步就卡在标注上。得有人用标注工具把每一张缺陷图上的瑕疵区域框出来框得越准模型学得越好。听起来没问题对吧但产线上的缺陷千奇百怪裂纹是细长的凹坑是不规则的划痕是弯曲的有的缺陷颜色和背景几乎一样肉眼都得凑近了才分得清。在这种情况下标注人员的水平直接决定了模型的天花板。我见过一个项目标注员为了赶进度把一条很长的划痕断成了三截只框了中间最明显的部分。模型训练完肉眼可见的漏检。还有更致命的某些缺陷本身就很难定义边界。比如注塑件上的轻微流痕你说它算不算缺陷它影响功能吗不一定。但客户就是觉得难看。让标注员去框这种“感觉”他只能凭直觉发挥结果就是一批数据一个风格模型训练出来妥妥的“精神分裂”。所以“框”这个动作不仅消耗人力还把缺陷的先验知识位置、形状强行灌给了模型。这导致模型的泛化能力很差换一条产线、换一种光照之前的标注基本作废。而且越是依赖框标注的共识成本就越高。让三个工程师分别给同一张图的缺陷画框画出来的IoU能到0.7就算烧高香了。模型学着一堆充满分歧的标签它不懵才怪。1.2 一次尝试的缘起被“漏检”逼出的新思路我们当时接的是一家做精密结构件的客户需求要检测加工表面的微小划痕和压伤产量大、节拍快。按照老办法先拉了半个月的图像找了三个标注员吭哧吭哧框了两周加起来两万多张图。结果一上测试集漏检率居高不下。客户那边催得急产线上每天的QC质检员倒班都顶不住了。我那会儿就在琢磨有没有一种办法能绕开“画框”这个流程直接从图像本身去学习“什么是正常的”。只要学会了正常样本的样子不正常的东西一出现它自己就会报警而且不需要告诉它具体哪儿不正常。这个思路往深了想其实就是不定义缺陷本身而是定义“正常”。这比定义缺陷要容易得多因为正常样本到处都是采集成本极低。于是我就开始动手验证最初用的不是多复杂的深度学习模型就是把一堆正常的灰度图拿去训练一个自编码器。想法很简单如果模型只见过正常样本那么遇到缺陷样本时它的重建误差Reconstruction Error应该会显著变大。实验结果还真有那个趋势。缺陷区域确实在误差图上亮了起来但背景纹理的干扰也大得吓人。不过至少验证了方向可行不画框也能揪出异常。2. 核心思路拆解缺陷检测的本质是“找不同”2.1 为什么“找不同”比“认缺陷”更实际我们换个角度来看。画框检测本质上是“认缺陷”是让模型去学习某一类缺陷的视觉特征。比如学会“划痕”的样子那就得给它看几百张画了框的“划痕”图。问题在于产线上的缺陷是无穷无尽的你可以标注出常见的几十类但总会有一种新形态的缺陷训练的时候没见过模型就会漏检。不画框的方案换了个角度把缺陷检测变成了“找不同”。我不需要知道缺陷长什么样我只需要知道“正常”长什么样。正常的表面的纹理、光泽、颜色在理想状态下是有规律的。一旦出现缺陷不管它是什么类型它在空间分布上一定会打破这种规律在像素层面产生局部突变。模型只要足够敏感就能捕捉到这种突变。这个思路在工业场景里特别实用。因为大多数生产线上正常产品的数量是远大于缺陷产品的正常样本的占比一般在90%以上。用这些干净的正常样本来训练模型数据采集和清洗的难度很低。而“画框”方案里往往还需要做大量的数据增强、难点样本挖掘就是为了对抗样本的多样性。不画框方案一上手你会发现数据准备的工作量直接降了一个维度。2.2 技术路线的取舍从特征嵌入到重建误差哪个更靠谱确定了“找不同”的方向具体实现上有几种路线我给大家做个对比。第一种是重建误差路线典型代表就是自编码器和生成对抗网络的变体。模型吃一张图吐一张图目标是让输出逼近输入。正常样本重建得很好缺陷样本重建不出来就会在误差图上“现形”。这种方案部署简单模型轻量但有个天生的问题如果模型学习能力太强它可能连缺陷也一起重建出来了导致漏检。所以在训练时得控制模型的表达容量但这又容易欠拟合。第二种是特征嵌入路线代表算法是PatchCore。这种方案不直接重建像素而是把图像切分成一个个小块用预训练的卷积神经网络把这些小块提取成特征向量。正常样本的特征会被存进一个“记忆库”里。推理时把测试图像的小块也提取特征然后去记忆库里找它最相似的特征如果相似度不够高就判定为缺陷。这个方案现在的鲁棒性最好对纹理背景的干扰抵抗力很强我最终选择的就是这条路线。第三种是基于知识蒸馏的Teacher-Student方案。用一个大模型当老师一个小模型当学生两个都看同一张图。老师预测的结果和学生的预测结果做对比正常情况下它们应该一致一旦出现缺陷学生模型就会预测错乱和老师的输出产生差异差异图就是缺陷图。这三种方案我实际都跑过一轮对比测试下来PatchCore的稳定性明显优于重建方案准确率也更高知识蒸馏的调参成本会高一些适合有充足时间打磨的团队。对于多数制造业客户我偏向前两种的实用主义路线。2.3 无监督异常检测在三种场景中的适配性场景A表面纹理检测金属拉丝、磨砂面。这种场景最难因为正常纹理本身就有随机性。用画框方案框都框不准。我的经验是必须用PatchCore并且特征提取网络得选大一点的才能捕捉到细微的纹理异常。场景B规则表面检测玻璃面板、塑料外壳。这种场景相对简单正常表面高度一致。自编码器就能胜任因为背景干扰小重建误差很容易凸显缺陷。推荐先用自编码器跑一版成本低、速度快。场景C结构件轮廓检测螺丝、卡扣、密封圈。缺陷往往发生在边缘和角落这里的上下文信息很关键。画框方案喜欢把边缘截断导致模型学不到完整轮廓。而无监督方案能更好利用全局上下文。3. 实操过程从零搭建一套“无框”缺陷检测系统3.1 数据准备先干三件脏活累活数据是地基虽然不用画框了但预处理绝对马虎不得。我总结为三个步骤清洗、裁切、归一化。第一清洗。这是所有步骤里最费人的。一张图拍摄的角度偏了光线反光了甚至料件上沾了手指印这都算“正常”还是“异常”如果手指印被当成正常样本喂给模型模型就会学会容忍手印那是灾难。所以清洗的原则是肉眼看不出来的异常要当正常样本处理肉眼能看出非表面缺陷的干扰要直接剔除。第二裁切。产线上拍出来的原图往往是几百像素见方的区域缺陷可能只占几个像素。直接把全图丢给模型计算量太大而且严重的背景干扰会淹没缺陷特征。我习惯按感兴趣区域做裁切把有效检测区切出来尽量让正常纹理在图中占比高这样模型学得更专注。每个区域的尺寸尽量保持一致避免模型学到尺度差异。第三归一化。工业相机的成像受光源影响非常大不同批次可能存在亮度波动。如果不做归一化模型就会去适应亮度的变化真正的缺陷特征反而学不到。我采用的是简单的均值和方差归一化把图像像素值缩放到标准范围实测对于消除光源波动影响有明显帮助。3.2 环境配置与核心模型选型硬件方面我用的是单张中高端显卡操作系统用的常见发行版软件栈就是标准的深度学习框架加开源的异常检测工具库。这套组合跑PatchCore非常流畅训练百来张正常样本的图像只要几分钟推理一张图在GPU上不超过几十毫秒完全满足在线检测的节拍需求。PatchCore的核心思路我刚才提过一嘴这里再展开。它把输入图搞成很多重叠的图像块用预训练好的特征提取网络把这些块映射成向量。正常样本的全部向量都存下来构建成一个“记忆库”。但库里向量数量太多会拖慢推理速度所以PatchCore还内置了一个贪心采样算法挑出最有代表性的那部分向量大幅压缩记忆库的体积推理速度能快好几倍同时精度损失却几乎可以忽略。它最终的预测也很有实操价值。推理时输入图像的每个块都生成一个特征向量去记忆库里找最接近的邻居算一下距离。这个距离大于某个阈值就认为它是region anomaly区域异常。把所有异常区域合在一起还能得到一张像素级的异常得分图直接转成热力图叠加在原图上定位缺陷位置非常直观。3.3 让参数更实用的调校细节阈值、核心尺寸和特征选择很多朋友第一次跑通模型之后最头疼的就是阈值设置。其实阈值设置之前有几个更底层的参数要调好。一是图像块的尺寸。PatchCore的核心尺寸参数直接决定特征的尺度。缺陷比较小比如几个像素的麻点就得用小一点的块比如16像素或者32像素。缺陷比较细长比如划痕就得适当放大块尺寸比如用96像素甚至128像素让块内同时包含划痕和周边的正常纹理作为背景上下文这样异常更容易凸显。这个参数需要对比实测来选我一般会拿一批验证集试几个候选值看哪组能让正常样本和缺陷样本的得分分布分得最开。二是特征池的构建方式。正常样本尽量涵盖产线可能出现的所有正常状态。有时候同一种产品会切换不同工序表面粗糙度可能会有差异这种差异属于正常波动但模型分不清就会把它当成异常。所以采集数据时尽量把不同工序状态下的正常样本都塞进去让记忆库足够丰富。三是阈值设定。阈值不是拿着验证集跑出来的而是要到现场去试出来的而且要多试几轮。因为真实产线上的光照、振动都会影响得分分布。我习惯的做法是先在离线数据集上算一个初始阈值然后装到产线测试记录误报情况再根据实时数据回馈来微调。有时候上下浮动0.5个得分误报率就能差出一个数量级。3.4 推理部署如何把模型塞进产线系统里模型训好后下一步就是部署。工业现场不比实验室电脑配置参差不齐有的甚至还是老式工控机没有独立显卡。针对这种情况我会把模型做一次集中化处理就是用推理加速框架把模型封装成接口生成动态链接库。这样就能绕开原始深度学习框架的环境依赖一个工厂里几十台电脑不用每台都折腾配置环境直接拷贝文件、注册组件、调用DLL接口就行。接口的输入输出也很讲究。输入就是一张BMP格式的灰度图或者彩色图输出是一个包含得分、坐标信息的数据结构。得分是全局异常分数坐标是异常区域的中心点。这样工控机上的上位机软件只要调用接口传一张图进去就能拿到结果然后在界面上画个红框报警。部署流程里我总结出几个容易踩坑的点模型输出彩色图还是灰度图一定要和训练时保持一致否则精度直接掉一截。接口的输入尺寸要固定因为实际产线上的源码图和裁切图的尺寸可能不一样如果是动态尺寸输入每个尺寸都得重新适配麻烦且易错。所以我习惯在训练时就把输入尺寸固定到某一个值推理时也一样多出来的像素直接填灰度值不参与计算。工控机的CPU版本推理速度如果跟不上最简单的优化是把输入尺寸再缩小一档或者换用轻量级骨干网络。我实测过把输入尺寸从512降到384推理时间能缩短三分之一精度损失在可接受范围内。4. 常见问题与排查技巧实录4.1 误报压不下来先别急多半是“正常”没学全误报是这类系统的头号敌人。每次信号一响产线工人跑过去一看啥事没有多折腾几回工人就不信这个系统了直接把它当摆设。排查思路不要盯着模型要先问这个“正常”的状态模型真的见过吗有一次客户反映一个产品在某个固定位置总是误报我过去一看原来那个位置贴了一张小小的标签纸是印刷上去的序列号。正常产品都有的东西但我们的正常训练集里恰好没怎么覆盖。就这么一个疏漏导致所有带标签的样本都变成了“异常”。后来我在采集阶段就默默记下一本账正常样本里必须覆盖所有的固定特征包括文字、标签、定位孔、按钮区域。这样做之后误报率立刻下去了。所以遇到误报先回去翻训练集比调阈值管用得多。4.2 真的缺陷漏过去了可能是“块头”没对好漏检比误报更让人头疼因为你不知道什么时候会漏。有一次我们检测一种细长的裂纹长度跨度很大有的裂纹只有几十个像素有的甚至贯穿整个检测区。我一开始用默认的块尺寸去训练结果长裂纹漏检严重因为长裂纹的图像块在特征空间里更像是一条“正常的边缘过渡”不像缺陷。后来我把块尺寸调大让它能看到裂纹旁边的正常背景特征对比一下就出来了漏检率终于降下来。所以如果你发现某种缺陷一直漏检优先怀疑是不是图像块的感受野太小看不清“全局”。还有一个细节裂纹的方向也有影响水平和垂直方向的检测难度不一样。最好在训练数据里多放一些各个方向的样本。4.3 现场内存爆炸这是高分图像带来的隐性问题工业相机现在分辨率越来越高有的直接给到1200万像素甚至更高。如果训练和推理时直接用全分辨率图内存和显存都会撑不住推理速度也惨不忍睹。我做过一次挑战用的是一台只有16GB内存的工控机跑1200万像素的图。直接把全图塞进模型内存直接爆掉。后来把检测区裁切出来只针对关键表面做检测内存占用降到了合理范围推理速度也回到了满足产线节拍的水平。我的建议是不要迷信高分辨率。在保证缺陷被分辨出来的前提下尽量压缩图像尺寸或者裁出关键区域。4.4 各类异常模式的排查速查表常见问题优先排查方向推荐处理手段误报集中在某个固定区域该区域存在正常标记、定位孔或固定特征扩充该区域正常样本或将区域排除出检测范围细小点状缺陷漏检图像块感受野过大纹理特征被平均化调小块尺寸例如从128降到64或32长条裂纹缺陷漏检块感受野过小缺乏背景上下文调大块尺寸例如从32升到96或128光照变化引发误报归一化参数失效或光源老化重新采集各光照条件下的正常样本调节归一化参数推理速度不达标输入尺寸过大、特征库冗余按比例缩小输入尺寸精简记忆库规模减少检索量新换产线立即误报训练集与现场状态不匹配用少量现场样本进行微调重新训练并更新记忆库提示排查时不要“头痛医头”先花时间搞清楚问题是数据问题、特征尺度问题还是阈值问题方向对了才有效。5. 工具选型解析与经验心得5.1 框架怎么挑能少走一半弯路异常的检测工具有个特别好的地方就是大部分研究已经开源了而且还在持续更新。我在好几个项目里都是直接使用开源框架作为基础它集成了各种主流的异常检测算法包括无监督、半监督以及更前沿的基于大模型的方案。调用方式很友好而且踩过坑的工程师们已经把很多教程写得比较清楚上手成本比从零写模型低太多。我个人的排序建议如果追求结果稳定先上PatchCore如果想轻量快速验证先用自编码器如果团队有算法专家可以考虑探索基于变换器的最新方案但对绝大多数现场项目来说传统的算法已经足够用。先进不一定好用稳才实用。5.2 关于“不画框”方案我的几点体会这套方案已经帮我在三四个行业的检测项目里落过地包括金属件外观、塑料件外观、纺织品表面。整体来看交付效率确实提升了项目的确认周期明显缩短。但也要说点实话它并不是万能的。它最适合的还是表面纹理均匀、正常状态相对单一的场景。如果产品本身设计就非常复杂每当一个不同型号上线就需要重新采集正常样本更新记忆库维护成本会显著增加。而且它只能告诉你“哪里不一样”不太擅长告诉你“这个不一样严不严重”。最终判定是否合格的规则还是要靠阈值来定这个需要客户和你慢慢打磨。但我的另一个重要体会是这个方案极大改变了项目交付各方的协作关系。以前调模型要反复催客户标注客户还总是标注得不符合规范现在采集一批正常样本一个下午就能搞定客户省事我也省心。而且实际上因为减少了人工干预客观性更强了客户对检测结果的信任度反而提升了不少。6. 写在最后的几个小建议如果你正准备用这个思路去做产品别急着一次就追求完美。我的做法是分两步走第一步搞明白产品到底有多少“正常状态”用一周时间把正常样本攒足宁多勿缺第二步先上最简单的自编码器验证流程把检测界面、报警逻辑、数据回传这些外围环节跑通再换PatchCore做精度优化。这样整个交付节奏会从容很多。另外不管用什么方案现场的抗干扰设计永远别忽略。光源晃一下、相机抖动一下都会导致成像波动。模型再强也扛不住输入剧烈变化。所以硬件固定好后尽量加装遮光罩和减振装置这些细节对检测准确率的影响很可能比十个好的算法参数还大。这套“不画框”的方案说到底就是一场思路转换与其费劲教模型认识每一种“错”不如让模型清楚地知道什么才是“对”。只要抓住了“正常”那些不速之客自然原形毕露。