首页/新闻资讯/正文详情

无监督缺陷检测系统实战:从良品图到产线部署的完整指南

发布时间:2026/9/27 1:18:13 来源:云帆数科 栏目:资讯中心
无监督缺陷检测系统实战:从良品图到产线部署的完整指南
简介这份资源面向希望入门工业视觉缺陷检测的开发者与算法学习者提供一套基于无监督学习的缺陷检测Python实现方案。核心思路借助相位变换phase by transform完成图像重构与异常判别无需大量缺陷样本即可定位产品表面异常适合数据稀缺场景下的快速验证与教学演示。压缩包共13个文件约7.02MB包含1个py脚本与1个ipynb笔记本作为主要代码载体另有5个jpeg、4个png图像用于展示原始图、模糊图、重构图、二值化图及检测结果对比并附README说明与LICENSE授权文件便于直接下载到本地运行调试。目前已有332人学习下载。读者可从中获得完整的无监督缺陷检测流程、相位变换重构思路、图像预处理与结果可视化方法以及可复用的notebook实验模板适合作为深度学习缺陷检测方向的入门参考与二次开发起点。1. 产线上没有缺陷样本怎么把无监督学习跑成一套缺陷检测系统做工业视觉的同行大概率都遇到过这种局面客户拉来一条新产线说“帮我做缺陷检测”然后你问要缺陷样本对方两手一摊——良品堆成山坏品一个没有。这不是刁难是真实产线的常态。缺陷本身是低概率事件等攒够几百张标注好的缺陷图产线早就换型了。基于无监督学习的缺陷检测系统要解决的就是这个死结只用良品图训练让模型学会“正常长什么样”任何偏离正常的区域都判为异常。它适合两类人——一类是被缺陷样本卡住、标注成本压垮的算法工程师另一类是手里有大量良品图、想快速上线第一版检测能力的产线技术负责人。这篇文章不讲论文综述只讲怎么从零把一套能跑、能调、能上线的无监督缺陷检测系统搭起来包括选型、训练、阈值标定和那些让我翻过车的坑。2. 无监督缺陷检测到底在学什么三条主流路线与选型理由2.1 重建式、嵌入式、合成式先搞清楚你该站哪一队无监督缺陷检测不是一种算法而是一类思路。落到工程上主流就三条路线选错了后面全是白干。第一条是重建式代表是自编码器和它的变体。核心逻辑是拿良品图训练一个网络让它学会压缩再还原良品图推理时喂进一张有缺陷的图缺陷区域因为训练时没见过重建误差会明显偏高误差图就是缺陷热力图。这条路线的优点是直观、可解释缺点是网络太强会把缺陷也“重建”出来太弱又对正常纹理还原不好平衡点很难找。第二条是嵌入式代表是 PatchCore、PaDiM 这类方法。思路是借一个在 ImageNet 上预训练好的骨干网络ResNet、WideResNet 都行提取特征把良品的特征块存成一个记忆库推理时算每个位置特征和记忆库的最近邻距离距离大就是异常。这条路线的工程优势非常明显不需要训练整个网络特征提取器冻结只需要构建和查询记忆库落地速度快对小样本极其友好。我目前手上大部分项目默认走这条。第三条是合成式用 GAN 或者扩散模型生成伪缺陷把无监督硬掰成有监督。优点是能利用判别式模型的高精度缺点是生成质量不稳定训练成本高调参玄学成分大产线赶工期的时候不建议碰。选型判断其实就三个问题良品图有多少张缺陷类型是否已知上线时间给多久良品图少于 200 张、缺陷类型未知、两周内要出 demo直接选嵌入式良品图上千张、缺陷偏结构性比如缺件、错位可以试重建式合成式留给研究场景。2.2 嵌入式方案的最小可跑通流程下面这段代码用 PyTorch 搭一个嵌入式检测的最小骨架骨干用预训练 ResNet18特征层取 layer2 和 layer3 拼接这是 PatchCore 的简化版思路。先跑通再谈优化。import torch import torch.nn as nn import torchvision.models as models import torchvision.transforms as T from torch.nn import functional as F class FeatureExtractor(nn.Module): def __init__(self): super().__init__() # 用 ImageNet 预训练权重冻结全部参数 backbone models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) self.stem nn.Sequential( backbone.conv1, backbone.bn1, backbone.relu, backbone.maxpool, backbone.layer1, backbone.layer2 ) self.layer3 backbone.layer3 for p in self.parameters(): p.requires_grad False # 关键冻结不训练 def forward(self, x): f2 self.stem(x) # 1/8 分辨率 f3 self.layer3(f2) # 1/16 分辨率 # 把 f3 上采样到 f2 尺寸后拼接兼顾语义和细节 f3_up F.interpolate(f3, sizef2.shape[-2:], modebilinear, align_cornersFalse) return torch.cat([f2, f3_up], dim1) # 特征图每个空间位置做自适应平均池化得到 patch 级特征 def embed_patches(feat_map, patch_size3): # feat_map: [B, C, H, W] - [B, H*W, C] pooled F.avg_pool2d(feat_map, kernel_sizepatch_size, stride1, paddingpatch_size//2) B, C, H, W pooled.shape return pooled.permute(0, 2, 3, 1).reshape(B, H * W, C)这段代码有三个参数决定成败。patch_size控制感受野设 3 意味着每个特征点看周围 3x3 的区域纹理细的产线比如布面、PCB调到 3 或 5结构大的比如铸件可以到 7。特征层选择上layer2 分辨率高、细节多但语义弱layer3 语义强但位置粗拼接是折中方案如果缺陷极小几个像素只保留 layer2 反而更稳。冻结参数这一行千万别漏一旦解冻小数据集上几个 epoch 就把预训练特征带偏了这是新手最常见的翻车点。2.3 记忆库构建与推理距离计算特征提出来之后嵌入式方案的核心是构建良品记忆库推理时算最近邻距离。全量存所有 patch 特征会爆内存工业上一般做 coreset 采样保留最具代表性的那部分。import numpy as np from sklearn.random_projection import SparseRandomProjection class MemoryBank: def __init__(self, n_proj128, coreset_ratio0.1): self.proj SparseRandomProjection(n_componentsn_proj, random_state0) self.coreset_ratio coreset_ratio self.bank None def fit(self, features): # features: [N, C] 所有良品 patch 特征 reduced self.proj.fit_transform(features) # 降维加速最近邻 n_keep max(1, int(len(reduced) * self.coreset_ratio)) # 贪心最远点采样让保留的特征尽量分散 idx self._greedy_coreset(reduced, n_keep) self.bank torch.from_numpy(reduced[idx]).float() return self def _greedy_coreset(self, X, k): n len(X) selected [np.random.randint(n)] dist np.linalg.norm(X - X[selected[0]], axis1) for _ in range(k - 1): nxt int(np.argmax(dist)) selected.append(nxt) dist np.minimum(dist, np.linalg.norm(X - X[nxt], axis1)) return np.array(selected) def score(self, query_features): # 返回每个 query patch 到记忆库的最近邻距离 q torch.from_numpy(self.proj.transform(query_features)).float() d torch.cdist(q, self.bank) return d.min(dim1).values.numpy()n_proj128是降维维度特征原始通道数可能是 384 或 512降到 128 能把最近邻查询速度提三到五倍精度损失通常在 1% 以内。coreset_ratio0.1表示只保留 10% 的良品特征一张 512x512 的图大概产生几千个 patch一万张良品图全存是几千万条采样后压到几百万条内存和查询都能接受。贪心最远点采样是 O(Nk)N 大时慢工程上可以先用随机采样粗筛再跑贪心或者直接用 k-center 的近似算法。推理时把距离图 resize 回原图尺寸就是缺陷热力图。3. 从良品图到上线数据、训练、阈值标定的完整落地链路3.1 数据采集与预处理良品图不是随便拍无监督方法对良品图的质量要求比有监督还高因为模型只见过这些图你喂什么它学什么。采集阶段有几条硬规矩。第一良品图必须覆盖产线的正常波动不同批次、不同光照、不同工位、不同季节的色差都要有否则模型会把正常波动当异常。我一般要求至少覆盖连续三天的生产数据每天抽 200 到 500 张。第二图像要配准。相机固定的话问题不大但如果工件在视野里位置会漂必须先做模板匹配或特征点对齐把工件摆正再送进模型否则模型学到的“正常”里混进了位置变化异常定位会糊成一片。第三分辨率要统一长边缩到 512 或 768 是常见做法太小丢细节太大推理慢。预处理流水线用 torchvision 写清楚别在训练和推理时用两套逻辑这是低级但高频的坑。train_tf T.Compose([ T.Resize((512, 512)), T.ToTensor(), T.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ]) # 推理时只做 Resize ToTensor Normalize绝对不要加随机增强注意推理流水线里不能有任何随机性RandomHorizontalFlip、ColorJitter 这类只在训练特征提取时用而且用了增强之后记忆库要重新构建。归一化参数用 ImageNet 的均值方差因为骨干是 ImageNet 预训练的这一步对齐能明显提升特征质量。3.2 训练与记忆库构建的实操命令嵌入式方案严格说没有“训练”只有特征提取和记忆库构建。但工程上我会把它包装成一个脚本方便复现和版本管理。# 目录结构约定 # data/good/ 良品图 # data/test/ 测试图含缺陷 # checkpoints/bank.pkl 记忆库输出 python build_bank.py \ --good_dir data/good \ --backbone resnet18 \ --layers layer2,layer3 \ --patch_size 3 \ --n_proj 128 \ --coreset_ratio 0.1 \ --batch_size 16 \ --out checkpoints/bank.pkl--layers指定用哪几层特征多一层拼接精度可能涨一点但内存和耗时也涨。--batch_size在显存够的前提下尽量大特征提取是纯前向batch 16 在 8G 显存上跑 512 分辨率没问题。构建完记忆库后拿测试集跑一遍输出每张图的异常分数和热力图人工看几张确认定位是否合理再进入阈值标定。3.3 阈值标定决定误报和漏报的那条线无监督检测没有天然的判别阈值异常分数是个连续值卡在哪直接决定误报率和漏报率。产线最怕的是误报一天报几百次假警操作员直接把系统关了。我的做法是拿一批确认的良品图跑推理统计异常分数的分布取 99.5 或 99.9 分位数作为阈值保证良品误报率控制在千分之几再拿已知缺陷图验证漏报如果漏报太高说明特征或 patch_size 需要调而不是简单降阈值。import numpy as np def calibrate_threshold(scores_good, scores_defect, target_fpr0.005): # scores_good: 良品图的图像级异常分数 th np.quantile(scores_good, 1 - target_fpr) recall (scores_defect th).mean() print(f阈值{th:.4f} 误报率{target_fpr} 缺陷召回{recall:.3f}) return thtarget_fpr是你能接受的误报率上限产线通常 0.005 到 0.01。如果算出来的召回低于 0.8别急着调阈值先回去看热力图——大概率是缺陷太小被 patch 平均掉了或者特征层选得太深。阈值标定不是一劳永逸换批次、换光源、换镜头都要重新标我一般把标定脚本做成定期任务每周用最新良品数据刷一次。4. 避坑与排查那些让无监督检测翻车的真实记录4.1 良品图里混进了缺陷模型直接学歪现象上线后模型对某类缺陷完全不报热力图一片干净。原因采集良品图时靠人工挑漏掉了少量带轻微缺陷的图模型把这些缺陷也当成“正常”学进了记忆库。解决良品图入库前跑一遍粗筛用第一版模型对候选良品图打分分数偏高的挑出来人工复核确认是良品再入库。这个自举过程跑两三轮记忆库会干净很多。4.2 光照变化被当成缺陷误报刷屏现象白天不报晚上换班后误报激增。原因训练良品图集中在白天采集夜间光照色温和亮度不同特征分布偏移模型把光照变化判成异常。解决良品图必须覆盖不同时段和光照条件如果补不齐数据在预处理里加光照归一化比如灰度世界白平衡或者 CLAHE把光照影响压下去再提特征。4.3 patch_size 设太小缺陷被切碎定位不准现象缺陷能报出来但热力图是零散的点连不成完整区域后处理很难框出缺陷。原因patch_size 太小每个特征点感受野不够缺陷区域内部特征差异被放大。解决把 patch_size 从 3 调到 5 或 7或者对异常分数图做高斯平滑再二值化。平滑核大小一般取 patch_size 的 2 到 3 倍。4.4 记忆库太大推理延迟拖垮产线节拍现象离线测试精度很好上线后单张推理要 800ms产线节拍要求 200ms。原因coreset_ratio 设太高记忆库几十万条最近邻查询是瓶颈。解决降 coreset_ratio 到 0.05 甚至 0.02同时把 n_proj 降到 64再不行就上 FAISS 做近似最近邻用 IVF 索引把查询压到毫秒级。精度会掉一点但节拍保住了。4.5 用测试集调阈值上线就崩现象离线评估 AUC 0.98上线一周误报率远超预期。原因阈值是在测试集上调的测试集和产线真实分布有差异过拟合了测试集。解决单独留一批产线实时数据做阈值标定测试集只用来评估模型能力不参与任何阈值决策。这条血泪经验值一个项目。5. 把无监督检测用稳的进阶技巧多尺度融合与在线更新单尺度特征在复杂缺陷上容易顾此失彼小缺陷要浅层高分辨率特征大缺陷要深层语义特征。我现在的默认配置是多尺度融合layer1、layer2、layer3 都提各自构建记忆库推理时把三个尺度的异常分数图归一化后加权求和权重按验证集表现调通常浅层权重 0.3、中层 0.4、深层 0.3。这样小缺陷靠浅层兜住大缺陷靠深层兜住实测比单尺度召回能涨 5 到 10 个点。def fuse_multiscale(score_maps, weights(0.3, 0.4, 0.3)): # score_maps: 三个尺度的异常分数图已 resize 到同一尺寸 normed [] for s in score_maps: s (s - s.min()) / (s.max() - s.min() 1e-8) normed.append(s) return sum(w * s for w, s in zip(weights, normed))另一个技巧是在线更新记忆库。产线运行过程中会不断产生新的良品图这些图代表了最新的正常分布。我一般每周挑一批低异常分数的实时图人工确认后增量加入记忆库同时按时间衰减淘汰最老的样本。这样模型能跟上产线的缓慢漂移不用频繁重训。更新时注意保留原始记忆库的一部分做锚点防止新数据把分布带偏。验证方法上别只看 AUC。产线关心的是固定误报率下的召回以及单张推理延迟。我习惯画一张误报率-召回曲线标出产线可接受的误报率位置看召回够不够再压测 1000 张图统计 P99 延迟。这两个数达标方案才算能上线。最后说个我自己的习惯每上一个新产线先花半天把良品图按批次、时段、工位分组每组抽几张跑推理看分数分布分布偏移大的组单独处理。这个动作看起来笨但能提前暴露八成以上的上线翻车。无监督检测没有后悔药数据阶段偷的懒上线后都会加倍还回来。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

《计算机工程》投稿全攻略:从选刊到录用的避坑指南
《计算机工程》投稿全攻略:从选刊到录用的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:18:13

电动汽车无线充电电磁暴露评估:从ICNIRP到仿真与实测
电动汽车无线充电电磁暴露评估:从ICNIRP到仿真与实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:18:07

ST-LINK SWD接线避坑指南:VCC与TMS接错也不烧芯片
ST-LINK SWD接线避坑指南:VCC与TMS接错也不烧芯片

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:18:07

2026最新html5做音乐网站报价避坑指南
2026最新html5做音乐网站报价避坑指南

2026最新html5做音乐网站报价避坑指南 备案流程一头雾水,是不是让你对着那几张表格就头大?别慌,这种焦虑在2026年依然普遍存在,尤其是当你决定用html5做音乐网站时,技术选型和合规备案的双重压力往往让人寸步难行。作为在华北市场摸爬… · 2026/9/27 3:54:44

RK3128A刷机深度指南:驱动、固件与eMMC兼容性三重验证
RK3128A刷机深度指南:驱动、固件与eMMC兼容性三重验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 3:54:44

F28388D EtherCAT从站开发实战:从硬件设计到TwinCAT联调
F28388D EtherCAT从站开发实战:从硬件设计到TwinCAT联调

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 3:54:38

工厂宿舍无线网络覆盖解决方案:高密度场景下的选型、拓扑与优化实践
工厂宿舍无线网络覆盖解决方案:高密度场景下的选型、拓扑与优化实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 3:54:38

Verilog集成脚本:Python+openpyxl构建数字设计自动化流水线
Verilog集成脚本:Python+openpyxl构建数字设计自动化流水线

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 3:54:32

PSP金手指CMF合集1215个:使用教程与避坑指南
PSP金手指CMF合集1215个:使用教程与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 3:54:32

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码