EfficientAD: Accurate Visual Anomaly Detection at Millisecond-Level Latencies
1、Background
EfficientAD使用了学生-教师方法。训练了一个学生网络来预测正常即无异常训练图像上预训练教师网络计算的特征。由于学生没有在异常图像上进行训练,它通常无法在这些图像上模仿教师。因此,在测试时,教师和学生的输出之间的大距离使得能够检测到异常。
为了进一步增加这种效果,提出了一种以训练损失形式的损失诱导不对称性,这种损失阻止学生在正常图像之外模仿教师。这种损失在测试时不影响计算成本,也不限制架构设计。它能够为学生和教师都使用高效网络架构,同时提高异常特征的检测能力。识别异常局部特征可以检测与正常图像在结构上不同的异常。
然而,一个具有挑战性的问题是违反正常对象的位置、大小、排列等逻辑约束。为了解决这个问题,EfficientAD 包括一个自编码器,该自编码器学习训练图像的逻辑约束,并在测试时检测违规行为。
EfficientAD展示了如何有效地将自编码器与学生-教师模型结合起来。此外,提出了一种通过在组合结果之前校准自编码器和学生-教师模型的检测结果来提高异常检测性能的方法。
2、Method
在 EfficientAD 方法中,为了阻止学生网络在正常图像之外模仿教师网络,提出了一种特殊的训练损失,称为“hard feature loss”。这种方法的核心思想是让学生网络只在那些它当前模仿得最不好的图像部分进行学习,也就是那些与教师网络输出差异最大的部分。具体来说,这种方法的工作流程如下:
教师-学生网络架构:首先,使用一个预训练的教师网络(teacher network)和一个学生网络(student network)。教师网络用于提取正常图像的特征,而学生网络则被训练来预测这些特征。
特征差异计算:对于每个训练图像,教师网络和学生网络都会输出特征图。然后,计算这两组特征图之间的差异,通常使用平方差来表示。
硬特征损失(Hard Feature Loss):在计算差异之后,不是简单地使用所有差异来计算损失,而是选择差异最大的一部分来进行反向传播。具体来说,会根据一个预先设定的阈值(例如 0.999 分位数),只选择超过这个阈值的特征差异参与损失计算。这意味着只有那些学生网络最难模仿教师网络的特征会被用于训练。
损失函数:通过这种方式,损失函数(Lhard)只关注那些最难模仿的部分,从而阻止学生网络在正常图像之外过度模仿教师网络。这种方法可以形式化为:
训练过程:在训练过程中,学生网络通过最小化这个硬特征损失来学习。这样,学生网络就会专注于那些最难模仿的特征,而不是试图在所有特征上都完美地模仿教师网络,从而在异常图像上产生更好的检测效果。
通过这种方法,EfficientAD 能够在保持低延迟的同时,提高对异常特征的检测能力,尤其是在那些学生网络难以模仿教师网络的区域。这不仅提高了异常检测的性能,还保持了模型的计算效率。
在 EfficientAD 方法中,自编码器被用来学习训练图像的逻辑约束,并在测试时检测这些约束的违规行为。具体步骤如下:
自编码器训练:自编码器是一个标准的卷积自编码器,它通过编码器将输入图像压缩成一个低维的潜在表示(latent code),然后通过解码器重建图像。自编码器的目标是学习正常图像的表示,以便能够准确重建这些图像。
逻辑约束学习:在训练阶段,自编码器被训练为仅对正常图像进行优化。这意味着自编码器学习了正常图像的内在结构和模式,从而隐式地学习了这些图像的逻辑约束。逻辑约束可能涉及对象的位置、大小、排列顺序等。
异常检测:在测试阶段,自编码器尝试重建输入图像。如果输入图像包含逻辑异常,例如违反了学习到的逻辑约束,自编码器将无法准确地重建图像。这种重建失败表明输入图像中可能存在异常。
重建误差分析:自编码器的输出(重建图像)与原始输入图像之间的差异被用作异常图(anomaly map)。如果在某个区域的重建误差显著高于正常图像的重建误差,那么这个区域可能包含异常。
学生网络的辅助:EfficientAD 方法还包括一个学生网络,该网络被训练为预测自编码器的输出。学生网络在正常图像上进行训练,因此它学会了自编码器在重建正常图像时的系统性误差。在测试时,学生网络的输出与自编码器的输出之间的差异被用来进一步增强异常检测。
异常图的融合:EfficientAD 方法将学生-教师模型产生的局部异常图和自编码器产生的全局异常图结合起来,以提高异常检测的准确性。这两种异常图的结合使得方法能够同时检测结构和逻辑异常。
异常图的归一化:为了使局部和全局异常图在尺度上相似,以便在融合之前进行有效的比较,EfficientAD 方法使用基于分位数的归一化方法。这种方法对正常图像的验证集计算异常分数的分位数,并使用这些分位数来归一化异常图,使得异常图在不同测试图像之间具有一致的尺度。
通过这种方式,EfficientAD 方法能够有效地利用自编码器来检测违反训练图像逻辑约束的异常,同时保持了高效率和低延迟的检测性能。
EfficientAD 方法有效地 结合了自编码器和学生-教师模型
,使得能够同时检测局部的结构异常和全局的逻辑异常,提高了异常检测的准确性和鲁棒性。此外,这种方法还保持了高效率和低延迟,适合实时应用场景。
具体步骤:
- 独立训练:自编码器和学生-教师模型是独立训练的。自编码器学习训练图像的全局特征和逻辑约束,而学生-教师模型专注于学习局部特征。
- 特征融合:在测试阶段,自编码器和学生-教师模型都被用来处理同一张测试图像。自编码器尝试重建输入图像,并生成一个重建误差图,这反映了图像中的全局异常。同时,学生-教师模型生成一个基于特征预测误差的局部异常图。
- 双流架构:EfficientAD 采用了一个双流架构,其中一个流是学生-教师模型,用于检测局部异常;另一个流是自编码器,用于检测全局逻辑异常。学生网络不仅预测教师网络的输出,还额外预测自编码器的输出。
- 异常图的计算:对于自编码器,异常图是通过比较自编码器的输出和学生网络的预测输出来计算的。对于学生-教师模型,异常图是通过比较教师网络的输出和学生网络的预测输出来计算的。
- 异常图的归一化和融合:为了将局部和全局异常图结合起来,EfficientAD 使用了基于分位数的归一化方法来调整异常图的尺度,使得它们可以在相同的尺度上进行比较。归一化后,这两个异常图被平均结合起来,形成一个综合的异常图。
- 阈值和决策:综合异常图用于计算图像级别的异常分数,这个分数可以用于决定一张图像是否包含异常。异常图还可以用于定位图像中的异常区域。
pseudo-code
# 导入必要的库
import torch
import torch.nn as nn
import torch.optim as optim
# 假设我们有一个预训练的教师网络 TeacherNetwork 和一个学生网络 StudentNetwork
class TeacherNetwork(nn.Module):
# 定义教师网络结构
pass
class StudentNetwork(nn.Module):
# 定义学生网络结构
pass
# 初始化网络
teacher_network = TeacherNetwork()
student_network = StudentNetwork()
# 定义自编码器 Autoencoder
class Autoencoder(nn.Module):
def __init__(self):
super(Autoencoder, self).__init__()
# 定义自编码器的编码器和解码器部分
pass
def forward(self, x):
# 定义前向传播过程
pass
autoencoder = Autoencoder()
# 定义损失函数
def hard_feature_loss(student_output, teacher_output, threshold):
# 计算学生输出和教师输出之间的差异
diff = (student_output - teacher_output) ** 2
# 应用阈值,只关注最难模仿的特征
loss = torch.mean(diff[diff > threshold])
return loss
# 定义训练过程
def train(model, data_loader, optimizer):
model.train()
for images in data_loader:
# 提取特征
teacher_features = teacher_network(images)
student_features = student_network(images)
# 计算损失
loss = hard_feature_loss(student_features, teacher_features, threshold=0.999)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 定义异常检测过程
def detect_anomalies(test_image):
# 使用教师网络和自编码器提取特征
teacher_features = teacher_network(test_image)
reconstructed_image = autoencoder(test_image)
# 使用学生网络预测自编码器的输出
student_prediction = student_network(reconstructed_image)
# 计算异常图
local_anomaly_map = hard_feature_loss(student_network(test_image), teacher_features, threshold=0.999)
global_anomaly_map = torch.mean((reconstructed_image - test_image) ** 2)
# 归一化和融合异常图
normalized_local_map = normalize(local_anomaly_map)
normalized_global_map = normalize(global_anomaly_map)
combined_anomaly_map = 0.5 * normalized_local_map + 0.5 * normalized_global_map
return combined_anomaly_map
# 辅助函数:归一化异常图
def normalize(anomaly_map):
# 使用验证集上的分位数来归一化异常图
# 这里省略了具体的归一化步骤
pass
# 训练学生网络
optimizer = optim.Adam(student_network.parameters(), lr=0.001)
train(student_network, train_data_loader, optimizer)
# 检测异常
test_image = ... # 加载测试图像
anomaly_map = detect_anomalies(test_image)
3、Experiments
🐂🐎。。。
4、Conclusion
- 提出了一个高效的网络架构EfficientAD,有效地将自编码器与学生-教师模型结合,加快了特征提取速度。
- 引入了一种训练损失,显著提高了学生-教师模型的异常检测性能,而不影响其推理运行时间。
- 实现了一种高效的基于自编码器的逻辑异常检测,并提出了一种方法,用于在与学生-教师模型的检测结果结合之前对其进行校准组合。