首页
/ 使用CleverHans库实现MNIST对抗训练与攻击防御教程

使用CleverHans库实现MNIST对抗训练与攻击防御教程

2025-07-07 06:47:43作者:管翌锬

概述

本教程将介绍如何使用CleverHans库在MNIST数据集上实现对抗训练和评估模型对对抗攻击的鲁棒性。CleverHans是一个专注于对抗性机器学习的Python库,提供了多种对抗攻击和防御方法的实现。

环境准备

在开始之前,确保已安装以下依赖:

  • PyTorch
  • CleverHans
  • torchvision
  • absl-py

模型架构

教程中提供了两种CNN模型架构:

1. 基础CNN模型

class CNN(torch.nn.Module):
    def __init__(self, in_channels=1):
        super(CNN, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, 64, 8, 1)
        self.conv2 = nn.Conv2d(64, 128, 6, 2)
        self.conv3 = nn.Conv2d(128, 128, 5, 1)
        self.fc1 = nn.Linear(128 * 4 * 4, 128)
        self.fc2 = nn.Linear(128, 10)

该模型包含三个卷积层和两个全连接层,使用ReLU激活函数。

2. PyNet模型

class PyNet(nn.Module):
    def __init__(self, in_channels=1):
        super(PyNet, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

PyNet模型来自PyTorch官方MNIST示例,包含两个卷积层、两个dropout层和两个全连接层。

数据加载

def ld_mnist():
    train_transforms = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
    test_transforms = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
    
    train_dataset = MNISTDataset(root="/tmp/data", transform=train_transforms)
    test_dataset = MNISTDataset(root="/tmp/data", train=False, transform=test_transforms)
    
    train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=128, shuffle=True)
    test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=128, shuffle=False)
    return EasyDict(train=train_loader, test=test_loader)

数据加载函数使用标准的MNIST数据集,应用简单的ToTensor转换,并返回训练和测试数据加载器。

对抗攻击方法

教程中使用了两种经典的对抗攻击方法:

  1. 快速梯度符号法(FGSM)

    • 单步攻击方法
    • 计算损失函数相对于输入的梯度
    • 使用梯度的符号扰动输入
  2. 投影梯度下降法(PGD)

    • 多步迭代攻击方法
    • 被认为是FGSM的"最强"版本
    • 在每次迭代中应用小扰动并在允许的扰动范围内投影

训练流程

训练过程支持两种模式:

  • 普通训练
  • 对抗训练(使用PGD生成的对抗样本)
for epoch in range(1, FLAGS.nb_epochs + 1):
    for x, y in data.train:
        if FLAGS.adv_train:
            x = projected_gradient_descent(net, x, FLAGS.eps, 0.01, 40, np.inf)
        optimizer.zero_grad()
        loss = loss_fn(net(x), y)
        loss.backward()
        optimizer.step()

对抗训练通过在训练过程中使用对抗样本代替原始样本,可以提高模型对对抗攻击的鲁棒性。

评估流程

评估阶段测试模型在三种情况下的表现:

  1. 原始测试数据
  2. FGSM攻击后的数据
  3. PGD攻击后的数据
for x, y in data.test:
    x_fgm = fast_gradient_method(net, x, FLAGS.eps, np.inf)
    x_pgd = projected_gradient_descent(net, x, FLAGS.eps, 0.01, 40, np.inf)
    
    _, y_pred = net(x).max(1)
    _, y_pred_fgm = net(x_fgm).max(1)
    _, y_pred_pgd = net(x_pgd).max(1)

参数配置

教程提供了几个可配置参数:

  • nb_epochs: 训练轮数
  • eps: 对抗扰动的最大幅度
  • adv_train: 是否使用对抗训练
  • model: 选择使用的模型类型(cnn或pynet)

结果分析

运行后会输出三个准确率:

  1. 原始测试数据的准确率
  2. FGSM攻击下的准确率
  3. PGD攻击下的准确率

通过比较这些结果,可以评估模型的鲁棒性。通常,对抗训练会提高模型在对抗攻击下的准确率,但可能会略微降低原始测试数据的准确率。

结论

本教程展示了如何使用CleverHans库实现对抗训练和评估模型对对抗攻击的鲁棒性。对抗训练是提高模型安全性的有效方法之一,特别是在对抗攻击可能存在的应用场景中。通过调整训练参数和模型架构,可以进一步优化模型的性能和鲁棒性。

对于希望深入了解对抗机器学习的开发者,建议尝试不同的攻击参数、探索其他攻击方法,并研究更先进的防御策略。