【对抗算法复现】FGSM

FGSM

先训练一个神经网络的模型 LeNet

下载数据集并可视化
# 这句话的作用:即使是在Python2.7版本的环境下,print功能的使用格式也遵循Python3.x版本中的加括号的形式
from __future__ import print_function

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
from torch import nn

#加载数据集
mnist_train=torchvision.datasets.MNIST(root='datasets',train=True,download=True,transform=torchvision.transforms.ToTensor())
mnist_test=torchvision.datasets.MNIST(root='datasets',train=False,download=True,transform=torchvision.transforms.ToTensor())
# print(len(mnist_train))60000
# print(len(mnist_test))10000
imgs,target=mnist_train[0]
# print(feature.shape,label)打印图像大小torch.Size([1, 28, 28]),标签5
dataloader=DataLoader(mnist_test,batch_size=64,num_workers=0)#每次加载64张,num_workers 参数是用于指定用于数据加载的子进程数量的参数
step=0
writer=SummaryWriter(log_dir='runs/mnist')#可视化,在terminal中注意使用绝对路径
for data in dataloader:
    imgs,target=data
    writer.add_images(tag='train',img_tensor=imgs,global_step=step)
    step+=1
writer.close()

此处注意先激活环境,然后使用绝对路径
在这里插入图片描述
在这里插入图片描述

模型搭建

在这里插入图片描述

#定义lenet模型
from torch import nn


class LeNet(nn.Module):
    def __init__(self):
        super(LeNet,self).__init__()
        self.model1=nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2),
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Flatten(),
            nn.Linear(in_features=16 * 5 * 5, out_features=120),
            nn.Sigmoid(),
            nn.Linear(120, 84),
            nn.Sigmoid(),
            nn.Linear(in_features=84, out_features=10)
        )
    def forward(self,x):
        return self.model1(x)

# leNet=LeNet()
# print(leNet)

在这里插入图片描述

完整代码
# 这句话的作用:即使是在Python2.7版本的环境下,print功能的使用格式也遵循Python3.x版本中的加括号的形式
from __future__ import print_function

import torch.optim
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
from torch import nn

#加载数据集
mnist_train=torchvision.datasets.MNIST(root='datasets',train=True,download=True,transform=torchvision.transforms.ToTensor())
mnist_test=torchvision.datasets.MNIST(root='datasets',train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloader_train=DataLoader(mnist_train,batch_size=64,num_workers=0)
dataloader_test=DataLoader(mnist_test,batch_size=64,num_workers=0)
#模型搭建
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet,self).__init__()
        self.model1=nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2),
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Flatten(),
            nn.Linear(in_features=16 * 5 * 5, out_features=120),
            nn.Sigmoid(),
            nn.Linear(120, 84),
            nn.Sigmoid(),
            nn.Linear(in_features=84, out_features=10)
        )
    def forward(self,x):
        return self.model1(x)

#创建模型
leNet=LeNet()
#损失函数
loss_fn=nn.CrossEntropyLoss()
#优化器
learning_rate=1e-2
optimizer=torch.optim.Adam(leNet.parameters(),lr=learning_rate)
total_train_step=0#记录训练次数
epoch=10#训练次数
writer=SummaryWriter(log_dir='runs/LeNet')
#训练
for i in range(epoch):
    print("-------第{}轮训练开始-------".format(i+1))
    leNet.train()
    train_loss=0
    for data in dataloader_train:
        imgs,target=data
        outputs=leNet(imgs)
        loss=loss_fn(outputs,target)
        optimizer.zero_grad()
        loss.backward()#反向传播
        optimizer.step()#更新参数
        total_train_step+=1
        train_loss+=loss.item()
        writer.add_scalar('train_loss_detail',loss.item(),total_train_step)
    writer.add_scalar('train_loss_total',train_loss,i+1)


    leNet.eval()  # 测试模式
    total_test_loss = 0  # 当前轮次模型测试所得损失
    total_accuracy = 0  # 当前轮次精确率
    with torch.no_grad():  # 关闭梯度反向传播
        for data in dataloader_test:
            imgs, targets = data
            outputs = leNet(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss.item()
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy
    writer.add_scalar("test_loss", total_test_loss, i + 1)
    writer.add_scalar("test_accuracy", total_accuracy / len(mnist_test), i + 1)

torch.save(leNet,'models/LeNet.pth')#注意这里必须要手动建母文件models,否则会报错
# leNet=torch.load('./models/LeNet') 加载模型
writer.close()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

FGSM

剪切

在迭代更新过程中,随着迭代次数的增加,部分像素值可能会溢出。比如超出0到1 的范围,此时需将这些值用0或者1 代替,最后才能生成有效的图像。该过程确保了新样本的各个像素和在原样本各像素的某一邻域内,不至于失真。
在这里插入图片描述

import numpy as np
import torch.utils.data
from torch import nn
from torchvision import datasets, transforms
import torch.nn.functional as F
import matplotlib.pyplot as plt
import os
os.environ['KMP_DUPLICATE_LIB_OK']='TRUE'


epsilons=[0,.05,.1,.15,.2,.25,.3]
pretrained_model='models/LeNet.pth'
test_loader=torch.utils.data.DataLoader(
    datasets.MNIST('datasets/MNIST',train=False,download=True,transform=transforms.ToTensor()),
                    batch_size=1,
                    shuffle=True#是否对训练数据进行洗牌的操作
)

#定义网络模型
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet,self).__init__()
        self.model1=nn.Sequential(
            nn.Conv2d(1,6,5,2),
            nn.Sigmoid(),
            nn.AvgPool2d(6,2),
            nn.Conv2d(6,16,5,1),
            nn.Sigmoid(),
            nn.AvgPool2d(2,2),
            nn.Flatten(),
            nn.Linear(16*5*5,120),
            nn.Sigmoid(),
            nn.Linear(120,84),
            nn.Sigmoid(),
            nn.Linear(84,10)
        )
    def forward(self,x):
        return self.model1(x)

model=torch.load('models/LeNet.pth')
# print(model)
#在评估模式下设置模型
model.eval()

def fgsm_attack(image,epsilon,data_grad):
    """
    :param image: 被攻击的图像
    :param epsilon: 扰动值的范围
    :param data_grad:图像的梯度
    :return:扰动后的图像
    """
    #收集数据梯度的元素符号
    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

#开始攻击
def test(model,test_loader,epsilon):
    #计数器
    correct=0
    adv_examples=[]

    #循环遍历测试集中的所有示例
    for data,target in test_loader:
        data.requires_grad=True#用于指示是否要对张量进行梯度运算
        output=model(data)
        init_pred=output.max(1,keepdim=True)[1]

        #如果初始预测是错误的,不断地攻击
        if init_pred.item()!=target.item():
            continue

        #计算损失
        loss=F.nll_loss(output,target)
        model.zero_grad()
        loss.backward()
        data_grad=data.grad.data
        perturbed_data=fgsm_attack(data,epsilon,data_grad)#使用fgsm进行攻击
        output=model(perturbed_data)#重新分类收到扰乱的图像
        #检查是否成功
        final_pred=output.max(1,keepdim=True)[1]
        if final_pred.item()==target.item():
            correct=correct+1
            if(epsilon==1)and (len(adv_examples)<5):
                adv_ex=perturbed_data.squeeze().detach().cpu().numpy()
                adv_examples.append((init_pred.item(),final_pred.item(),adv_ex))
        else:
            #用于可视化
            if len(adv_examples)<5:
                adv_ex = perturbed_data.squeeze().detach().cpu().numpy()
                adv_examples.append((init_pred.item(), final_pred.item(), adv_ex))

    #计算该epsilon的最终准确度
    final_acc=correct/float(len(test_loader))
    print("Epsilon: {}\tTest Accuracy = {} / {} = {}".format(epsilon, correct, len(test_loader), final_acc))

    return final_acc,adv_examples
accuracies=[]
examples=[]
#开始测试
for eps in epsilons:
    acc,ex=test(model,test_loader,eps)
    accuracies.append(acc)
    examples.append(ex)

plt.figure(figsize=(5, 5))
plt.plot(epsilons, accuracies, "*-")
plt.yticks(np.arange(0, 1.1, step=0.1))
plt.xticks(np.arange(0, .35, step=0.05))
plt.title("Accuracy vs Epsilon")
plt.xlabel("Epsilon")
plt.ylabel("Accuracy")
plt.show()

# 在每个epsilon上绘制几个对抗样本的例子
cnt = 0
plt.figure(figsize=(8, 10))
for i in range(len(epsilons)):
    for j in range(len(examples[i])):
        cnt += 1
        plt.subplot(len(epsilons), len(examples[0]), cnt)
        plt.xticks([], [])
        plt.yticks([], [])
        if j == 0:
            plt.ylabel("Eps: {}".format(epsilons[i]), fontsize=14)
        orig, adv, ex = examples[i][j]
        plt.title("{} -> {}".format(orig, adv))
        plt.imshow(ex, cmap="gray")
plt.tight_layout()
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Fast Gradient Sign Method (FGSM) 是一种用于生成对抗样本的基本方法,它利用了梯度信息来最小幅度地修改输入数据,使其对模型的预测产生误导。在 Python 中,你可以使用深度学习库如 TensorFlow 或 PyTorch 来实现 FGSM。以下是一个简化的示例,用 TensorFlow 来展示如何在 Keras API 中应用 FGSM: ```python import tensorflow as tf from tensorflow.keras import layers, models # 假设我们有一个简单的线性模型 def create_model(input_shape): model = models.Sequential() model.add(layers.Dense(64, activation='relu', input_shape=input_shape)) model.add(layers.Dense(1, activation='sigmoid')) return model # 加载预训练模型或根据需求创建 model = create_model((28, 28, 1)) # 假设我们有一个图片和标签 input_data = tf.keras.Input(shape=(28, 28, 1)) label = tf.keras.Input(shape=(), dtype='float32') # 单分类问题,如果多分类则应为 int32 类型 # 使用模型并获取损失值 logits = model(input_data) loss = tf.keras.losses.binary_crossentropy(label, logits) # 获取梯度 grads = tf.gradients(loss, input_data) # FGSM 函数 def fgsm_attack(image, label, epsilon=0.1): perturbed_image = image + epsilon * tf.sign(grads) perturbed_image = tf.clip_by_value(perturbed_image, 0, 1) # 确保图像像素值在 [0, 1] 区间内 return perturbed_image # 示例使用 epsilon = 0.1 # 攻击强度 perturbed_image = fgsm_attack(input_data, label, epsilon) pred = model(perturbed_image) # 预测受影响的图片 # 注意:在实际应用中,你需要先将模型转换为可训练模式(.trainable=True),这里为了简洁省略了这部分 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值