深入 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):
- 多尺度补丁特征提取:图像被拆分为补丁,使用预训练 CNN 特征提取器从多个不同层抽取每个补丁的嵌入向量。由于不同卷积层对应不同感受野与语义层级,将多层激活向量拼接后,嵌入向量同时携带了细粒度(低级纹理)与全局(高级语义)上下文信息。
- 随机降维:拼接后的嵌入向量可能包含冗余信息,因此通过随机选择(random selection)进行维度缩减,只保留固定数量的特征维度。
- 逐补丁高斯建模:对整个训练批次,为每个补丁嵌入生成一个多元高斯分布,所有补丁的高斯参数组合成一个高斯参数矩阵(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 中"矩阵化马氏距离形成异常图"的描述,具体三步:
compute_distance:实现论文 Section III-C 的公式 (2),计算测试补丁嵌入与参考分布的马氏距离(delta^T · inv_cov · delta)后开方并clamp(0),得到(B, 1, H, W)的原始分数图(见 anomaly_map.py);up_sample:通过F.interpolate(..., mode="bilinear")将分数图上采样回原始输入图像尺寸(见 anomaly_map.py);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)的构造参数如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
backbone | str | "resnet18" | 预训练骨干网络名称,常用resnet18、wide_resnet50_2等 timm 模型 |
layers | list[str] | ["layer1", "layer2", "layer3"] | 抽取特征的骨干层名称列表,按分辨率从高到低排列 |
pre_trained | bool | True | 是否使用预训练骨干权重 |
n_features | int | None | None | 降维后保留的特征数;论文默认值见下表 |
pre_processor/post_processor/evaluator/visualizer | module | bool | True | Anomalib 标准预处理、后处理、评估器与可视化组件开关 |
关键注意:n_features为None时自动使用论文默认值(定义于 torch_model.py):
| 骨干网络 | 默认 n_features |
|---|---|
resnet18 | 100 |
wide_resnet50_2 | 550 |
若使用其他骨干网络,则必须显式指定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=1、val_check_interval=1.0、num_sanity_val_steps=0、devices=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 数据集的类别(如bottle、carpet、transistor等)。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_dir、val_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.yaml4.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)
| Avg | Carpet | Grid | Leather | Tile | Wood | Bottle | Cable | Capsule | Hazelnut | Metal Nut | Pill | Screw | Toothbrush | Transistor | Zipper | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ResNet-18 | 0.891 | 0.945 | 0.857 | 0.982 | 0.950 | 0.976 | 0.994 | 0.844 | 0.901 | 0.750 | 0.961 | 0.863 | 0.759 | 0.889 | 0.920 | 0.780 |
| Wide ResNet-50 | 0.950 | 0.995 | 0.942 | 1.0 | 0.974 | 0.993 | 0.999 | 0.878 | 0.927 | 0.964 | 0.989 | 0.939 | 0.845 | 0.942 | 0.976 | 0.882 |
5.2 Pixel-Level AUC(像素级 AUC)
| Avg | Carpet | Grid | Leather | Tile | Wood | Bottle | Cable | Capsule | Hazelnut | Metal Nut | Pill | Screw | Toothbrush | Transistor | Zipper | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ResNet-18 | 0.968 | 0.984 | 0.918 | 0.994 | 0.934 | 0.947 | 0.983 | 0.965 | 0.984 | 0.978 | 0.970 | 0.957 | 0.978 | 0.988 | 0.968 | 0.979 |
| Wide ResNet-50 | 0.979 | 0.991 | 0.970 | 0.993 | 0.955 | 0.957 | 0.985 | 0.970 | 0.988 | 0.985 | 0.982 | 0.966 | 0.988 | 0.991 | 0.976 | 0.986 |
5.3 Image F1 Score(图像级 F1)
| Avg | Carpet | Grid | Leather | Tile | Wood | Bottle | Cable | Capsule | Hazelnut | Metal Nut | Pill | Screw | Toothbrush | Transistor | Zipper | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ResNet-18 | 0.916 | 0.930 | 0.893 | 0.984 | 0.934 | 0.952 | 0.976 | 0.858 | 0.960 | 0.836 | 0.974 | 0.932 | 0.879 | 0.923 | 0.796 | 0.915 |
| Wide ResNet-50 | 0.951 | 0.989 | 0.930 | 1.0 | 0.960 | 0.983 | 0.992 | 0.856 | 0.982 | 0.937 | 0.978 | 0.946 | 0.895 | 0.952 | 0.914 | 0.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),仅供参考