FGSM生成对抗样本(MNIST数据集)Pytorch代码实现与实验分析

1 实验目标

  1. pytorch实现fgsm attack
  2. 原始样本、对抗样本与对抗扰动的可视化
  3. 探究不同epsilon值对accuracy的影响

2 实验流程

  1. 搭建LeNet网络训练MNIST分类模型,测试准确率。
  2. 生成不同epsilon值的对抗样本,送入训练好的模型,再次测试准确率,得到结果

2.1 搭建LeNet训练,测试准确度

导入pytorch必要库

import os.path

import torch
import torchvision
import torchvision.transforms as transforms
from torch import nn
from torch.utils.data import DataLoader

import numpy as np
import matplotlib.pyplot as plt

加载torchvision中的MNIST数据集

train_data = torchvision.datasets.MNIST(
    root='data',
    train=True,
    download=True,
    transform=transforms.ToTensor()
)
test_data = torchvision.datasets.MNIST(
    root='data',
    train=False,
    download=True,
    transform=transforms.ToTensor()
)

batch_size = 64

train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size)
test_dataloader = DataLoader(dataset=test_data, batch_size=batch_size)

matplotlib展示MNIST图像

plt.figure(figsize=(8, 8))
iter_dataloader = iter(test_dataloader)

n=1

# 取出n*batch_size张图片可视化
for i in range(n):
    images, labels = next(iter_dataloader)
    image_grid = torchvision.utils.make_grid(images)
    plt.subplot(1, n, i+1)
    plt.imshow(np.transpose(image_grid.numpy(), (1, 2, 0)))

MNIST
转移到GPU训练

device = 'cuda:0' if torch.cuda.is_available() else 'cpu'
print(device)

搭建LeNet网络

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet,self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1,6,3,stride=1,padding=1),
            nn.MaxPool2d(2,2),
            nn.Conv2d(6,16,5,stride=1,padding=1),
            nn.MaxPool2d(2,2)
        )
        self.fc = nn.Sequential(
            nn.Linear(576,120),
            nn.Linear(120,84),
            nn.Linear(84,10)
        )
    def forward(self,x):
        out = self.conv(x)
        out = out.view(out.size(0),-1)
        out = self.fc(out)
        return out

定义训练函数

def train(network):

    losses = []
    iteration = 0

    epochs = 10

    for epoch in range(epochs):
        loss_sum = 0
        for i, (X, y) in enumerate(train_dataloader):
            X, y = X.to(device), y.to(device)

            pred = network(X)
            loss = loss_fn(pred, y)

            loss_sum += loss.item()

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

        mean_loss = loss_sum / len(train_dataloader.dataset)
        losses.append(mean_loss)
        iteration += 1
        print(f"Epoch {epoch+1} loss: {mean_loss:>7f}")

    # 训练完毕保存最后一轮训练的模型
    torch.save(network.state_dict(), "model.pth")

    # 绘制损失函数曲线
    plt.xlabel("Epochs")
    plt.ylabel("Loss Value")
    plt.plot(list(range(iteration)), losses)
network = LeNet()
network.to(device)

loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params=network.parameters(), lr=0.001, momentum=0.9)

if os.path.exists('model.pth'):
    network.load_state_dict(torch.load('model.pth'))
else:
    train(network)

得到损失值与损失值图像
loss value
loss value image
对模型进行测试,得到准确度

positive = 0
negative = 0
for X, y in test_dataloader:
    with torch.no_grad():
        X, y = X.to(device), y.to(device)
        pred = network(X)
        for item in zip(pred, y):
            if torch.argmax(item[0]) == item[1]:
                positive += 1
            else:
                negative += 1
acc = positive / (positive + negative)
print(f"{acc * 100}%")

acc

2.2 fgsm生成对抗样本

# 寻找对抗样本,并可视化

eps = [0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]

for X, y in test_dataloader:
    X, y = X.to(device), y.to(device)

    X.requires_grad = True
    pred = network(X)
    network.zero_grad()
    loss = loss_fn(pred, y)
    loss.backward()

    plt.figure(figsize=(15, 8))

    plt.subplot(121)
    image_grid = torchvision.utils.make_grid(torch.clamp(X.grad.sign(), 0, 1))
    plt.imshow(np.transpose(image_grid.cpu().numpy(), (1, 2, 0)))

    X_adv = X + eps[2] * X.grad.sign()
    X_adv = torch.clamp(X_adv, 0, 1)

    plt.subplot(122)
    image_grid = torchvision.utils.make_grid(X_adv)
    plt.imshow(np.transpose(image_grid.cpu().numpy(), (1, 2, 0)))

    break

左图为对抗扰动,右图为对抗样本
对抗扰动与对抗样本

2.3 探究不同epsilon值对分类准确度的影响

# 用对抗样本替代原始样本,测试准确度
# 探究不同epsilon对LeNet分类准确度的影响
positive = 0
negative = 0
acc_list = []
for epsilon in eps:

    for X, y in test_dataloader:
        X, y = X.to(device), y.to(device)

        X.requires_grad = True
        pred = network(X)
        network.zero_grad()
        loss = loss_fn(pred, y)
        loss.backward()

        X = X + epsilon * X.grad.sign()
        X_adv = torch.clamp(X, 0, 1)

        pred = network(X_adv)
        for item in zip(pred, y):
            if torch.argmax(item[0]) == item[1]:
                positive += 1
            else:
                negative += 1

    acc = positive / (positive + negative)
    print(f"epsilon={epsilon} acc: {acc * 100}%")
    acc_list.append(acc)

plt.xlabel("epsilon")
plt.ylabel("Accuracy")
plt.ylim(0, 1)
plt.plot(eps, acc_list, marker='o')

在这里插入图片描述

acc

3 实验结果

对同一个分类模型来说,随着epsilon的增加,fgsm生成的对抗样本使得分类准确度减小

4 完整代码

github: https://github.com/gwcrepo/FGSM-MNIST

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是使用PyTorch实现50次FGSM迭代攻击MNIST数据集并保存对抗样本代码: ```python import torch import torchvision from torchvision import transforms import matplotlib.pyplot as plt # 加载MNIST数据集 transform = transforms.Compose([transforms.ToTensor()]) trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=1, shuffle=True) # 加载预训练的MNIST分类模型 model = torch.load('mnist_model.pth') # 定义FGSM攻击函数 def fgsm_attack(image, epsilon, data_grad): # 收集数据梯度的符号 sign_data_grad = data_grad.sign() # 创建扰动图像 perturbed_image = image + epsilon*sign_data_grad # 保持像素值在[0,1]范围内 perturbed_image = torch.clamp(perturbed_image, 0, 1) return perturbed_image # 迭代FGSM攻击 epsilon = 0.05 # 扰动大小 alpha = 1.0 # 步长 num_iter = 50 # 迭代次数 for i, (images, labels) in enumerate(trainloader): # 将图像和标签转为张量 images = images.requires_grad_().to('cuda') labels = labels.to('cuda') # 执行迭代攻击 perturbed_images = images.clone() for j in range(num_iter): # 计算梯度并得到对抗样本 outputs = model(perturbed_images) loss = torch.nn.functional.cross_entropy(outputs, labels) loss.backward() data_grad = perturbed_images.grad.data perturbed_images = fgsm_attack(perturbed_images, alpha, data_grad) perturbed_images.grad.zero_() # 将对抗样本保存到本地 torchvision.utils.save_image(perturbed_images, f"adversarial_images/{i}.png") # 显示原图像和对抗样本 plt.imshow(torchvision.utils.make_grid(torch.cat([images, perturbed_images]))) plt.show() # 只攻击50张图像 if i == 50: break ``` 该代码通过迭代FGSM攻击生成50张对抗样本,并将它们保存到本地文件夹`adversarial_images`中。执行程序后,可以在生成的每个对抗样本中观察到扰动的效果,如下图所示: ![对抗样本](https://i.imgur.com/jzyBgxB.png)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值