Anomalib FastFlow 实战:基于 2D 归一化流的无监督异常检测原理、配置与源码解析
【免费下载链接】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
FastFlow 是 anomalib 中基于 2D 归一化流(Normalizing Flow)的异常检测与定位算法。本篇以仓库中 FastFlow 参考文档 覆盖的四个核心模块(Lightning 封装、Torch 网络、损失函数、异常图生成器)为骨架,结合 模型源码 与 官方配置,完整讲清其参数含义、前向计算链路与训练方式,读完后可独立完成 FastFlow 的配置、训练与结果解读。
一、FastFlow 是什么:可插拔的 2D 归一化流
FastFlow 的核心思想(论文:FastFlow: Unsupervised Anomaly Detection and Localization via 2D Normalizing Flows)是:把任意预训练深度特征提取器(ResNet、Vision Transformer 等)抽出的视觉特征,通过归一化流变换到一个可解析的概率分布空间。训练阶段学习"输入特征 → 可处理分布"的变换;推理阶段则评估像素级似然——正常区域似然高,异常区域似然低。
模型 README 将其定位为Segmentation(像素级分割/定位)类型的模型,即它不仅输出图像级异常分数,还输出与输入同尺寸的异常热力图。
在 anomalib 中,FastFlow 作为 AnomalibModule 生态的一部分注册在 anomalib.models 下,可通过类名Fastflow直接实例化,也可通过 YAML 配置反序列化。
二、模块组成与源码结构
参考文档 通过automodule指令引用了四个模块,它们共同构成 FastFlow 的完整实现:
| 模块 | 职责 | 关键类/函数 |
|---|---|---|
| lightning_model.py | PyTorch Lightning 封装:训练/验证步骤、优化器、评估指标 | Fastflow |
| torch_model.py | 纯 PyTorch 网络:特征提取器 + 多层 Fast Flow Block | FastflowModel、create_fast_flow_block、subnet_conv_func |
| loss.py | 负对数似然损失 | FastflowLoss |
| anomaly_map.py | 由隐变量生成异常热力图 | AnomalyMapGenerator |
__init__.py对外暴露三个公共符号:
# 来自 src/anomalib/models/image/fastflow/__init__.py __all__ = ["FastflowModel", "FastflowLoss", "Fastflow"]三、模型参数详解
Fastflow的构造函数(见 lightning_model.py#L100-L136)参数及默认值如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
backbone | str | "resnet18" | 特征提取骨干网络 |
pre_trained | bool | True | 是否加载 ImageNet 预训练权重 |
flow_steps | int | 8 | 每个尺度下归一化流的耦合变换步数 |
conv3x3_only | bool | False | 是否只使用 3x3 卷积子网(否则奇偶步交替 3x3/1x1) |
hidden_ratio | float | 1.0 | 子网隐藏通道数 = 输入通道数 × 该比例 |
pre_processor/post_processor/evaluator/visualizer | 组件或bool | 均为True | 标准 Anomalib 组件插槽,True表示使用各自默认实现 |
需要注意一个初始化约束:Fastflow要求传入input_size,否则直接抛出ValueError(lightning_model.py#L118-L120):
if self.input_size is None: msg = "Fastflow needs input size to build torch model." raise ValueError(msg)这是因为每个 Fast Flow Block 的卷积子网和 LayerNorm 形状都依赖于特征图的空间尺寸。input_size通常由数据模块(如MVTecAD的input_size)通过配置注入。
四、FastflowModel:骨干网络与 Fast Flow Block
4.1 支持的四类骨干网络
FastflowModel(torch_model.py#L109-L151)通过 timm 加载骨干网络,仅支持四种取值:
cait_m48_448(CaiT)deit_base_distilled_patch16_384(DeiT)resnet18wide_resnet50_2
其他取值会抛出ValueError并提示可用列表。两类骨干的处理方式不同:
ResNet 系(多尺度 CNN):以features_only=True, out_indices=[1, 2, 3]取三个阶段的特征(通道数与下采样倍数由feature_info动态获取),并为每个尺度附加一个可训练的 LayerNorm(torch_model.py#L138-L145):
# for transformers, use their pretrained norm w/o grad # for resnets, self.norms are trainable LayerNorm self.norms = nn.ModuleList() for channel, scale in zip(channels, scales, strict=True): self.norms.append( nn.LayerNorm([channel, int(input_size[0] / scale), int(input_size[1] / scale)], elementwise_affine=True), )Transformer 系(单尺度 ViT):直接取768通道、下采样16倍的最后一层 patch 特征;源码中还会手动截取特定 block 深度——ViT 取前 8 个 block、CaiT 取前 41 个 block(对应原论文 Table 6 的 Block Index 7 / 40,见 torch_model.py#L228 与 torch_model.py#L259),再 reshape 回(B, C, H/16, W/16)的 2D 特征图。
无论哪种骨干,其参数都会被冻结:
for parameter in self.feature_extractor.parameters(): parameter.requires_grad = False即只训练流变换与 LayerNorm,骨干网络不参与更新,这是无监督模式下的标准做法。
4.2 Fast Flow Block 的构造
每个特征尺度上都有一个独立的SequenceINN(来自 FrEIA 库)块,由create_fast_flow_block构建(torch_model.py#L53-L85):
nodes = SequenceINN(*input_dimensions) for i in range(flow_steps): kernel_size = 1 if i % 2 == 1 and not conv3x3_only else 3 nodes.append( AllInOneBlock, subnet_constructor=subnet_conv_func(kernel_size, hidden_ratio), affine_clamping=clamp, # 默认 2.0 permute_soft=False, )要点:
- 每个 block 由
flow_steps个AllInOneBlock堆叠(该组件位于 anomalib/models/components/flow),对应原论文 Section 3.3 的"all-in-one"耦合层设计; - 默认配置下奇数步用 1x1 卷积子网、偶数步用 3x3 卷积子网;
conv3x3_only=True时全部使用 3x3; - 子网本身是"卷积-ReLU-卷积"的两层结构,隐藏通道数由
hidden_ratio控制(torch_model.py#L42-L48); affine_clamping=2.0用于约束仿射系数范围,保证变换数值稳定;permute_soft=False表示不使用 FrEIA 的软置换层。
4.3 前向计算:训练与推理两条路径
forward方法(torch_model.py#L168-L202)先强制骨干进入eval()模式,然后按骨干类型分派到_get_cnn_features/_get_vit_features/_get_cait_features。随后对每个尺度的特征执行流变换:
for fast_flow_block, feature in zip(self.fast_flow_blocks, features, strict=True): hidden_variable, log_jacobian = fast_flow_block(feature) hidden_variables.append(hidden_variable) log_jacobians.append(log_jacobian)- 训练模式:返回
(hidden_variables, log_jacobians),供损失函数使用; - 推理模式:调用
AnomalyMapGenerator生成异常图,并以异常图在空间维上的最大值作为图像级分数:
anomaly_map = self.anomaly_map_generator(hidden_variables) pred_score = torch.amax(anomaly_map, dim=(-2, -1)) return InferenceBatch(pred_score=pred_score, anomaly_map=anomaly_map)五、损失函数:逐层的负对数似然
FastflowLoss(loss.py#L36-L65)对每一层的隐变量与雅可比行列式对数求和:
loss = torch.tensor(0.0, device=hidden_variables[0].device) for hidden_variable, jacobian in zip(hidden_variables, jacobians, strict=True): loss += torch.mean(0.5 * torch.sum(hidden_variable**2, dim=(1, 2, 3)) - jacobian) return loss从公式看,它假设隐空间服从标准正态分布:0.5 * Σ z²即标准正态密度的负对数似然主体,- jacobian项由变量代换公式修正流变换带来的体积变化。总损失是所有尺度层"逐样本平均"后的累加。该损失与training_step中train_loss的日志项一一对应(lightning_model.py#L138-L154)。
六、异常图生成:从隐变量到热力图
AnomalyMapGenerator(anomaly_map.py#L50-L84)把每层隐变量转换为一张"flow map"并做平均:
for hidden_variable in hidden_variables: log_prob = -torch.mean(hidden_variable**2, dim=1, keepdim=True) * 0.5 prob = torch.exp(log_prob) flow_map = F.interpolate( input=-prob, size=self.input_size, mode="bilinear", align_corners=False, ) flow_maps.append(flow_map) flow_maps = torch.stack(flow_maps, dim=-1) return torch.mean(flow_maps, dim=-1)步骤与类文档说明一致:对每个隐变量先按通道取均方计算负对数概率,指数化为概率,取负后经双线性插值放大到input_size,最后把各尺度的 flow map 堆叠后跨层取平均得到最终(N, 1, H, W)异常图。多尺度平均的设计使浅层特征对定位细节的贡献与深层语义特征得到平衡。
七、Lightning 封装:训练配置与指标
Fastflow继承AnomalibModule,几个值得注意的实现细节:
训练器参数(lightning_model.py#L172-L175):
@property def trainer_arguments(self) -> dict[str, Any]: return {"gradient_clip_val": 0, "num_sanity_val_steps": 0}FastFlow 关闭梯度裁剪与训练前的 sanity check 验证轮。
优化器:固定的 Adam,学习率0.001、weight decay0.00001(lightning_model.py#L177-L187),不提供外部超参覆盖入口。
学习类型:LearningType.ONE_CLASS(单类学习,只用正常样本训练)。
评估器:验证阶段记录image_AUROC、pixel_AUROC两项(用于早停监控),测试阶段额外增加image_F1Score、pixel_F1Score(lightning_model.py#L198-L215)。
八、配置与训练:YAML + CLI + Python API
8.1 官方配置文件
examples/configs/model/fastflow.yaml 给出了仓库自带的标准配置:
model: class_path: anomalib.models.Fastflow init_args: backbone: resnet18 pre_trained: true flow_steps: 8 conv3x3_only: false hidden_ratio: 1.0 trainer: max_epochs: 500 callbacks: - class_path: lightning.pytorch.callbacks.EarlyStopping init_args: patience: 3 monitor: pixel_AUROC mode: max要点:最多 500 个 epoch,早停回调以pixel_AUROC为监控指标、耐心值 3——这与 模型 README 中"基准结果均使用 early stopping (patience: 3) 产生"的说明相互印证。
8.2 CLI 训练命令
README 给出的命令行方式为:
anomalib train --model Fastflow --data MVTecAD --data.category <category>8.3 Python API
Fastflow的模块级文档示例给出了完整流程(init.py#L10-L20):
from anomalib.data import MVTecAD from anomalib.models import Fastflow from anomalib.engine import Engine datamodule = MVTecAD() model = Fastflow() engine = Engine() engine.fit(model, datamodule=datamodule) predictions = engine.predict(model, datamodule=datamodule)由于Fastflow要求input_size,实践中一般通过配置方式(AnomalibModule.from_config)让数据模块的input_size注入模型,而非手工构造裸参数。
8.4 测试用例佐证
单元测试 tests/unit/models/components/base/test_anomaly_module.py 将fastflow纳入参数化用例,验证AnomalibModule.from_config能基于examples/configs/model/fastflow.yaml成功构建出AnomalibModule实例,是配置文件与模型注册链路一致性的回归保障。
九、基准结果(来自模型 README)
模型 README 附带了在 MVTec AD 数据集上的基准(全部使用 seed0,启用 patience 为 3 的早停回调)。四类骨干的平均指标如下:
| 骨干 | 图像级 AUC | 像素级 AUC | 图像 F1 | 像素 F1 |
|---|---|---|---|---|
| ResNet-18 | 0.907 | 0.968 | 0.916 | 0.519 |
| Wide ResNet50 | 0.963 | 0.979 | 0.947 | 0.589 |
| DeiT | 0.925 | 0.975 | 0.906 | 0.557 |
| CaiT | 0.944 | 0.980 | 0.911 | 0.575 |
完整分类目表格(Bottle、Cable、Capsule 等 15 个类别的 Image AUC / Pixel AUC / Image F1 / Pixel F1)可查阅 README 原文。从中可以看出:更换更强的骨干(Wide ResNet50)能同时提升检测与定位指标,而 README 也提示增大早停 patience 有可能进一步改善结果。
十、小结
FastFlow 在 anomalib 中的实现是一条清晰的链路:冻结的多尺度骨干特征 → FrEIA 多层 AllInOneBlock 流变换(输出隐变量与雅可比对数)→ 逐层高斯负对数似然损失训练 → 隐变量转 flow map 并跨层平均得到异常图 → 空间最大值作为图像分数。理解这条链路后,可以结合flow_steps、conv3x3_only、hidden_ratio与骨干选择(torch_model.py)做针对性调参,并利用 fastflow.yaml 中"500 epoch + pixel_AUROC 早停"的标准配置复现基准结果。
【免费下载链接】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),仅供参考