PatchCore 异常检测算法的原理
1. 算法概述与核心思想
PatchCore 是一种基于 内存库 和 局部特征 的异常检测与定位方法。它在 2021 年被提出,并在当时的 MVTec AD 等公开数据集上达到了最先进的性能。
它的核心思想非常直观:
一个正常的物体,其所有局部区域的视觉特征都应该与训练集中大量正常样本的对应局部特征相似。如果某个局部区域的特征在正常样本的记忆库中“找不到邻居”,那么这个区域就很可能是异常的。
简单来说,PatchCore 为正常样本建立了一个非常庞大且具有代表性的 “正常模式记忆库”。在测试时,它会将待测图像的每个局部特征与这个记忆库进行比对,通过计算相似度来发现异常。
2. 关键动机与核心问题
在 PatchCore 之前,已经有很多基于深度特征的异常检测方法,但它们普遍存在两个问题:
- 全局特征 vs. 局部缺陷:很多方法使用整张图像的全局特征向量进行比对。但对于微小的、局部的缺陷(如划痕、斑点),全局特征的变化可能非常微小,容易被淹没在正常的整体结构信息中,导致漏检。
- 预训练模型的偏差:直接在 ImageNet 上预训练的模型,其特征可能并不完全适用于特定工业领域的纹理和结构。直接使用高层特征可能会引入与任务无关的偏差。
PatchCore 的设计就是为了解决这两个核心问题:
- 针对问题1:它摒弃了全局特征,专注于 极致的局部特征(Image Patches)。
- 针对问题2:它使用 中层网络特征,这些特征既保留了足够的空间和细节信息,又具备一定的语义抽象能力,非常适合用于描述局部区域。
3. 算法详细原理与步骤
PatchCore 的流程可以分为两个主要阶段:离线构建记忆库 和 在线异常检测。
阶段一:离线构建正常样本的记忆库
这一步是整个算法的基础,只在正常的训练集上进行。
步骤 1: 提取局部特征图
- 输入:所有正常的训练图片。
- 网络 backbone:使用一个在 ImageNet 上预训练的卷积神经网络(如 WideResNet-50),但不进行微调。
- 提取层级:并非使用最后一层的输出,而是选择 网络的中层特征层。通常选择多个层(如
layer2和layer3),将它们提取的特征图进行融合。这样做的好处是:- 中层特征 具有较高的空间分辨率,能保留更多的细节和位置信息,这对于精确定位小缺陷至关重要。
- 相比底层特征,它又有一定的语义信息,抗噪声能力更强。
- 输出:对于每一张正常训练图片,我们得到一个三维的 特征图
F ∈ R^(C×H×W)。这个特征图可以看作是H×W个C维的特征向量,每个向量都对应原始图像上的一个局部区域(Receptive Field)。
步骤 2: 构建 Patch-Feature Memory Bank
- 核心操作:将上一步得到的所有训练图片的特征图
F中的 每一个空间位置上的 C 维特征向量 都取出来。 - 为什么叫 “Patch”:每个特征向量都对应原始图像上的一个图像块,因此这些特征向量被称为 “Patch Features”。
- 结果:最终,我们得到一个巨大的集合,称为 记忆库 M:
M = {m₁, m₂, m₃, ..., m_N}
其中,N = (训练图片数量) × H × W,m_i ∈ R^C。
这个记忆库M本质上是一个巨大的矩阵,它密集地、无遗漏地记录了所有正常训练样本中所有可能的局部外观模式。
步骤 3: 核心集子采样
- 问题:直接使用完整的记忆库
M会非常庞大(可能包含数百万个特征向量)。在测试时与如此庞大的库进行最近邻搜索,计算成本会非常高,无法满足实时需求。 - 解决方案:PatchCore 采用了一种称为 Coreset Selection(核心集选择) 的算法。其目标是从庞大的
M中选取一个很小的子集M_Coreset,使得这个子集能够最大限度地保留原始记忆库的分布和代表性。 - Coreset 算法:通常使用一种迭代的贪心算法(如 k-Center Greedy 算法,也称为 Minibatch K-Means++ 的初始化步骤)。该算法会尽量选择那些能“覆盖”整个特征空间的特征向量作为代表,避免冗余。
- 最终记忆库:经过 Coreset 采样后,我们得到一个规模小得多但代表性极强的记忆库
M_Coreset。这大大加速了后续的推理过程,是 PatchCore 能实现高效检测的关键。
阶段二:在线异常检测与定位
当有一个新的测试图像需要判断时,执行以下步骤:
步骤 1: 提取测试特征
- 使用和训练阶段完全相同的 Backbone 和特征层,提取测试图片的特征图
F_test ∈ R^(C×H×W)。
步骤 2: 局部最近邻搜索
- 对于测试特征图
F_test上的每一个空间位置(i, j),取其对应的 C 维特征向量f_{i,j}。 - 在缩减后的记忆库
M_Coreset中,为f_{i,j}寻找最相似的 K 个近邻(通常 K=1,即最近邻)。 - 计算它们之间的 距离(通常使用余弦距离或欧氏距离的倒数来衡量相似度)。这个距离反映了该测试局部特征与“正常模式”的偏离程度。
s_{i,j} = distance(f_{i,j}, NN(f_{i,j}, M_Coreset))
距离越大,说明该局部区域越异常。
步骤 3: 生成异常分数图
- 将所有空间位置
(i, j)上计算得到的距离值s_{i,j}组合起来,形成一个二维的 异常分数图S_map ∈ R^(H×W)。 - 这个分数图
S_map已经粗略地定位了图像中哪些区域可能是异常的。
步骤 4: 后处理与结果输出
- 异常定位:将
S_map上采样到原始测试图像的尺寸,即可得到像素级的异常分割图。分数高的区域即为疑似缺陷区域。 - 图像级异常分数:对整个图像计算一个总的异常分数。通常有两种简单有效的方法:
- 取最大值:
Score_image = max(S_map)。这种方法对即使是很小的异常也非常敏感。 - 取Top-K均值:
Score_image = mean(top-k values in S_map)。这种方法对大面积的异常更鲁棒。
- 取最大值:
- 最终决策:将
Score_image与一个预设的阈值进行比较,超过阈值则判定该测试图像为异常图像。
4. 为什么 PatchCore 如此有效?—— 优势总结
- 对局部缺陷高度敏感:通过比对局部特征,即使是微小的缺陷,只要其特征与记忆库中所有正常模式都不匹配,就能被有效地检测出来。
- 无需模型微调:直接利用强大的预训练模型特征,避免了在小数据集上微调可能导致的过拟合问题,也简化了训练流程。
- 极强的代表性记忆库:通过密集采样和中层特征,记忆库
M几乎涵盖了所有可能的正常模式变体。Coreset 子采样在保证效率的同时,最大限度地保留了这种代表性。 - 简单而强大:算法的核心就是最近邻搜索,没有复杂的概率建模或神经网络训练,方法非常直观且稳定,不容易出现难以调试的失败情况。
总结
PatchCore 的成功在于它回归了一个朴素而强大的理念:通过建立一个详尽且高效的“正常记忆”,然后将待测样本的每个部分与这个记忆进行最直接的比对来发现异常。它通过 “中层局部特征” 和 “核心集记忆库” 这两个关键技术,完美地平衡了检测精度、定位能力和推理速度,成为了工业异常检测领域一个非常重要的基准算法。
