深入 PaDiM:基于补丁分布建模的异常检测与定位 —— Anomalib 源码级实战指南
2026/9/17 18:51:15 网站建设 项目流程

深入 PaDiM:基于补丁分布建模的异常检测与定位 —— Anomalib 源码级实战指南

【免费下载链接】anomalibAn anomaly detection library comprising state-of-the-art algorithms and features such as experiment management, hyper-parameter optimization, and edge inference.项目地址: https://gitcode.com/GitHub_Trending/an/anomalib

PaDiM(Patch Distribution Modeling)是异常检测领域极具代表性的分割级(Segmentation)算法,它不依赖端到端训练,而是通过预训练 CNN 提取多尺度特征、为每个图像补丁拟合多元高斯分布,再以马氏距离完成异常评分与像素级定位。本文以 Anomalib 仓库中 PaDiM 官方文档 为核心骨架,结合 torch_model.py、lightning_model.py、anomaly_map.py 等源码与基准测试数据,系统讲解其算法原理、配置参数、训练推理流程与工程实践要点。读完本文,你将掌握在 Anomalib 中一键训练 PaDiM、调整骨干网络与特征维度、理解异常图生成链路,并复现 MVTec AD 基准结果的全部技能。

一、算法核心原理:补丁分布建模

PaDiM 的核心思想是:正常样本在每个空间补丁位置上的特征向量服从一个多元高斯分布,测试时通过与参考分布的马氏距离偏离程度来度量异常。

其整体流程分为三个关键阶段(对应 README 中的 Description):

  1. 多尺度补丁特征提取:图像被拆分为补丁,使用预训练 CNN 特征提取器从多个不同层抽取每个补丁的嵌入向量。由于不同卷积层对应不同感受野与语义层级,将多层激活向量拼接后,嵌入向量同时携带了细粒度(低级纹理)与全局(高级语义)上下文信息。
  2. 随机降维:拼接后的嵌入向量可能包含冗余信息,因此通过随机选择(random selection)进行维度缩减,只保留固定数量的特征维度。
  3. 逐补丁高斯建模:对整个训练批次,为每个补丁嵌入生成一个多元高斯分布,所有补丁的高斯参数组合成一个高斯参数矩阵(mean + inverse covariance)。

推理阶段:使用马氏距离(Mahalanobis distance)为测试图像的每个补丁位置打分,打分时直接使用训练阶段为该补丁计算的协方差矩阵的逆。所有补丁的马氏距离构成异常图(anomaly map),分数越高代表该区域越可能异常——这就是 README 中"Model Type: Segmentation"(像素级分割定位)的含义。

二、源码级原理剖析:特征提取到异常图

2.1 多层级特征拼接与随机降维(generate_embedding

在 torch_model.py 中,generate_embedding方法实现多层级特征的拼接与降维:

  • layers[0](分辨率最高的层)的特征图为基准;
  • 后续层特征图通过F.interpolate(..., mode="nearest")上采样到与首层一致的空间尺寸;
  • 沿通道维torch.cat拼接所有层特征;
  • 用预先随机生成的索引idx通过torch.index_select完成维度子采样。

这里的idx在模型初始化时通过torch.randperm(self.n_features_original)[: self.n_features]生成,并注册为 buffer(见 torch_model.py),源码注释明确说明"Since idx is randomly selected, save it with model to get same results"——随机索引会随模型保存,保证推理结果可复现

以 ResNet-18 骨干、layers=["layer1", "layer2", "layer3"]、输入 224×224 为例,三层特征形状分别为[B, 64, 56, 56][B, 128, 28, 28][B, 256, 14, 14],拼接后原始特征维度为 448,再按n_features=100随机保留 100 维(此示例来自 torch_model.py 的 docstring)。

2.2 逐补丁多元高斯拟合(MultiVariateGaussian

训练阶段,每个 batch 的嵌入被收集进memory_bank,训练结束后调用fit()一次性拟合高斯分布(见 torch_model.py),随后清空 memory bank 以释放显存。

高斯拟合的核心实现在 multi_variate_gaussian.py:

  • 计算每个空间位置(共 H×W 个补丁)沿 batch 维的均值mean,形状为(C, H*W)
  • 为每个补丁位置估计协方差矩阵(实现与numpy.cov等价),并在对角上添加0.01正则项保证可逆;
  • 整体协方差再叠加1e-5 * I进一步数值稳定化,最后用torch.linalg.inv求逆得到inv_covariance,形状为(H*W, C, C)
  • 特别地,当设备为 MPS(Apple Silicon)时,求逆操作会回退到 CPU 执行再拷回设备(见 multi_variate_gaussian.py)。

2.3 推理:马氏距离 → 上采样 → 高斯平滑(AnomalyMapGenerator

推理时由 AnomalyMapGenerator 完成异常图生成,对应 README 中"矩阵化马氏距离形成异常图"的描述,具体三步:

  1. compute_distance:实现论文 Section III-C 的公式 (2),计算测试补丁嵌入与参考分布的马氏距离(delta^T · inv_cov · delta)后开方并clamp(0),得到(B, 1, H, W)的原始分数图(见 anomaly_map.py);
  2. up_sample:通过F.interpolate(..., mode="bilinear")将分数图上采样回原始输入图像尺寸(见 anomaly_map.py);
  3. smooth_anomaly_map:使用GaussianBlur2d进行高斯平滑降噪,平滑核标准差sigma默认值为 4,核尺寸由2 * int(4.0 * sigma + 0.5) + 1计算(见 anomaly_map.py)。

最终在 forward 中,异常图取空间维最大值torch.amax作为图像级异常分数pred_score,与异常图一起封装进InferenceBatch返回。

三、模型参数详解与默认值

PadimLightning 模块(见 lightning_model.py)的构造参数如下:

参数类型默认值说明
backbonestr"resnet18"预训练骨干网络名称,常用resnet18wide_resnet50_2等 timm 模型
layerslist[str]["layer1", "layer2", "layer3"]抽取特征的骨干层名称列表,按分辨率从高到低排列
pre_trainedboolTrue是否使用预训练骨干权重
n_featuresint | NoneNone降维后保留的特征数;论文默认值见下表
pre_processor/post_processor/evaluator/visualizermodule | boolTrueAnomalib 标准预处理、后处理、评估器与可视化组件开关

关键注意n_featuresNone时自动使用论文默认值(定义于 torch_model.py):

骨干网络默认 n_features
resnet18100
wide_resnet50_2550

若使用其他骨干网络,则必须显式指定n_features,否则抛出ValueError;同时要求0 < n_features <= n_features_original(原始特征总维数),否则同样报错(见 torch_model.py)。

从源码结构还可以推断以下行为特征:

  • 无需传统训练configure_optimizers直接返回空(lightning_model.py),training_step只做特征抽取并返回一个占位 dummy loss(lightning_model.py),真正"学习"发生在fit()对高斯参数的估计;
  • 默认 trainer 参数max_epochs=1val_check_interval=1.0num_sanity_val_steps=0devices=1(仅支持单 GPU),见 lightning_model.py;
  • 学习类型LearningType.ONE_CLASS,属于单类别学习范式(lightning_model.py);
  • 继承自MemoryBankMixin:与 PatchCore 等共享"特征记忆库 + 事后拟合"的工程模式。

四、快速上手:三种使用方式

4.1 CLI 一键训练(README 官方命令)

在仓库根目录执行:

anomalib train --model Padim --data MVTecAD --data.category <category>

其中<category>替换为 MVTec AD 数据集的类别(如bottlecarpettransistor等)。README 中标注"Model Type: Segmentation",即该模型同时输出图像级分数与像素级异常图。

4.2 配置文件方式(推荐用于复现实验)

模型配置参考 padim.yaml:

model: class_path: anomalib.models.Padim init_args: layers: - layer1 - layer2 - layer3 backbone: resnet18 pre_trained: true n_features: null

数据配置参考 mvtec.yaml(test_split_mode: from_dirval_split_mode: same_as_test等字段可按需调整):

class_path: anomalib.data.MVTecAD init_args: root: ./datasets/MVTecAD category: bottle train_batch_size: 32 eval_batch_size: 32 num_workers: 8 test_split_mode: from_dir test_split_ratio: 0.2 val_split_mode: same_as_test val_split_ratio: 0.5 seed: null

组合使用:

anomalib train --config examples/configs/model/padim.yaml --data examples/configs/data/mvtec.yaml

4.3 Python API(Engine 训练与预测)

来自 lightning_model.py 的官方示例:

from anomalib.models import Padim from anomalib.data import MVTecAD from anomalib.engine import Engine # 初始化模型与数据 datamodule = MVTecAD() model = Padim( backbone="resnet18", layers=["layer1", "layer2", "layer3"], pre_trained=True, ) engine = Engine() engine.train(model=model, datamodule=datamodule) predictions = engine.predict(model=model, datamodule=datamodule)

模型也可通过get_model("Padim")或带init_args的配置字典动态实例化,相关用法在单元测试 test_model_utils.py 中有完整覆盖(包括传入backbone: wide_resnet50_2与完整class_path的两种注册方式)。

五、MVTec AD 基准结果

以下结果均由 seed42收集(与 README 保持一致)。图像级 AUC 与 F1 反映"图像是否异常"的判别能力,像素级 AUC 反映"异常区域定位"能力。

5.1 Image-Level AUC(图像级 AUC)

AvgCarpetGridLeatherTileWoodBottleCableCapsuleHazelnutMetal NutPillScrewToothbrushTransistorZipper
ResNet-180.8910.9450.8570.9820.9500.9760.9940.8440.9010.7500.9610.8630.7590.8890.9200.780
Wide ResNet-500.9500.9950.9421.00.9740.9930.9990.8780.9270.9640.9890.9390.8450.9420.9760.882

5.2 Pixel-Level AUC(像素级 AUC)

AvgCarpetGridLeatherTileWoodBottleCableCapsuleHazelnutMetal NutPillScrewToothbrushTransistorZipper
ResNet-180.9680.9840.9180.9940.9340.9470.9830.9650.9840.9780.9700.9570.9780.9880.9680.979
Wide ResNet-500.9790.9910.9700.9930.9550.9570.9850.9700.9880.9850.9820.9660.9880.9910.9760.986

5.3 Image F1 Score(图像级 F1)

AvgCarpetGridLeatherTileWoodBottleCableCapsuleHazelnutMetal NutPillScrewToothbrushTransistorZipper
ResNet-180.9160.9300.8930.9840.9340.9520.9760.8580.9600.8360.9740.9320.8790.9230.7960.915
Wide ResNet-500.9510.9890.9301.00.9600.9830.9920.8560.9820.9370.9780.9460.8950.9520.9140.947

对比可见:更宽的 Wide ResNet-50 骨干在图像级 AUC/F1 上全面优于 ResNet-18(图像级平均 AUC 从 0.891 提升至 0.950),说明更强的骨干特征对补丁分布建模至关重要;而像素级定位两者的差距相对较小(0.968 vs 0.979),侧面反映 PaDiM 的定位能力对骨干宽度依赖较小。

六、工程实践要点与限制

6.1 特征记忆库与显存权衡

训练时所有样本的嵌入先存入memory_bank,再在fit()中一次性torch.vstack拼接后拟合高斯并清空(torch_model.py)。这意味着训练阶段会累积特征而非更新梯度,内存占用随训练样本数线性增长;拟合后显存被及时释放。若 memory bank 为空(例如跳过训练直接验证),fit()会抛出ValueError提示。

6.2 推理链路与部署

推理输出同时包含pred_score(图像级分数)与anomaly_map(像素级异常图),默认后处理器PostProcessor()会基于此进行阈值化与可视化(lightning_model.py)。仓库的部署与导出测试(如 test_ov_export.py、test_inferencer.py)均覆盖了 PaDiM 的 OpenVINO 导出与推理路径,因此训练完成后可借助 Anomalib 的导出能力将其部署到边缘设备进行实时推理。

6.3 已知限制

  • 仅支持单设备训练:默认devices=1,暂不支持多卡并行;
  • 不支持 ViT 骨干PadimModel基于 timm 的features_onlyCNN 模式(output_fmt="NCHW"),与 transformer 类骨干的 token 输出格式不兼容;
  • 可复现性:随机降维索引随模型保存,配合固定 seed(基准使用42)即可稳定复现论文指标。

七、进一步阅读

  • 模型完整 API 参考:PaDiM 参考文档
  • 模型入口与注册:padim/init.py
  • 核心源码:torch_model.py | lightning_model.py | anomaly_map.py | multi_variate_gaussian.py
  • 模型注册与动态加载测试:test_model_utils.py

【免费下载链接】anomalibAn anomaly detection library comprising state-of-the-art algorithms and features such as experiment management, hyper-parameter optimization, and edge inference.项目地址: https://gitcode.com/GitHub_Trending/an/anomalib

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询