
做工业视觉这几年我几乎每年都要向新人解释一遍图像异常检测到底在做什么它和普通的图像分类有什么区别以及——当客户甩给你几百张只有正常样本的产线图片时你该从哪个算法下手。这篇文章就是一份清单。我把主流图像异常检测算法按技术路线分成几大类逐个说清楚核心思路、提出时间、开源地址GitHub 仓库名或搜索关键词再附上我在 MVTec AD 这类基准上实测的踩坑经验。适合刚要接触这个方向的研究生、准备做工业质检落地的工程师还有想在论文里快速选 baseline 的同学。说句实在话这个领域更新速度极快但真正能稳定复现、敢上线跑的方法就那么几条线。你先把谱系捋清楚后面看论文、选模型都不慌。那么开始。1. 先搞懂问题异常检测在检测什么方法谱系怎么选1.1 异常检测和图像分类的核心区别图像异常检测Anomaly Detection要解决的是只给一批正常样本让你判断一张新图是否偏离了正常分布。它跟图像分类最大的区别在于训练数据极度不均衡甚至完全没有异常样本可用目标也不是识别出这是哪一类缺陷而是发现这个不对劲。在工业质检里一个磁性材料表面可能因为划痕、凹坑、脏污、氧化产生几十种不同外观的缺陷你很难收集全所有坏样本更别说逐一标注。所以这类问题通常用半监督或无监督的方式建模训练阶段只用正常样本推理阶段用重建误差、特征距离、概率密度或者分类置信度来打分。分数越高越可能是异常。这个设定决定了整套算法的设计思路也决定了你不能拿一个普通分类网络硬套。1.2 方法谱系一图流与选型逻辑我习惯把方法按思考方式的演变分成几批后面每章详细讲技术路线代表方法提出时间核心动作单类分类One-Class SVM、SVDD、Deep SVDD2001-2018学一个包住正常样本的边界重建式AE、VAE、MemAE2013-2019重建误差越大越异常生成式AnoGAN、GANomaly2017-2018用 GAN 在潜在空间做映射特征嵌入PaDiM、SPADE、PatchCore、SimpleNet2020-2023在预训练特征空间里比距离蒸馏/流/TransformerSTFPM、RD4AD、FastFlow、CFlow2021-2022特征一致性或密度建模多模态AnomalyCLIP2023-2024文本引导的开放集异常检测选型逻辑其实很直观样本量少、只想快速验证成果优先特征嵌入类异常形态复杂且需要像素级定位重建式和蒸馏类更常见如果你要在边缘设备上跑、对延迟很敏感就别碰流模型和重参数化的大模型老老实实上 PatchCore 或者 SimpleNet。后面的章节都是按这个逻辑展开的。2. 经典基线One-Class SVM、SVDD 与 Deep SVDD 的适用范围2.1 One-Class SVM 与 SVDD2001 年的老方法为什么还在被对比One-Class SVM 是 Schölkopf 等人在 2001 年提出的SVDD 是 Tax 和 Duin 在 2004 年提出的。核心思想一句话找一个能把所有正常样本圈起来的边界测试点落在边界外面就算异常。One-Class SVM 的做法是把数据映射到高维空间后最大化原点与分离超平面之间的距离用 ν 参数控制允许出错的样本比例SVDD 则是找一个紧致的超球把正常样本尽量包进去最小化球半径。这两个方法直接作用在原始像素上效果很差。我试过把 224×224 的灰度图拉平成一维向量喂给 scikit-learn 的 OneClassSVM误报率高到让人怀疑人生。图像是高维连续信号像素级欧氏距离根本描述不了形状是不是正常这种语义。正确做法是先用 HOG、SIFT 或者预训练 CNN 的中间特征把图像压缩到几百上千维再喂给它们。在特征维度上这两个算法非常快、非常稳适合当 baseline 兜底。scikit-learn 里 OneClassSVM 直接可用SVDD 可以在 GitHub 上搜 svdd 或找 DD_toolbox 相关实现。2.2 Deep SVDD2018 年的深度学习版单类分类2018 年 Ruff 等人在 ICLR 上提出 Deep SVDD思路是让神经网络把正常样本映射到一个以固定中心 c 为圆心的小超球里训练时最小化正常样本到中心的平均距离。GitHub 上有官方 PyTorch 实现 lukasruff/Deep-SVDD-PyTorch 代码结构很干净适合研究。这个方法的坑非常多。论文和作者开源代码里明确提到了几条网络最后一层不要加 bias激活函数尽量用有界函数否则会出现退化解——所有输入被映射到同一个点。中心 c 在训练前用一次前向传播的平均特征固定下来后面不要跟着更新不然训练会飘。我实际跑下来的体会是Deep SVDD 对特征质量极其敏感直接用预训练 ResNet 的特征当输入比端到端从像素学效果好很多。如果你要发论文、比 baselineDeep SVDD 几乎每个新方法都会带上但要上产线它很少是首选。3. 重建式方法Autoencoder、AnoGAN 到记忆模块的三次迭代3.1 Autoencoder / VAE简单但容易重建得比输入还干净自编码器思路很直白把图像压缩到低维瓶颈再解压重建网络只在正常样本上训练。测试时正常图像重建误差小异常图像重建误差大。VAE 是 2013 年 Kingma Welling 提出的加了隐变量的高斯先验重建更平滑。但马上你会发现一个尴尬现象异常图像也能被重建得很好。原因很简单神经网络有很强的泛化能力对没见过的新模式也不是完全不会重建。我遇到过最离谱的案例一张有很明显裂纹的图像AE 输出把它修得整整齐齐裂纹消失重建误差反而比某些正常样本还小。这就是重建得比输入还正常的幻觉问题。后续改进都在给重建过程加限制MemAE2019ICCV用记忆模块强制瓶颈只能通过查字典的方式组合正常模式MNAD2020CVPR进一步用图记忆和邻域约束避免记忆模块退化。这些在 GitHub 上都能搜到官方或高星实现。但说句实话重建式方法在工业场景里误报率普遍偏高现在新项目里我很少把它作为主力方案。3.2 AnoGAN 与 GANomalyGAN 系的开创与退场AnoGAN 是 2017 年提出、2018 年发表在 CVPR 的工作。它反着用 GAN先把 GAN 在正常样本上训练好测试时在潜在空间里迭代寻找到一个 z使得 G(z) 生成的图像与输入最接近然后用重建损失和判别器分数共同打分。官方开源在 tSchlegl/AnoGAN 。但迭代寻优意味着推理速度很慢做一次检测要几百次梯度更新。于是 GANomaly2018ACCV改为训练时直接学一个编码器作为从图像到潜在空间的投影再配判别器逼迫重建结果保持真实结构是 Encoder-Decoder-Encoder 三段官方实现见 samet-akcay/ganomaly 。这两个方法在论文里重要但实际落地性价比不高。GAN 训练本来就摇摇晃晃异常检测又要用重建差异做信号两个不稳定的东西叠在一起经常出现训练时 loss 还在降测试时分数却乱了的情况。我在一个半导体表面项目上试过 GANomaly调了两周最终效果还不如一个没怎么调参的 PatchCore。现在论文里 GAN 系基本只当 baseline 出现。3.3 重建式方法的共同软肋归纳一下一是网络泛化能力太强导致异常被修复二是训练目标和异常分数之间隔了一层重建质量而重建质量跟视觉显著性并不等价三是对图像分辨率、噪声、光照变化太敏感工业现场一点打光抖动都会让重建误差升高误报就来了。后面几年大家逐渐意识到与其费劲跟网络泛化能力作斗争不如换个思路——不再重建像素而是利用预训练模型对正常图像的语义特征做建模。这直接催生了第 4 章那批方法。4. 特征嵌入路线PaDiM、PatchCore 到 SimpleNet 的落地首选4.1 PaDiM 与 SPADE用预训练特征给异常打分2020 年的 PaDiM 把预训练 CNN 特征引入异常检测。它把输入图像切成 patch用固定特征提取器Wide ResNet-50 的中间层为每个 patch 提取特征向量然后对每个 patch 位置分别用多元高斯分布建模正常特征异常评分用马氏距离计算。复现友好代码在 gudovskiy/PaDiM-anomaly-detection 。2021 年的 SPADE 换成了最近邻思路把正常样本的所有 patch 特征摆成一个档案库测试样本的每个 patch 特征去库里找最近邻距离大的就是异常。可以理解成一种非参数的密度估计。2022 年 PatchCore 把这条路推到极致。4.2 PatchCore为何成为默认首选PatchCoreCVPR 2022官方仓库在 amazon-science/patchcore-inspection 把全量特征做记忆库改为用 coreset 采样抽取有代表性的子集既减少存储又提高检索速度推理时做 K 近邻距离打分。我日常项目的基准首选就是它理由有三个。第一训练成本极低——只要跑一遍预训练网络的前向把正常图像的特征存下来再做一次 coreset 采样整个过程在一张 3090 上处理几百张图只要几分钟对需要频繁迭代的场景太舒服了。第二它在 MVTec AD 的 15 个类别上平均图像级 AUROC 能到 99% 左右像胶囊、螺纹、皮革这类让很多方法翻车的难类别也不太容易出问题。第三它的推理逻辑很直观距离越远越异常客户要解释时直接把最近邻正常图像贴出来对方一眼就懂。实操中我会做几件事输入分辨率拉到 320 以上patch size 根据缺陷尺度调整coreset 采样比例在 1% 到 10% 之间调如果异常像素很小改用特征金字塔的中间层而不是只用最后一层语义特征。4.3 SimpleNet轻量化替代方案PatchCore 很强但推理时要维护一个记忆库做 K 近邻搜索对边缘部署是个负担。SimpleNet2023的思路是把它简化成判别任务在预训练特征后面挂一个线性适配器把特征投影到低维空间同时用判别头学习正常特征该长什么样异常分数就是判别头输出的置信度。代码在 donaldrr/SimpleNet 。我实测的感受训练时间比 PatchCore 长一些毕竟有真正的反向传播但推理更快、显存占用低在纹理类数据上跟 PatchCore 不相上下在物体类上略输一点点。如果目标设备是低配 CPU 板或工控机我会优先考虑 SimpleNet。5. 进阶路线蒸馏、归一化流与多模态怎么选5.1 师生蒸馏STFPM 与 RD4AD蒸馏类方法的基本框架一个预训练教师网络固定不动一个结构相似的学生网络去模仿它的中间层特征。训练时只用正常样本正常区域师生特征差异被压得很小推理时异常区域没在训练里见过学生模仿不出来差异就大。这个设定天然适合像素级定位。STFPM 是 2021 年提出的核心是多层级特征金字塔的匹配把各尺度差异纳入异常分数GitHub 上搜 stfpm 能找到官方实现。RD4AD2022CVPR做了两点改进把多个教师模型的中间特征聚合用反向蒸馏结构迫使模型抓住全局上下文。官方仓库在 plutions/rd4ad 。实操上有几条经验。教师网络必须冻结dropout 都要关掉不然特征分布会抖动。学生网络容量不要太小也不要太大太小学不会太大又会把异常区域也模仿得像模像样。输入归一化手段与训练时保持完全一致——我在这里栽过一次预处理从 ImageNet 均值换成全局均值AUROC 直接掉 8 个点。5.2 归一化流FastFlow 与 CFlow归一化流做异常检测的思路用可逆变换把视觉特征映射到标准高斯分布正常样本概率密度高异常样本落在低密度区域。FastFlow2021把预训练 CNN 的特征送入 2D 流模型拟合GitHub 上搜 fastflow anomaly detection 能找到官方实现。CFlowWACV 2022进一步引入条件归一化流以 patch 位置为条件做逐位置概率建模官方在 gathierry/CFlowAD 。流模型的优势是理论完备、能给出密度意义上的分数训练也比较快但参数量和计算量都偏大推理时要做多次可逆变换对部署不友好。我在服务器上做离线检测用它没问题要做实时视频流就果断放弃。另外流模型对特征提取器选择很挑剔换不同预训练骨干性能波动很大上线前一定要做骨干消融。5.3 Transformer 与多模态跨领域泛化的新选项近两年 Transformer 类方法也不少比如把 ViT 的 token 当 patch 特征做最近邻的方案以及统一检测、定位、分割的版本。但在 MVTec AD 这类数据集上ViT 相比强 CNN 并没有压倒性优势参数量还上去了。用 Transformer 的真正价值在异常种类非常复杂、需要跨领域泛化的场景。值得关注的是多模态路线。AnomalyCLIPICLR 2024把 CLIP 的文本-图像对齐能力引入异常检测通过可学习提示适应正常/异常这种开放语义零样本就能取得不错的成绩GitHub 上 zqfang/AnomalyCLIP 有开源。如果你的项目没有固定缺陷种类或者客户动不动就换产品、换材质这类开放集方法值得关注。我的选型经验是异常形态固定、流程稳定PatchCore/SimpleNet 够用要覆盖什么都可能坏的场景再上多模态。6. 动手实践数据集、评估指标与部署取舍6.1 基准数据集与评估指标怎么用几乎所有人最先接触的都是 MVTec AD2019 年提出的工业异常检测基准包含 15 类物体和纹理同时有图像级异常标注和像素级异常掩码。官方地址在 MVTec 官网的数据集页面GitHub 上也有大量配套代码可以直接加载。另外 BTAD2021、VisA2021-2022逐渐成为常见补充基准。评估指标一定要说清楚。图像级 AUROC 衡量这张图有没有异常的判别能力像素级 AUROC 衡量异常在哪的定位能力。很多方法图像级刷得很高像素级却一塌糊涂而工业项目里两个往往都要。还有 AP 和 F1-max当正负样本比例不均时比 AUROC 更能反映真实可用性。我建议提交结果时把每个类别的单独指标一起贴出来只看平均分很容易被个别类别拉偏。6.2 训练与推理的实操建议我的典型处理流程可以直接照抄。图像统一尺寸常见是 256 或 288 的方形输入纹理类可以小一点微小缺陷类要往 320 以上走。固定预训练特征提取器只做特征提取或轻量微调。确定异常分数的融合方式PatchCore 直接用 KNN 距离蒸馏类把多个层级差异做加权和权重可以用验证集搜索。评估时做 5 次不同随机种子报均值和方差避免被一次运气好糊弄过去。几个亲测有效的细节图像归一化必须严格一致不要盲目上数据增强旋转和颜色抖动对正常样本分布影响很大可能凭空造出伪异常类别不平衡时需要重采样但不要让异常样本参与训练否则会引入泄漏。下面这段代码是评估阶段最常用的我每次都直接复制from sklearn.metrics import roc_auc_score y_true [...] # 0 表示正常1 表示异常 y_score [...] # 模型输出的异常分数越大越异常 img_auc roc_auc_score(y_true, y_score) print(fImage-level AUROC: {img_auc:.4f})6.3 部署形态怎么取舍预算有限用一张普通 GPU 做产线抽检PatchCore 或 SimpleNet 足够。要接高速摄像头、CPU 工控机必须把特征提取器换小比如 EfficientNet 或轻量 ViT并接受一点 AUROC 下降。要求像素级框出缺陷位置时蒸馏类方法定位更稳PatchCore 的分割能力相对弱一点。有两次交付经验供参考一次是 7 类磁性材料外观检测选了 PatchCore ResNet5030 万张图的特征库用 coreset 压到 3 万单图推理 30ms 以内一次是半导体晶圆表面缺陷像素极小PatchCore 不行最后换成 RD4AD 的多尺度定位方案。7. 踩坑实录常见问题与排查速查表7.1 我踩过的三个真实坑第一个坑是光照不一致。训练集和测试集打光角度稍有偏差PatchCore 分数整体漂高误报率飙升。解决办法收集数据时严格固定打光同时用直方图匹配或 CLAHE 做预处理把光照影响压下去。第二个坑是干净异常。有些样本明明有缺陷但特征距离很小因为缺陷本身与正常纹理差异不大。增加层数或换特征提取器效果一般最有效的是把 patch 尺寸调小配合像素级标注做局部特征对齐。第三个坑是评估被泄漏污染。有人为了让特征库更丰富把测试集的正常图也加进去建库AUROC 看着 99.9%实际上线直接翻车。特征库只能来自训练集这是红线。7.2 常见问题速查表现象可能原因排查/解决训练正常但测试误报高光照、分辨率、归一化不一致统一预处理流程检查推理前处理代码图像级 AUROC 高但定位差只用高层语义特征加入浅层特征金字塔或换蒸馏类方法PatchCore 推理内存不够记忆库太大调小 coreset 采样比例或改用 SimpleNet某几个类别分数特别低数据特征分布差异大分类别调 patch size别共享一套参数重建式方法图像被修复网络泛化过强加记忆模块或改用特征距离打分这张表我每次评审前都会过一遍基本能拦住 80% 的翻车。最后说点题外话。图像异常检测这行最容易犯的错不是模型不先进而是忘了正常本身是动态的——产线换一种光源、换一批原材料正常分布就变了。所以无论你选哪个算法一定要在工程里把数据更新和模型回滚机制做进去定期用新正常样本重估特征库或重训判别头。我的个人习惯是每个月跑一次分布漂移体检看看特征库中心到底挪没挪。另外刚开始接触这个领域的朋友我建议第一周先别管新论文把 PatchCore 和 SimpleNet 复现一遍跑通 MVTec AD 的数据加载到指标计算闭环后面再谈别的。把地基打好比追任何新算法都值。