☰
无监督视觉检测落地指南:不标缺陷也能高效检测异常
2026/9/26 6:40:29 网站建设 项目流程

干过工业视觉检测的人都懂,一个项目里最烧钱、最熬人的往往不是算法调参,而是数据标注。我见过太多团队,算法工程师和标注员一起加班到凌晨,对着几千张缺陷图一帧一帧抠框、画掩膜,标注完还得做一致性审核,来回折腾好几个礼拜。到后面大家不只是秃头,是连头皮都在报警。

所以这两年,“无监督视觉检测”在工业圈里越来越热。它的核心卖点就一句话:不用标注缺陷样本,也能把产线上的异常找出来。我最早看到这个思路时也半信半疑,但实测下来,在不少场景里它确实能做到“即插即用”的状态——你给它一批正常产品的图像,它自己学会什么是“正常”,推理时遇到长相不一样的,直接报警。这篇文章就把我实际落地这套方案的过程、踩过的坑、选型的思路都摊开讲一讲。

1. 数据标注:工业视觉里最闷的瓶颈

1.1 一张标注图像的隐形成本

先说个扎心的事实:在工业视觉项目里,标注的隐形成本远比大多数人想象的高。你说标注不就是拿个框圈一圈吗?在自然图像领域确实差不多,但在工业检测里完全是另一回事。

我举个例子。做手机中框外观检测,缺陷类型包括划伤、压伤、脏污、异色、麻点、凹坑……每种缺陷的形态还不一样:划伤有细长条、有片状的;压伤有的在边缘、有的在平面。标注员首先要看懂这些缺陷长什么样,然后还要理解“这个缺陷在什么光照下看得清”“边角反光算不算缺陷”这类因为成像条件不同而产生的歧义。

一个熟练的标注员在复杂工业图上,单张耗时两到五分钟是很正常的事。一个项目要是攒了五千张缺陷图,光标注工时就是三四个人的工作量。而且这还只是第一步,后面还有标注审核、返工、争议仲裁。前前后后一个礼拜能搞定都算快的。

1.2 工业场景为什么让标注更难

比耗时长更头痛的是“标不准”。工业缺陷本身就存在极度长尾的分布问题:某个批次的样件里,常见的划伤可能有几百个样本,但那种罕见的压裂可能一共就出现五六个。标注员在这么稀疏的样本上,很难形成稳定的判断标准。我见过同一个缺陷图,两个标注员一个判成“划伤”、一个判成“压伤”,最后还得拉上工艺工程师来仲裁——工艺工程师还未必有空。

更麻烦的是,有些缺陷类型连专家都说不清边界。比如注塑件的“光泽度异常”,你让标注员框出来,他可能觉得整张图都不对劲,但到底是哪个区域、什么范围,十个人有十个答案。这类模糊缺陷在监督学习下根本跑不出好效果,因为标注本身就带噪声,模型再厉害也是从垃圾里面学垃圾。

还有一个小众但很痛的场景——3D点云标注。热词里提到“3D点云标注ppt教学课件”,这背后是真实的痛苦。点云标注跟2D完全两码事,你面对的是几万个空间点,要旋转、缩放、框选,标一个三维包围盒就要花好几分钟,一帧数据标完人都麻了。很多团队一算成本,干脆暂时放弃三维检测,宁可漏检也不愿扛标注工时。

2. 无监督视觉检测到底在做什么

2.1 核心思路:只学“正常”,挑出“异常”

无监督视觉检测的思路其实很反直觉。传统监督检测是“缺陷样本 + 正常样本”一起喂给模型,模型学的是“缺陷长什么样”;无监督则完全不管缺陷长什么样,你只需要给它一堆正常样本,让它把“正常”这个概念内部化。推理的时候,模型看到跟“正常”偏差大的区域,就判定为异常。

这个思路之所以在工业场景走得通,原因也很简单:正常样本往往大把都是,缺陷样本反而稀缺。你去产线拍正常产品,一开机拍几千张都不是事,但要等缺陷出现,可能等一个班次都等不出几件。与其费劲去攒缺陷样本,不如反过来把好样本用足。

打个不严格的比方,这就好比保安认人。监督学习的保安是拿着几十张通缉犯照片站在门口比对,你会漏掉照片上没拍到的歹徒;无监督学习的保安是花几天时间记住厂里所有员工的脸,不是通缉名单上的人一律不放行,虽然也会偶尔误伤来参观的访客,但至少内部人员里的异常一个都跑不掉。

2.2 主流技术路线对比:重建、嵌入、蒸馏

“无监督”这三个字底下其实有三条不同的技术路线,搞明白这些才知道什么时候该选谁。

第一条是重建流派。核心是先训练一个自编码器或者GAN模型,让它学会压缩再还原正常图像。推理时把测试图像输入进去,模型会尝试用自己学到的“正常模式”去重建它,缺陷区域因为不符合正常模式,重建之后往往就糊了,和原图一对比,差异大的地方就是异常。这个思路简单直观,实际做起来有个要命的短板——随着模型能力增强,它对异常区域也能重建得像模像样,异常就被“洗干净”了。

第二条是特征嵌入流派,也是目前工业实测我最推荐的。代表方法有PaDiM、PatchCore这些。它们不重建图像,而是用ImageNet预训练的骨干网络(比如WideResNet)提取图像不同层级的特征,然后用一种压缩策略将整批正常图像的特征压缩成一个“记忆库”。推理时把测试图的特征提取出来,跟记忆库里的特征做最近邻检索,距离越大越可能是缺陷。PatchCore在MVTec AD公共数据集上的AUROC能达到99.1%,在工业场景是经受过考验的。

第三条是知识蒸馏流派,代表方法是STFPM。思路是同时准备一个预训练的教师网络和一个结构更小的学生网络,学生只用正常样本去学习“模仿教师的输出”。因为学生只见过正常样本,它在正常区域能和教师保持一致,但在缺陷区域就模仿不到位,师生之间的分歧就成了缺陷得分的依据。

三条路线的差异用一句线能说明白:重建派在“画面上”找差异,嵌入派在“语义特征上”找差异,蒸馏派在“模型的认知差异上”找差异。从我的实践来看,嵌入派的稳定性最高,对超参不敏感,车间里换线调试少,是真正最能接近“即插即用”的路线。

流派核心原理代表算法优点容易踩的坑
重建原图与重建图对比AE、GAN思路简单、直观模型过强时缺陷被“洗掉”
嵌入特征与记忆库对比PaDiM、PatchCore鲁棒性好、漏检低内存占用偏大
蒸馏师生网络输出差异STFPM小模型、推理快训练收敛不稳定

3. 搭建一套“即插即用”的无监督检测方案

3.1 第一阶段:数据准备正确姿势

说了这么多原理,还是得落到实际操作上。我以PatchCore为例,讲一套完整可落地的流程。

第一步还不是写代码,而是收数据。无监督检测对数据准备的讲究程度不亚于监督方案。你拿“正常样本”也有讲究,不能随便从产线拍一百张干净图就完事。关键是覆盖度:同一个工位,不同批次、不同光照条件、不同产品位置,最好都能覆盖到。我之前吃过一个亏——训练时用的是稳定的恒亮光源,结果生产线上灯罩老化后亮度降了几个百分点,模型当场就“抽风”,把大批正常产品全判成异常,因为特征分布已经整体偏移了。

正常样本的数量方面,一两百张是个起步值,条件允许的话攒到五百张以上,内存够的前提下记忆库更丰富,边界更稳。需要特别注意的一点:正常样本里绝对不能混入缺陷样本。哪怕这个缺陷很小、肉眼看不清,只要特征层面混进去了,模型就会把这类缺陷当“正常”学进去,后面就查不出来了。

3.2 第二阶段:模型训练与特征库构建

代码层面我不建议直接手撸PatchCore,工业项目里直接用开源库能省掉你好几周时间。我一直在用的是anomalib,它集合了PatchCore、PaDiM、STFPM等主流无监督算法,安装和调用都很方便。核心代码大致是这个流程:

pip install anomalib

然后一个最小训练脚本:

from anomalib.data import MVTec from anomalib.models import Patchcore from anomalib.engine import Engine # 正常样本放在 normal_train 目录下 dataset = MVTec(root="path/to/your/data", category="normal", split="train") model = Patchcore(backbone="wide_resnet_50_2", layers=["layer2", "layer3"]) engine = Engine() engine.fit(model=model, datamodule=dataset)

训练完成之后,模型会做两件事:用骨干网络提取所有正常图像的特征,再做coreset采样压缩记忆库。这个coreset采样很重要,如果不用它,几百张图的特征堆在一起会占用非常大的内存——512x512的图像,只用layer2和layer3的特征拼接,一张图就可能是几万维向量,几百张图特征库轻松超过几百兆。coreset采样就是按贪心算法挑出最具有代表性的特征子集,能在保留足够表征能力的同时大大压减记忆库体积。

我实测时发现,对大部分表面检测场景,compress因子设0.1附近效果就不错,就是保留10%的特征点,既降低检索耗时也不损失太多准确率。如果你的产线对内存要求严格,可以再往下压到0.05,但AUROC可能掉1~2个点,自己权衡。

3.3 第三阶段:阈值设定与产线集成

模型训练完,下一步不是直接部署,是定阈值。这一步很多新手会犯错误——看到代码里有个阈值参数就随便填个0.5,上线之后误报多到产线工人想打人。

正确的做法是留出一批正常样本做验证集,模型跑一遍之后,得到每个正常样本的最大异常分数,看这个分数的分布。一般是取“验证集99%分位数”作为初始阈值,这样能保证在验证集上正常样本的误报率控制在1%以内。如果产线对误报特别敏感,比如后道人工复检成本高,可以把阈值上调到99.9%分位数,但你要清楚,这同时会把一部分缺陷也放过去,是典型的此消彼长。

阈值定好之后,部署方式就看你的产线环境了。简单一点的,直接在工控机上跑Python推理脚本,通过相机API触发抓图,输出缺陷分数和缺陷区域热力图。要上生产环境的话,更推荐封装成HTTP服务,用FastAPI写个推理接口,PLC或其他上位机系统通过MJPEG或HTTP请求调检测服务。异常分数超过阈值就输出NG,同时把热力图和原图保存下来,方便工艺那边复核。

# 推理部署伪代码 from anomalib.deploy import OpenVINOInferencer inferencer = OpenVINOInferencer(path="model/openvino.xml", device="CPU") results = inferencer.predict(image=frame) score = results.pred_score # 异常分数 if score > threshold: mark_ng(frame, results.segmentations)

使用OpenVINO导出模型之后,推理速度在CPU上也能跑到几十毫秒一帧,完全满足大多数产线的节拍要求,不需要额外上GPU。

4. 实操中的常见问题与排查记录

4.1 误检率居高不下怎么办

这是最常被问到的问题。我也没少在这上面栽跟头。先说结论:模型本身很少是误检率高的根源,根源通常是“正常”的分布覆盖不够,或者成像环境变了。

排查思路是有顺序的。先在离线环境下,拿一批最近一周产线拍的老图(已经被判定为正常),用现成的特征库跑一遍,看看得分分布是不是明显比训练时高。如果高,说明你的特征库已经过期了,需要把最近这些正常样本追加进特征库重新做coreset采样。我自己的做法是做个定时任务,每周自动从MES系统导出一批判为OK的图像,增量更新特征库——这相当于让模型跟着产线状态一起迭代,能消化掉大量由光源老化、相机白平衡漂移引起的误报。

如果离线跑分布在正常范围,还是误报,就要看是不是相机脏污。这种问题特别隐蔽:相机镜头上沾了一小点灰尘,在图上也就占十几个像素,但特征层面会造成持续稳定的“异常”响应。而且它不是随机误报,是固定位置误报。遇到这种,先用保存下来的误报图看异常区域位置是不是集中在固定坐标,如果是,就直接把机台清洁工单提上去。

4.2 细小缺陷检测不到怎么办

另一个高频问题是“细小划痕检测不到”。无监督方法在这种场景天然吃亏,因为特征分辨率有限。你用的是WideResNet,多一层池化就少一块细节。PatchCore默认用layer2和layer3的特征图,patch size理论上是16x16像素,一条宽度只有2到3个像素的细划痕,在特征层面几乎被抹平了。

解决办法有三个思路。第一个,把输入分辨率从256提到512甚至768,让缺陷在特征图里占据更多像素。第二个,把layer1的特征也加进来,特征金字塔的底层信息保留更多纹理细节,代价是特征库容量变大,推理变慢。第三个,对特定区域做ROI检测,比如只对手机中框的侧边区域做高倍率放大检测,而不是整面一刀切。这三个办法可以叠加,我做过一个组合方案,把输入提到640、加入layer1、只检测固定ROI,细小划痕的召回率从77%提到了91%,同时推理耗时还在可控范围内。

需要提醒的是,如果缺陷本身在原始图像里就只有两三个像素宽,那靠任何算法都救不回来,这时候应该回头去调光学系统,加光源、加放大倍率才是根治办法。

4.3 产品换型和多型号共线怎么处理

工业现场几乎没有“一个型号吃到老”的产线。今天做A型号手机中框,明天换B型号平板后盖,后天可能是C型号的摄像头支架。形态差异大、表面材质不同,一个特征库打天下是不可能的。

我的方案是按型号维护多个特征库,运行时通过产线的工单系统自动切换。具体做法是给每个型号单独跑一遍特征库构建流程,存成独立目录。程序里维护一个型号到特征库路径的映射表,当产线PLC把当前工单号传给检测服务时,直接加载对应的特征库。切换的时间也就一两秒,对节拍没影响。

还有一种情况是同一型号不同批次的材质有细微差异。这种情况不建议频繁重建特征库,不然模型一直在抖,反而失去稳定性。更稳的做法是只增量追加特征样本,让记忆库缓慢演化,同时定期用一批固定的“金标准样本”回归测试误报率和检出率,防止指标悄悄恶化。

5. 工具链与工作流的“一次降维重构”

5.1 labelstudio:从标注主力变成验证配角

对外行来说,无监督方案好像彻底用不上标注工具了,实际用下来并不是这么回事。标注工具依然有用,但是角色发生了根本性变化。

拿labelstudio来说(热词里出现的数据标注工具,估计很多同行都用过),以前它是标注缺陷的主力,现在它在我这儿主要是干三件事。第一件:做正常样本的初筛。产线拍回来的素材,里面偶尔混着几件外观可疑的产品,我用labelstudio快速标记这些“可疑样本”,把它们排除出正常训练集。第二件:标注系统误报的案例。模型上线后每天都会积累一批NG图片,其中混着一大半其实是正常件。我把这些误报图拉进labelstudio,让工艺工程师确认“这确实不是缺陷”,然后就用这批数据做特征库增量更新的素材。第三件:处理那些无监督确实搞不定的疑难场景,做小样本的补充标注,喂一个轻量级分类模型做二次判断。

换句话说,标注的工作量没有消失,但被压缩到了一个很低的量级,同时标注的内容从“给缺陷画框”变成了“确认是否正常”。前者的单张成本是几分钟,后者往往扫一眼就能判断,效率完全不在一个量级。

5.2 无监督检测在3D点云场景的延伸

热词里那个“3D点云标注”我前面提过,三维空间标注一帧成本高到离谱,所以我在三维检测项目里更坚定地拥抱无监督思路。

3D点云的无监督检测逻辑和2D是相通的:从一批正常点云中提取局部特征,建立特征记忆库,推理时看测试点云中每个点的特征是否落在“正常邻域”内。我实际测试过用PointNet++提取局部特征、再构建核心特征库的路线,检测焊接飞溅和表面凹凸的效果不错。跟2D方案相比,3D有个天然优势——空间关系更清晰,不会像2D那样被透视重叠干扰。但3D点云也存在原始数据量大的问题,一帧点云几十万个点,特征提取耗时明显比2D长,所以更依赖降采样和区域裁剪来提速。

在辆车焊接质量检测这个具体场景里,我的做法是先对点云做刚性配准,把当前工件的点云对齐到标准工件坐标系,然后直接在标准坐标系下做残差分析外加特征检索,两路结果联合判断。这个方案不需要标注一套带缺陷的三维框,真正的实现一次“数据采集完就能跑”。

6. 关于无监督方案的边界和一些个人体会

任何技术都有玻璃天花板,无监督视觉检测也不例外。我自己使用一阵子下来最大的感受是:它在“异常检测”这个定位上非常好用,但你指望它一步到位做“缺陷分类”是不现实的。

如果你现场已经积累了大量带标签的缺陷数据,或者要求算法不但要判断“有没有问题”还要回答“是哪种问题”——划伤还是压伤?脏污还是氧化?那就别硬套纯无监督方案。更实际的做法是做两级级联:第一级用无监督模型做粗筛,把异常区域标出来;第二级用一个小型的监督分类模型,只对异常区域做分类判断。这样两级的好处是,第一级可以筛得非常宽,宁可多召回一些不确定区域,把漏检压到最低;第二级因为只处理小块区域、缺陷类别有限,标注工作量也小得多。

还有一个我个人一直在用的原则:无监督检测不是用来替代人工复检的,而是用来把人工复检的工作量压到最低。产线末端放一个无监督检测工位,OK件直接放行,NG件和橙色预警件(分数在阈值边界附近的)才流到人工复检台。这套组合拳用下来,复检人员从原来十几个人的班组,压缩到三个人轻松周转,而且漏检率反而因为集中注意力而下来了。

最后说回开头那个词,“即插即用”。我个人的理解是:不是指零配置的魔法,而是指从产线取数据到模型跑起来这段路径足够短。短到不需要标注团队介入,短到一个熟悉Python的工程师花一个下午就能搞定,短到深夜被产线电话叫起来的时候,你能很从容地在远程改一个阈值参数然后回去续觉。按这套流程走下来,我已经把几个项目的标注成本几乎砍到了零,而检测效果还比之前的监督方案更稳——这种事干过一次就很难回去了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询