FGSM
先训练一个神经网络的模型 LeNet
下载数据集并可视化
# 这句话的作用:即使是在Python2.7版本的环境下,print功能的使用格式也遵循Python3.x版本中的加括号的形式
from __future__ import print_functionimport 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=datawriter.add_images(tag='train',img_tensor=imgs,global_step=step)step+=1
writer.close()
此处注意先激活环境,然后使用绝对路径
模型搭建
#定义lenet模型
from torch import nnclass 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)# leNet=LeNet()
# print(leNet)
完整代码
# 这句话的作用:即使是在Python2.7版本的环境下,print功能的使用格式也遵循Python3.x版本中的加括号的形式
from __future__ import print_functionimport 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=0for data in dataloader_train:imgs,target=dataoutputs=leNet(imgs)loss=loss_fn(outputs,target)optimizer.zero_grad()loss.backward()#反向传播optimizer.step()#更新参数total_train_step+=1train_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 = dataoutputs = 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 + accuracywriter.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=0adv_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.dataperturbed_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+1if(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 += 1plt.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()