
✅ 博主简介:擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。
✅ 具体问题可以私信或扫描文章底部二维码。
(1)针对异常样本中存在对抗攻击样本的问题,本文提出了一种对偶自编码器框架,旨在同时提升异常检测模型在分布外样本识别与对抗攻击鲁棒性方面的性能。传统的半监督异常检测方法通常仅依赖于正常样本构建重建模型,通过重建误差判断异常,然而这类方法在面对精心设计的对抗样本时表现脆弱,因为对抗扰动往往微小却足以误导模型输出。为解决这一问题,本文设计的对偶自编码器包含两个并行但功能互补的子网络:一个专注于图像空间的高质量重建,另一个则聚焦于隐空间中语义特征的提取与判别。两个子网络共享部分底层编码结构,但在高层特征处理上分别优化,从而在保持重建能力的同时增强对隐空间扰动的敏感性。特别地,本文引入互信息估计器作为隐空间的正则化组件,该组件通过最大化输入数据与隐变量之间的互信息,迫使模型保留对目标类别最具判别性的语义信息,同时抑制冗余或易受攻击的特征维度。这种设计有效提升了隐空间对正常模式的紧凑表达能力,使得异常或对抗样本在隐空间中更容易被识别为偏离正常流形的点。为了验证模型在对抗环境下的鲁棒性,本文构建了三个专门针对停车标志识别任务的对抗数据集,分别采用FGSM(快速梯度符号法)、BIM(基本迭代法)和DeepFool三种主流对抗攻击算法生成扰动样本。这些攻击方法在扰动幅度、迭代策略和攻击目标上各具特点,能够全面检验模型的防御能力。实验结果表明,相较于当前主流的半监督异常检测器如f-AnoGAN、OCGAN和CutPaste等,本文提出的对偶自编码器在所有对抗攻击场景下均表现出显著更高的检测准确率和更低的误报率。尤其在DeepFool攻击下,该方法仍能维持超过85%的异常识别率,而对比方法普遍下降至70%以下。这一优势源于模型在隐空间中对正常样本分布的更精确建模以及对扰动方向的敏感抑制机制。此外,对偶结构还带来了训练过程中的梯度协同效应,两个子网络在反向传播中相互提供监督信号,避免了单一自编码器在训练后期可能出现的模式崩溃问题,进一步增强了模型的泛化能力。

(2)针对隐空间构建过程中存在的特征判别能力弱、正常样本模式丢失以及训练不稳定三大核心问题,本文分别提出了三项针对性优化策略,形成一套系统性的隐空间增强方案。首先,为提升隐空间中正常与异常样本的可分性,本文设计了一个基于对比学习的隐空间优化网络。该网络不依赖标签信息,而是通过数据增强技术主动构造“难负样本”——即在原始正常样本基础上施加轻微但语义保持的变换(如颜色抖动、局部遮挡、几何扭曲等),生成与原始样本高度相似但非完全一致的增强样本。这些增强样本被用作对比学习中的负样本对,迫使编码器在隐空间中将同一原始样本的不同增强版本拉近,同时将不同原始样本的表示推远。这种“学会比较”的机制显著增强了隐空间的局部结构一致性,使得正常样本在隐空间中形成紧密簇群,而异常样本则因无法被有效重建或嵌入而自然偏离。其次,针对训练过程中可能出现的正常样本模式丢失问题——即模型过度拟合部分训练样本而忽略其他正常模式,本文提出了一种基于间接生成与最近邻策略的隐空间重构框架。该框架在训练阶段引入一个动态候选生成池,对每个输入训练图像,系统会从历史生成结果中检索与其在像素或特征层面最接近的若干候选图像,并将这些候选图像的分布作为辅助监督信号。通过最小化当前生成图像与最近邻候选图像之间的分布距离,模型被强制保留多样化的正常模式,避免陷入单一模式的过拟合。该策略尤其适用于小样本或高维数据场景,能有效缓解因数据稀疏导致的表征偏差。最后,为解决自编码器类模型在训练中常见的梯度消失或震荡问题,本文创新性地提出了解码器-编码器-解码器(D-E-D)三级架构。该架构将传统自编码器的单次重建过程拆解为两次级联重建:第一次由初始解码器生成粗略重建,第二次由中间编码器再次编码后再经最终解码器精细重建。在此过程中,中间编码器不仅接收原始隐变量输入,还融合第一次重建的误差反馈,形成闭环优化。更重要的是,本文将整个D-E-D结构本身作为鉴别器使用,替代传统GAN中的判别网络。这种设计摒弃了二分类逻辑损失,转而依赖重建质量作为判别依据,使得梯度信号更加丰富且连续。实验表明,该架构在DCASE 2020异常声音检测数据集上实现了训练损失的平稳下降,收敛速度提升约30%,且最终模型在AUC指标上较基准方法提升1.1%,验证了其在稳定性与性能上的双重优势。
(3)针对多场景下隐空间特征分布易出现过拟合的问题,本文根据视频监控与工业质检两类典型应用场景的数据特性,分别设计了细粒度的隐空间约束机制。在视频监控场景中,异常通常表现为时空行为的异常,如行人突然奔跑、车辆逆行等,这类异常具有强时序依赖性和上下文关联性。为此,本文提出了一种具有三重一致性约束的双向预测网络架构。该架构包含前向预测分支与后向预测分支,分别从过去帧预测未来帧,以及从未来帧回溯过去帧,形成双向时序建模。第一重约束为前后向预测一致性,要求两个方向的预测结果在隐空间中高度对齐,确保模型对正常时序动态的理解具有对称性和鲁棒性;第二重约束为跨模态关联一致性,即同时处理视频的RGB帧与光流场两种模态,在隐空间中强制两种模态的特征表示相互校准,利用光流提供的运动信息增强RGB帧的静态表征;第三重约束为时间序列完整性约束,通过引入时间窗口内的全局上下文编码器,确保局部帧的隐表示与整个视频片段的语义保持一致,防止模型仅关注局部细节而忽略整体行为模式。该三重约束机制在UCSD Ped2、CUHK Avenue和ShanghaiTech三个主流视频异常检测数据集上进行了验证,分别实现了1.0%、0.7%和3.3%的AUC提升,尤其在ShanghaiTech这种复杂城市场景中表现突出,证明了其对多样异常类型的适应能力。在工业质检场景中,异常通常表现为产品表面的微小缺陷,如划痕、污渍、缺失等,这类异常与正常样本在全局外观上高度相似,仅在局部纹理或结构上存在细微差异。为解决这一挑战,本文提出了一种基于隐空间特征匹配的知识蒸馏框架。该框架利用在ImageNet上预训练的大规模视觉模型(如ResNet-50)作为教师网络,提取无缺陷工业样本在通用视觉隐空间中的多层次特征表示。学生网络(即异常检测模型)在训练过程中不仅需重建输入图像,还需在多个中间层上匹配教师网络对应层的特征分布。具体而言,匹配过程包含两个层面:一是整体特征分布匹配,通过最大均值差异(MMD)或Wasserstein距离对齐学生与教师隐空间的全局统计特性;二是逐层独立特征匹配,对每一层的通道级特征进行精细化对齐,确保局部细节信息不被忽略。这种双重匹配机制使得学生网络能够继承教师网络在大规模数据上学到的丰富先验知识,即使在工业数据集样本有限的情况下,也能构建出更具泛化能力的正常模式隐空间。在MVTec AD数据集上的实验表明,该框架在多种产品类别(如金属、织物、电子元件)上均取得当前最优性能,平均像素级AUC达到96.2%,显著优于PatchCore、SPADE等现有方法,尤其在微小缺陷检测任务中展现出更强的敏感性与鲁棒性。
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
from torchvision.datasets import ImageFolder
import numpy as np
import os
from sklearn.metrics import roc_auc_score
from collections import OrderedDict
class DualAutoencoder(nn.Module):
def __init__(self, latent_dim=128):
super(DualAutoencoder, self).__init__()
self.latent_dim = latent_dim
self.encoder_shared = nn.Sequential(
nn.Conv2d(3, 64, 4, stride=2, padding=1),
nn.ReLU(),
nn.Conv2d(64, 128, 4, stride=2, padding=1),
nn.ReLU(),
nn.Conv2d(128, 256, 4, stride=2, padding=1),
nn.ReLU()
)
self.encoder_img = nn.Sequential(
nn.Conv2d(256, 512, 4, stride=2, padding=1),
nn.ReLU(),
nn.Flatten(),
nn.Linear(512 * 4 * 4, latent_dim)
)
self.encoder_feat = nn.Sequential(
nn.AdaptiveAvgPool2d((1,1)),
nn.Flatten(),
nn.Linear(256, latent_dim)
)
self.decoder_img = nn.Sequential(
nn.Linear(latent_dim, 512 * 4 * 4),
nn.ReLU(),
nn.Unflatten(1, (512, 4, 4)),
nn.ConvTranspose2d(512, 256, 4, stride=2, padding=1),
nn.ReLU(),
nn.ConvTranspose2d(256, 128, 4, stride=2, padding=1),
nn.ReLU(),
nn.ConvTranspose2d(128, 64, 4, stride=2, padding=1),
nn.ReLU(),
nn.ConvTranspose2d(64, 3, 4, stride=2, padding=1),
nn.Sigmoid()
)
self.decoder_feat = nn.Sequential(
nn.Linear(latent_dim, 256),
nn.ReLU(),
nn.Unflatten(1, (256, 1, 1)),
nn.Upsample(scale_factor=32, mode='nearest'),
nn.Conv2d(256, 128, 3, padding=1),
nn.ReLU(),
nn.Conv2d(128, 64, 3, padding=1),
nn.ReLU(),
nn.Conv2d(64, 3, 3, padding=1),
nn.Sigmoid()
)
self.mutual_info_estimator = nn.Sequential(
nn.Linear(latent_dim, 256),
nn.ReLU(),
nn.Linear(256, 1)
)
def forward(self, x):
shared = self.encoder_shared(x)
z_img = self.encoder_img(shared)
z_feat = self.encoder_feat(shared)
recon_img = self.decoder_img(z_img)
recon_feat = self.decoder_feat(z_feat)
mi_img = self.mutual_info_estimator(z_img)
mi_feat = self.mutual_info_estimator(z_feat)
return recon_img, recon_feat, z_img, z_feat, mi_img, mi_feat
class ContrastiveLearningNetwork(nn.Module):
def __init__(self, base_encoder, latent_dim=128):
super(ContrastiveLearningNetwork, self).__init__()
self.encoder = base_encoder
self.projector = nn.Sequential(
nn.Linear(latent_dim, latent_dim),
nn.ReLU(),
nn.Linear(latent_dim, 64)
)
def forward(self, x1, x2):
z1 = self.encoder(x1)
z2 = self.encoder(x2)
p1 = self.projector(z1)
p2 = self.projector(z2)
return p1, p2
class NearestNeighborGenerator(nn.Module):
def __init__(self, encoder, decoder, memory_size=1000):
super(NearestNeighborGenerator, self).__init__()
self.encoder = encoder
self.decoder = decoder
self.register_buffer('memory_bank', torch.randn(memory_size, 128))
self.memory_ptr = 0
self.memory_size = memory_size
def update_memory(self, features):
batch_size = features.size(0)
if self.memory_ptr + batch_size > self.memory_size:
self.memory_bank[self.memory_ptr:] = features[:self.memory_size - self.memory_ptr]
self.memory_bank[:batch_size - (self.memory_size - self.memory_ptr)] = features[self.memory_size - self.memory_ptr:]
self.memory_ptr = batch_size - (self.memory_size - self.memory_ptr)
else:
self.memory_bank[self.memory_ptr:self.memory_ptr + batch_size] = features
self.memory_ptr += batch_size
def get_nearest_neighbors(self, query, k=5):
query = query.detach()
similarities = torch.mm(query, self.memory_bank.t())
_, indices = torch.topk(similarities, k, dim=1)
return self.memory_bank[indices]
def forward(self, x):
z = self.encoder(x)
self.update_memory(z)
neighbors = self.get_nearest_neighbors(z)
neighbor_recons = self.decoder(neighbors.view(-1, neighbors.size(-1)))
recon = self.decoder(z)
return recon, neighbor_recons.view(z.size(0), -1, *recon.shape[1:])
class DecoderEncoderDecoder(nn.Module):
def __init__(self, latent_dim=128):
super(DecoderEncoderDecoder, self).__init__()
self.encoder1 = nn.Sequential(
nn.Conv2d(3, 64, 4, 2, 1),
nn.ReLU(),
nn.Conv2d(64, 128, 4, 2, 1),
nn.ReLU(),
nn.Conv2d(128, 256, 4, 2, 1),
nn.ReLU(),
nn.Conv2d(256, latent_dim, 4, 2, 1)
)
self.decoder1 = nn.Sequential(
nn.ConvTranspose2d(latent_dim, 256, 4, 2, 1),
nn.ReLU(),
nn.ConvTranspose2d(256, 128, 4, 2, 1),
nn.ReLU(),
nn.ConvTranspose2d(128, 64, 4, 2, 1),
nn.ReLU(),
nn.ConvTranspose2d(64, 3, 4, 2, 1),
nn.Sigmoid()
)
self.encoder2 = nn.Sequential(
nn.Conv2d(3, 64, 4, 2, 1),
nn.ReLU(),
nn.Conv2d(64, 128, 4, 2, 1),
nn.ReLU(),
nn.Conv2d(128, 256, 4, 2, 1),
nn.ReLU(),
nn.Conv2d(256, latent_dim, 4, 2, 1)
)
self.decoder2 = nn.Sequential(
nn.ConvTranspose2d(latent_dim, 256, 4, 2, 1),
nn.ReLU(),
nn.ConvTranspose2d(256, 128, 4, 2, 1),
nn.ReLU(),
nn.ConvTranspose2d(128, 64, 4, 2, 1),
nn.ReLU(),
nn.ConvTranspose2d(64, 3, 4, 2, 1),
nn.Sigmoid()
)
def forward(self, x):
z1 = self.encoder1(x)
recon1 = self.decoder1(z1)
z2 = self.encoder2(recon1)
recon2 = self.decoder2(z2)
return recon1, recon2, z1, z2
class BidirectionalPredictor(nn.Module):
def __init__(self, input_dim=3, hidden_dim=64):
super(BidirectionalPredictor, self).__init__()
self.conv_in = nn.Conv3d(input_dim, hidden_dim, kernel_size=(1,3,3), padding=(0,1,1))
self.gru_forward = nn.GRU(hidden_dim*8*8, hidden_dim*8*8, batch_first=True)
self.gru_backward = nn.GRU(hidden_dim*8*8, hidden_dim*8*8, batch_first=True)
self.conv_out = nn.Conv3d(hidden_dim, input_dim, kernel_size=(1,3,3), padding=(0,1,1))
self.hidden_dim = hidden_dim
def forward(self, x):
b, t, c, h, w = x.shape
x = x.permute(0,2,1,3,4)
x = self.conv_in(x)
x_flat = x.reshape(b, t, -1)
forward_out, _ = self.gru_forward(x_flat)
backward_out, _ = self.gru_backward(torch.flip(x_flat, [1]))
combined = forward_out + torch.flip(backward_out, [1])
combined = combined.reshape(b, self.hidden_dim, t, h//4, w//4)
recon = self.conv_out(combined)
recon = F.interpolate(recon, size=(t, h, w), mode='nearest')
return recon
class KnowledgeDistillationAnomalyDetector(nn.Module):
def __init__(self, student_encoder, teacher_encoder, layers=['layer2', 'layer3']):
super(KnowledgeDistillationAnomalyDetector, self).__init__()
self.student = student_encoder
self.teacher = teacher_encoder
self.layers = layers
for param in self.teacher.parameters():
param.requires_grad = False
self.adaptation_layers = nn.ModuleDict()
for layer in layers:
self.adaptation_layers[layer] = nn.Conv2d(getattr(self.student, layer).out_channels,
getattr(self.teacher, layer).out_channels, 1)
def forward(self, x):
student_features = OrderedDict()
teacher_features = OrderedDict()
x_student = x
x_teacher = x
for name, module in self.student.named_children():
x_student = module(x_student)
if name in self.layers:
student_features[name] = self.adaptation_layers[name](x_student)
with torch.no_grad():
for name, module in self.teacher.named_children():
x_teacher = module(x_teacher)
if name in self.layers:
teacher_features[name] = x_teacher
return student_features, teacher_features
def compute_mmd(x, y, kernel='rbf'):
xx = torch.mm(x, x.t())
yy = torch.mm(y, y.t())
xy = torch.mm(x, y.t())
rx = xx.diag().unsqueeze(0).expand_as(xx)
ry = yy.diag().unsqueeze(0).expand_as(yy)
if kernel == 'rbf':
dxx = rx.t() + rx - 2.*xx
dyy = ry.t() + ry - 2.*yy
dxy = rx.t() + ry - 2.*xy
sigma = 1.0
mmd = torch.mean(torch.exp(-dxx/(2*sigma**2))) + torch.mean(torch.exp(-dyy/(2*sigma**2))) - 2*torch.mean(torch.exp(-dxy/(2*sigma**2)))
else:
mmd = torch.mean(dxx) + torch.mean(dyy) - 2*torch.mean(dxy)
return mmd
def train_dual_ae(model, dataloader, epochs=50, lr=1e-3):
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
model.train()
for epoch in range(epochs):
for batch in dataloader:
x, _ = batch
x = x.cuda()
recon_img, recon_feat, z_img, z_feat, mi_img, mi_feat = model(x)
loss_recon = F.mse_loss(recon_img, x) + F.mse_loss(recon_feat, x)
loss_mi = -torch.mean(mi_img) - torch.mean(mi_feat)
loss = loss_recon + 0.1 * loss_mi
optimizer.zero_grad()
loss.backward()
optimizer.step()
def train_contrastive(model, dataloader, augment_fn, epochs=50, lr=1e-3):
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
model.train()
for epoch in range(epochs):
for batch in dataloader:
x, _ = batch
x1 = augment_fn(x)
x2 = augment_fn(x)
p1, p2 = model(x1.cuda(), x2.cuda())
loss = -F.cosine_similarity(p1, p2.detach()).mean() - F.cosine_similarity(p2, p1.detach()).mean()
optimizer.zero_grad()
loss.backward()
optimizer.step()
def train_ded(model, dataloader, epochs=50, lr=1e-3):
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
model.train()
for epoch in range(epochs):
for batch in dataloader:
x, _ = batch
x = x.cuda()
recon1, recon2, z1, z2 = model(x)
loss = F.mse_loss(recon1, x) + F.mse_loss(recon2, x)
optimizer.zero_grad()
loss.backward()
optimizer.step()
def evaluate_anomaly(model, normal_loader, anomaly_loader):
model.eval()
scores = []
labels = []
with torch.no_grad():
for x, _ in normal_loader:
x = x.cuda()
recon, _, _, _ = model(x)
error = torch.mean((x - recon)**2, dim=[1,2,3])
scores.extend(error.cpu().numpy())
labels.extend([0]*x.size(0))
for x, _ in anomaly_loader:
x = x.cuda()
recon, _, _, _ = model(x)
error = torch.mean((x - recon)**2, dim=[1,2,3])
scores.extend(error.cpu().numpy())
labels.extend([1]*x.size(0))
auc = roc_auc_score(labels, scores)
return auc
如有问题,可以直接沟通
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
3246

被折叠的 条评论
为什么被折叠?



