实验背景与目标
本实验旨在系统研究对抗训练对深度学习模型鲁棒性的提升效果。随着深度学习在安全敏感领域的广泛应用,模型面对对抗样本攻击时的脆弱性已成为重要安全隐患。对抗样本是通过对原始输入添加人眼难以察觉的微小扰动而生成的恶意样本,能导致模型产生错误预测。
实验以CIFAR-10数据集为基础,构建卷积神经网络分类器,通过对比标准训练与对抗训练两种策略,分析模型在面对FGSM击时的性能表现。研究目标包括:
验证标准深度学习模型在对抗攻击下的脆弱性
评估对抗训练策略对模型鲁棒性的提升效果
分析对抗训练对模型正常分类性能的影响
实验环境
深度学习框架 : PyTorch 2.5.1+cu121
Python版本 : 3.10.0
硬件环境 : NVIDIA GeForce RTX 4060
数据集 : CIFAR-10
模型架构 : 自定义并训练的CIFAR10Model
实验设计
模型构建与标准训练: 设计并实现卷积神经网络分类器,包含三个特征提取阶段和全连接分类器。使用Adam优化器进行50轮标准训练,监控损失收敛过程,在测试集上评估模型性能并建立准确率基线。
对抗攻击实施: 实现FGSM对抗攻击算法,生成对抗样本并可视化攻击效果。测试标准模型在对抗攻击下的性能表现,量化分析模型脆弱性。
对抗训练执行: 在标准训练流程中集成对抗样本,设置80%的对抗样本混合比例和增强的扰动系数。执行对抗训练过程,保存训练后的鲁棒模型。
效果评估对比: 系统比较标准训练与对抗训练模型在干净样本和对抗样本上的性能差异,量化鲁棒性提升效果,分析准确率-鲁棒性权衡关系。
实验步骤
实验环境初始化与基础配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optimimport torchvisionimport torchvision.transforms as transformsimport numpy as npimport matplotlib.pyplot as pltimport timeimport randomimport warnings warnings.filterwarnings('ignore' ) device = torch.device('cuda' if torch.cuda.is_available() else 'cpu' ) classes = ('plane' , 'car' , 'bird' , 'cat' , 'deer' , 'dog' , 'frog' , 'horse' , 'ship' , 'truck' )def plot_images (X, y, yp, M, N ): f, ax = plt.subplots(M, N, sharex=True , sharey=True , figsize=(N, M*1.3 )) for i in range (M): for j in range (N): ax[i][j].imshow(((X[i*N+j].cpu().numpy().transpose(1 , 2 , 0 )+1 )/2 *255 ).astype(np.uint8)) title = ax[i][j].set_title("P: {}" .format (classes[yp[i*N+j].max (dim=0 )[1 ]])) plt.setp(title, color=('g' if yp[i*N+j].max (dim=0 )[1 ] == y[i*N+j] else 'r' )) ax[i][j].set_axis_off() plt.tight_layout()
导入必要的深度学习库和工具包,包括PyTorch框架用于模型构建和训练,torchvision用于数据处理,numpy和matplotlib用于数值计算和结果可视化。
定义CIFAR-10数据集的10个类别名称,准备后续的分类标签显示。
实现图像可视化函数plot_images,用于展示模型预测结果,该函数能够将标准化后的图像张量还原为可视格式,并用颜色编码区分正确和错误预测。
CIFAR10Model架构设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 class CIFAR10Model (nn.Module): def __init__ (self ): super (CIFAR10Model, self ).__init__() self .conv1 = nn.Sequential( nn.Conv2d(3 , 32 , 3 , padding=1 ), nn.BatchNorm2d(32 ), nn.ReLU() ) self .conv2 = nn.Sequential( nn.Conv2d(32 , 32 , 3 , padding=1 ), nn.BatchNorm2d(32 ), nn.ReLU() ) self .pool1 = nn.MaxPool2d(2 , 2 ) self .conv3 = nn.Sequential( nn.Conv2d(32 , 64 , 3 , padding=1 ), nn.BatchNorm2d(64 ), nn.ReLU() ) self .conv4 = nn.Sequential( nn.Conv2d(64 , 64 , 3 , padding=1 ), nn.BatchNorm2d(64 ), nn.ReLU() ) self .pool2 = nn.MaxPool2d(2 , 2 ) self .conv5 = nn.Sequential( nn.Conv2d(64 , 128 , 3 , padding=1 ), nn.BatchNorm2d(128 ), nn.ReLU() ) self .conv6 = nn.Sequential( nn.Conv2d(128 , 128 , 3 , padding=1 ), nn.BatchNorm2d(128 ), nn.ReLU() ) self .pool3 = nn.MaxPool2d(2 , 2 ) self .output = nn.Sequential( nn.Linear(4 *4 *128 , 512 ), nn.BatchNorm1d(512 ), nn.ReLU(), nn.Linear(512 , 10 ), nn.Softmax(dim=1 ) ) def forward (self, x ): x = self .conv1(x) x = self .conv2(x) x = self .pool1(x) x = self .conv3(x) x = self .conv4(x) x = self .pool2(x) x = self .conv5(x) x = self .conv6(x) x = self .pool3(x) x = x.view(-1 , 4 *4 *128 ) x = self .output(x) return x
CIFAR10Model采用经典的卷积神经网络架构。网络包含三个特征提取阶段,每个阶段由卷积层、批归一化层、激活函数和池化层组成精心设计的序列。
在第一特征提取阶段,网络处理32×32×3的输入图像。首先通过3×3卷积核配合padding=1保持空间分辨率不变,将通道数从3提升至32。这种设计选择基于多重考虑:3×3是VGG网络验证的高效卷积核尺寸,在感受野与参数数量间取得良好平衡;padding=1确保特征图尺寸保持不变,避免边缘信息损失;通道数提升为后续的特征学习提供足够的表达能力。紧接着的批归一化层通过规范化激活值分布,有效缓解深度网络训练中的内部协变量偏移问题,允许使用更高的学习率并减少对参数初始化的敏感度。ReLU激活函数引入非线性变换,增强模型的表达能力。
下采样策略采用2×2最大池化,这一设计在空间信息压缩和特征保留间达成平衡。最大池化操作提供了一定的平移不变性,同时保留最显著的特征响应。网络通过三次这样的下采样过程,将空间维度从32×32逐步压缩至4×4,同时通道数按照32→64→128的规律倍增。
特征提取完成后,4×4×128的特征图通过view
操作展平为2048维向量,进入全连接分类器模块。分类器采用两层全连接网络设计,首层将2048维特征映射到512维隐藏空间。这一维度选择经过精心考量:过高的维度会增加过拟合风险,过低的维度会限制模型表达能力。512维隐藏层在两者间取得平衡,既提供足够的容量学习复杂决策边界,又避免过度参数化。
批归一化层在分类器中继续发挥作用,稳定训练过程。最后的输出层通过10维全连接层配合Softmax激活函数,将隐藏层输出转换为类别概率分布。
CIFAR10Model训练与测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 def train (model, optimizer, trainloader, epoch, device, pretrain=None ): if pretrain is None : init_epoch = 0 loss = nn.CrossEntropyLoss() else : checkpoint = torch.load(pretrain) model.load_state_dict(checkpoint['model_state_dict' ]) optimizer.load_state_dict(checkpoint['optimizer_state_dict' ]) init_epoch = checkpoint['epoch' ] loss = checkpoint['loss' ] for ep in range (init_epoch, epoch): running_loss = 0.0 for i, (inputs, labels) in enumerate (trainloader, 0 ): inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) l = loss(outputs, labels) optimizer.zero_grad() l.backward() optimizer.step() running_loss += l.item() print ('epoch: %d, loss: %.4f' % (ep, running_loss / len (trainloader))) running_loss = 0.0 torch.save({'epoch' : ep, 'model_state_dict' : model.state_dict(), 'optimizer_state_dict' : optimizer.state_dict(), 'loss' : loss}, 'weights.tar' ) print ('Finish Training' ) def test (model, testloader, device, visible=True ): correct = 0 total = 0 for images, labels in testloader: images, labels = images.to(device), labels.to(device) outputs = model(images) total += labels.size(0 ) correct += (outputs.max (dim=1 )[1 ] == labels).sum ().item() print ('Accuracy of the network on the test images: %.3f %%' % (100.0 * correct / total)) if visible: plot_images(images, labels, outputs, 5 , 5 )
1 2 3 4 5 6 model = CIFAR10Model() model = model.to(device) optimizer = optim.Adam(model.parameters(), lr=learning_rate) train(model, optimizer, trainloader, epoch, device)
标准训练过程使用Adam优化器配合交叉熵损失函数。Adam优化器结合了动量法和RMSProp的优点,通过计算梯度的一阶矩估计和二阶矩估计,为不同参数设计独立的自适应学习率。学习率设置为0.005,这一数值经过初步实验验证,能够在收敛速度和稳定性间取得良好平衡。
训练配置采用批量大小200,这一选择基于计算效率和梯度估计质量的综合考量。较大的批量大小提供更准确的梯度估计方向,有利于训练的稳定性;同时考虑到GPU内存限制,200是一个在实践中被证明有效的折中值。训练周期设置为50个epoch,确保模型有足够的机会收敛到令人满意的局部最优解,同时通过观察损失曲线避免过拟合。
损失从初始2.01逐步下降至1.50以下,显示模型有效学习。每轮损失平稳下降,未出现明显过拟合。
CIFAR10Model性能评估
1 2 3 model.eval () test(model, testloader, device)
Accuracy of the network on the test images: 81.730 %
标准训练后模型在测试集上达到81.73% 的准确率,证明网络架构设计的有效性。可视化结果显示模型对结构清晰的类别(车辆、船等)识别准确,但在细粒度分类(猫狗区分)上仍存在挑战。
FGSM对抗攻击实施
FGSM(快速梯度符号方法)利用模型梯度信息生成对抗样本
1 2 3 4 5 6 def fgsm (model, X, y, device, epsilon=0.1 ): delta = torch.zeros_like(X, requires_grad=True ).to(device) loss = nn.CrossEntropyLoss() loss_val = loss(model(X + delta), y) loss_val.backward() return epsilon * delta.grad.detach().sign()
梯度计算 :通过前向传播计算损失,反向传播获取输入梯度
扰动生成 :使用梯度符号确定扰动方向,ε控制扰动幅度
视觉不可感知性 :小幅度扰动(ε=0.1)
1 2 3 4 5 6 7 8 for X, y in testloader: X, y = X.to(device), y.to(device) break delta = fgsm(model, X, y, device) yp = model(X+delta) plot_images(X+delta, y, yp, 5 , 5 )
青蛙和卡车的攻击成功率较低。
1 2 3 4 5 6 7 8 9 10 11 12 correct = 0 total = 0 for images, labels in testloader: images, labels = images.to(device), labels.to(device) delta = fgsm(model, images, labels, device) outputs = model(images+delta) total += labels.size(0 ) correct += (outputs.max (dim=1 )[1 ] == labels).sum ().item() print ('Accuracy of the network on the test images: %.3f %%' % (100.0 * correct / total))
Accuracy of the network on the test images: 19.450 %
在ε=0.1的FGSM攻击下,标准训练模型的性能下降,测试准确率从81.730%急剧降至19.450%。
对抗训练策略实施
训练过程中的随机选择机制确保每个训练批次都是原始样本和对抗样本的混合。
从优化理论的角度,对抗训练可以形式化为一个min-max问题:外层优化最小化模型在对抗样本上的期望损失,内层优化寻找使损失最大化的对抗扰动。
从正则化的角度理解,对抗训练实质上引入了一种特殊的数据增强形式,通过显式地扩大训练数据的覆盖范围,迫使模型学习更加平滑和鲁棒的决策边界。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 def train_adv (model, optimizer, trainloader, epoch, device, pretrain=None , ratio=0.8 , epsilon=0.2 ): if pretrain is None : init_epoch = 0 loss = nn.CrossEntropyLoss() else : checkpoint = torch.load(pretrain) model.load_state_dict(checkpoint['model_state_dict' ]) optimizer.load_state_dict(checkpoint['optimizer_state_dict' ]) init_epoch = checkpoint['epoch' ] loss = checkpoint['loss' ] for ep in range (init_epoch, epoch): running_loss = 0.0 for i, (images, labels) in enumerate (trainloader, 0 ): images, labels = images.to(device), labels.to(device) delta = fgsm(model, images, labels, device, epsilon) outputs = model(images+delta if random.random() < ratio else images) l = loss(outputs, labels) optimizer.zero_grad() l.backward() optimizer.step() running_loss += l.item() print ('epoch: %d, loss: %.4f' % (ep, running_loss / len (trainloader))) running_loss = 0.0 torch.save({'epoch' : ep, 'model_state_dict' : model.state_dict(), 'optimizer_state_dict' : optimizer.state_dict(), 'loss' : loss}, 'weights_adv.tar' ) print ('Finish Training' )
混合比例(ratio=0.8) :80%训练样本使用对抗版本,平衡鲁棒性与准确率
扰动幅度(epsilon=0.2) :增强训练时的扰动强度,提升模型鲁棒性边界
随机选择机制 :确保每个批次包含原始样本和对抗样本
1 2 3 4 5 6 7 model_adv = CIFAR10Model() model_adv = model_adv.to(device) optimizer = optim.Adam(model_adv.parameters(), lr=learning_rate) train_adv(model_adv, optimizer, trainloader, 50 , device)
损失从初始2.23逐步下降至1.51以下,显示模型有效学习。每轮损失平稳下降,未出现明显过拟合。
对抗训练效果评估与对比分析
1 2 3 model_adv.eval () test(model_adv, testloader, device)
1 2 3 4 5 6 7 8 9 10 11 12 13 correct = 0 total = 0 for images, labels in testloader: images, labels = images.to(device), labels.to(device) delta = fgsm(model_adv, images, labels, device) outputs = model_adv(images+delta) total += labels.size(0 ) correct += (outputs.max (dim=1 )[1 ] == labels).sum ().item() print ('Accuracy of the network on the test images: %.3f %%' % (100.0 * correct / total))
Accuracy of the network on the test images: 63.140 %
经过对抗训练的模型在面对相同FGSM攻击时,准确率从标准模型的19.450%显著提升至63.140% ,证明对抗训练有效增强了模型对对抗样本的防御能力。
对抗训练在提升鲁棒性的同时,对原始测试集的准确率产生一定影响,从81.73%轻微下降,这体现了准确率与鲁棒性权衡。
总结与心得
对抗训练导致标准准确率轻微下降,并非模型性能缺陷,而是其实现鲁棒性提升的内在机制所引致的必然结果。其核心原理可归结为以下三点:
优化目标的根本性改变 :
标准训练旨在最小化模型在自然数据分布 上的期望损失。而对抗训练求解的是一个更严格的极小极大问题 ,其目标是最小化模型在最坏情况扰动 下的期望损失。这个更苛刻的优化目标极大地约束了可行的模型假设空间,迫使模型放弃那些仅在纯净数据上表现最优、但对扰动高度敏感的复杂假设。
决策边界的正则化与平滑化 :
标准训练得到的决策边界为追求高准确率,往往在数据点附近呈现高度非线性与复杂性 ,这使其对微小扰动极为脆弱。对抗训练则作为一种强大的显式正则化 ,强制决策边界在样本的局部邻域内保持平滑与线性 。这种更简单、更稳定的边界虽然能有效抵御攻击,但也必然损失其对原始数据分布中某些复杂模式的极致拟合能力,导致对部分自然样本的分类能力下降。
特征表示的范式转移 :
从表示学习的视角看,对抗训练引导模型发生根本性的特征学习转变。它迫使模型摒弃那些虽具统计判别力但非因果性的表面关联特征 (例如,特定的纹理模式),转而依赖那些在输入变化下保持不变的本质不变性特征 (例如,物体的整体形状)。这种对稳健特征的归纳偏置,虽然显著提升了模型的抗干扰能力,但可能不足以完美捕捉自然图像中全部细微的判别性细节。
准确率与鲁棒性之间的权衡,深刻揭示了模型容量在标准风险与对抗风险之间的再分配。对抗训练通过系统性地约束假设空间和引入强归纳偏置,将模型从“高精度、高脆弱性 ”的状态引导至“精度可接受、高稳健性 ”的状态。