Pytorch实现FGSM(Fast Gradient Sign Attack)
目錄
- 1. 相關(guān)說明
- 2. 相關(guān)簡(jiǎn)述
- 3. 代碼實(shí)現(xiàn)
- 3.1 引入相關(guān)包
- 3.2 輸入
- 3.3 定義被攻擊的模型
- 3.4 定義FGSM攻擊函數(shù)
- 3.5 測(cè)試函數(shù)
- 4. 可視化結(jié)果
- 5. 可視化對(duì)抗樣本
- 6. 預(yù)訓(xùn)練模型下載
- 7. 訓(xùn)練模型
- 8. 完整代碼
1. 相關(guān)說明
最近在整理相關(guān)實(shí)驗(yàn)代碼的時(shí)候,無意中需要重新梳理下對(duì)抗攻擊里的FGSM,于是自己參考網(wǎng)上的一些資料以及自己的心得寫下這篇文章,用來以后回憶。
2. 相關(guān)簡(jiǎn)述
快速梯度標(biāo)志攻擊(FGSM),是迄今為止最早和最受歡迎的對(duì)抗性攻擊之一,它由 Goodfellow 等人在[Explaining and Harnessing Adversarial Examples] (https://arxiv.org/abs/1412.6572)中提出,是一種簡(jiǎn)單但是有效的對(duì)抗樣本生成算法。它旨在通過利用模型學(xué)習(xí)的方式和漸變來攻擊神經(jīng) 網(wǎng)絡(luò)。這個(gè)想法很簡(jiǎn)單,攻擊調(diào)整輸入數(shù)據(jù)以基于相同的反向傳播梯度來最大化損失,而不是通過基于反向傳播的梯度調(diào)整權(quán)重來最小化損失。 換句話說,攻擊是利用損失函數(shù)的梯度,然后調(diào)整輸入數(shù)據(jù)以最大化損失。
3. 代碼實(shí)現(xiàn)
3.1 引入相關(guān)包
# 這句話的作用:即使是在Python2.7版本的環(huán)境下,print功能的使用格式也遵循Python3.x版本中的加括號(hào)的形式 from __future__ import print_function import torch import torch.nn as nn import torch.nn.functional as F from torchvision import datasets, transforms import numpy as np import matplotlib.pyplot as plt3.2 輸入
# 設(shè)置不同擾動(dòng)大小epsilons = [0, .05, .1, .15, .2, .25, .3]# 預(yù)訓(xùn)練模型pretrained_model = "./data/lenet_mnist_model.pth"# 是否使用cudause_cuda = True3.3 定義被攻擊的模型
# 定義LeNet模型 class Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(1, 10, kernel_size=5)self.conv2 = nn.Conv2d(10, 20, kernel_size=5)self.conv2_drop = nn.Dropout2d()self.fc1 = nn.Linear(320, 50)self.fc2 = nn.Linear(50, 10)def forward(self, x):x = F.relu(F.max_pool2d(self.conv1(x), 2))x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))x = x.view(-1, 320)x = F.relu(self.fc1(x))x = F.dropout(x, training=self.training)x = self.fc2(x)return F.log_softmax(x, dim=1)#聲明 MNIST 測(cè)試數(shù)據(jù)集何數(shù)據(jù)加載 test_loader = torch.utils.data.DataLoader(datasets.MNIST('../data', train=False, download=True, transform=transforms.Compose([transforms.ToTensor(),])),batch_size=1, shuffle=True)# 定義我們正在使用的設(shè)備 print("CUDA Available: ",torch.cuda.is_available()) device = torch.device("cuda" if (use_cuda and torch.cuda.is_available()) else "cpu")# 初始化網(wǎng)絡(luò) model = Net().to(device)# 加載已經(jīng)預(yù)訓(xùn)練的模型 model.load_state_dict(torch.load(pretrained_model, map_location='cpu'))# 在評(píng)估模式下設(shè)置模型。在這種情況下,這適用于Dropout圖層 model.eval()然后我們運(yùn)行下,出現(xiàn)下面結(jié)果,主要是在下載數(shù)據(jù)集。
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to …/data/MNIST/raw/train-images-idx3-ubyte.gz
Extracting …/data/MNIST/raw/train-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to …/data/MNIST/raw/train-labels-idx1-ubyte.gz
Extracting …/data/MNIST/raw/train-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to …/data/MNIST/raw/t10k-images-idx3-ubyte.gz
Extracting …/data/MNIST/raw/t10k-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to …/data/MNIST/raw/t10k-labels-idx1-ubyte.gz
Extracting …/data/MNIST/raw/t10k-labels-idx1-ubyte.gz
Processing…
Done!
CUDA Available: True
3.4 定義FGSM攻擊函數(shù)
# FGSM算法攻擊代碼 def fgsm_attack(image, epsilon, data_grad):# 收集數(shù)據(jù)梯度的元素符號(hào)sign_data_grad = data_grad.sign()# 通過調(diào)整輸入圖像的每個(gè)像素來創(chuàng)建擾動(dòng)圖像perturbed_image = image + epsilon*sign_data_grad# 添加剪切以維持[0,1]范圍perturbed_image = torch.clamp(perturbed_image, 0, 1)# 返回被擾動(dòng)的圖像return perturbed_image3.5 測(cè)試函數(shù)
def test( model, device, test_loader, epsilon ):# 精度計(jì)數(shù)器correct = 0adv_examples = []# 循環(huán)遍歷測(cè)試集中的所有示例for data, target in test_loader:# 把數(shù)據(jù)和標(biāo)簽發(fā)送到設(shè)備data, target = data.to(device), target.to(device)# 設(shè)置張量的requires_grad屬性,這對(duì)于攻擊很關(guān)鍵data.requires_grad = True# 通過模型前向傳遞數(shù)據(jù)output = model(data)init_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability# 如果初始預(yù)測(cè)是錯(cuò)誤的,不打斷攻擊,繼續(xù)if init_pred.item() != target.item():continue# 計(jì)算損失loss = F.nll_loss(output, target)# 將所有現(xiàn)有的漸變歸零model.zero_grad()# 計(jì)算后向傳遞模型的梯度loss.backward()# 收集datagraddata_grad = data.grad.data# 喚醒FGSM進(jìn)行攻擊perturbed_data = fgsm_attack(data, epsilon, data_grad)# 重新分類受擾亂的圖像output = model(perturbed_data)# 檢查是否成功final_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probabilityif final_pred.item() == target.item():correct += 1# 保存0 epsilon示例的特例if (epsilon == 0) 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) )# 計(jì)算這個(gè)epsilon的最終準(zhǔn)確度final_acc = correct/float(len(test_loader))print("Epsilon: {}\tTest Accuracy = {} / {} = {}".format(epsilon, correct, len(test_loader), final_acc))# 返回準(zhǔn)確性和對(duì)抗性示例return final_acc, adv_examples再次運(yùn)行,輸出下面結(jié)果:
Epsilon: 0 Test Accuracy = 9810 / 10000 = 0.981
Epsilon: 0.05 Test Accuracy = 9426 / 10000 = 0.9426
Epsilon: 0.1 Test Accuracy = 8510 / 10000 = 0.851
Epsilon: 0.15 Test Accuracy = 6826 / 10000 = 0.6826
Epsilon: 0.2 Test Accuracy = 4303 / 10000 = 0.4303
Epsilon: 0.25 Test Accuracy = 2087 / 10000 = 0.2087
Epsilon: 0.3 Test Accuracy = 871 / 10000 = 0.0871
4. 可視化結(jié)果
在上面的基礎(chǔ)上我們添加下面的代碼:
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()運(yùn)行,出現(xiàn)下面結(jié)果:
5. 可視化對(duì)抗樣本
# 在每個(gè)epsilon上繪制幾個(gè)對(duì)抗樣本的例子 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()運(yùn)行,結(jié)果如下:
6. 預(yù)訓(xùn)練模型下載
文中我們有一個(gè)預(yù)訓(xùn)練好的模型,如果自己不想訓(xùn)練可以在這里下載:
模型下載地址
7. 訓(xùn)練模型
如果自己想訓(xùn)練一個(gè)模型,可以運(yùn)行下面這個(gè)函數(shù)main.py:
from __future__ import print_function import argparse import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms from torch.optim.lr_scheduler import StepLR# 定義LeNet模型 class Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(1, 10, kernel_size=5)self.conv2 = nn.Conv2d(10, 20, kernel_size=5)self.conv2_drop = nn.Dropout2d()self.fc1 = nn.Linear(320, 50)self.fc2 = nn.Linear(50, 10)def forward(self, x):x = F.relu(F.max_pool2d(self.conv1(x), 2))x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))x = x.view(-1, 320)x = F.relu(self.fc1(x))x = F.dropout(x, training=self.training)x = self.fc2(x)return F.log_softmax(x, dim=1)def train(args, model, device, train_loader, optimizer, epoch):model.train()for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device)optimizer.zero_grad()output = model(data)loss = F.nll_loss(output, target)loss.backward()optimizer.step()if batch_idx % args.log_interval == 0:print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(epoch, batch_idx * len(data), len(train_loader.dataset),100. * batch_idx / len(train_loader), loss.item()))if args.dry_run:breakdef test(model, device, test_loader):model.eval()test_loss = 0correct = 0with torch.no_grad():for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch losspred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probabilitycorrect += pred.eq(target.view_as(pred)).sum().item()test_loss /= len(test_loader.dataset)print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(test_loss, correct, len(test_loader.dataset),100. * correct / len(test_loader.dataset)))def main():# Training settingsparser = argparse.ArgumentParser(description='PyTorch MNIST Example')parser.add_argument('--batch-size', type=int, default=64, metavar='N',help='input batch size for training (default: 64)')parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',help='input batch size for testing (default: 1000)')parser.add_argument('--epochs', type=int, default=14, metavar='N',help='number of epochs to train (default: 14)')parser.add_argument('--lr', type=float, default=1.0, metavar='LR',help='learning rate (default: 1.0)')parser.add_argument('--gamma', type=float, default=0.7, metavar='M',help='Learning rate step gamma (default: 0.7)')parser.add_argument('--no-cuda', action='store_true', default=False,help='disables CUDA training')parser.add_argument('--dry-run', action='store_true', default=False,help='quickly check a single pass')parser.add_argument('--seed', type=int, default=1, metavar='S',help='random seed (default: 1)')parser.add_argument('--log-interval', type=int, default=10, metavar='N',help='how many batches to wait before logging training status')parser.add_argument('--save-model', action='store_true', default=True,help='For Saving the current Model')args = parser.parse_args()use_cuda = not args.no_cuda and torch.cuda.is_available()torch.manual_seed(args.seed)device = torch.device("cuda" if use_cuda else "cpu")train_kwargs = {'batch_size': args.batch_size}test_kwargs = {'batch_size': args.test_batch_size}if use_cuda:cuda_kwargs = {'num_workers': 1,'pin_memory': True,'shuffle': True}train_kwargs.update(cuda_kwargs)test_kwargs.update(cuda_kwargs)transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])dataset1 = datasets.MNIST('../data_row', train=True, download=True,transform=transform)dataset2 = datasets.MNIST('../data_row', train=False,transform=transform)train_loader = torch.utils.data.DataLoader(dataset1,**train_kwargs)test_loader = torch.utils.data.DataLoader(dataset2, **test_kwargs)model = Net().to(device)optimizer = optim.Adadelta(model.parameters(), lr=args.lr)scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma)for epoch in range(1, args.epochs + 1):train(args, model, device, train_loader, optimizer, epoch)test(model, device, test_loader)scheduler.step()# 保存網(wǎng)絡(luò)中的參數(shù), 速度快,占空間少if args.save_model:torch.save(model.state_dict(), "lenet_mnist_model.pth")if __name__ == '__main__':main()8. 完整代碼
上面是將每個(gè)模塊單獨(dú)拿出來寫的,需要完整代碼的可以在我的GitHub上下載,如果您覺得好的話記得給個(gè)Star。
完整代碼鏈接地址
總結(jié)
以上是生活随笔為你收集整理的Pytorch实现FGSM(Fast Gradient Sign Attack)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab中小波工具箱,matlab小
- 下一篇: 永久解决VSCode终端中文乱码问题