FGSM实例:利用fgsm攻击RMB识别模型
提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
目錄
一、模型訓練總結回顧
二、對RMB分類模型進行fgsm攻擊
1.fgsm原理
?2.大致思路流程概述
1.求數據集中每個數據集的梯度(以供fgsm生成噪聲)
2.通過fgsm,得到對抗樣本數據集
3.檢驗fgsm攻擊效果
3.設定擾動量epsilon和識別準確度accuracies
?????????4.定義FGSM攻擊函數(原理超級通俗)
?????????5.具體攻擊過程(僅展示思路,詳細代碼顯示于文末)
?????????6.攻擊結果實例化
代碼展示
成果展示
?三.完整代碼
總結
一、模型訓練總結回顧
RMB識別模型的具體訓練流程已在之前的文章詳細敘述,故在此僅聊一聊大致思路
1.數據導入:(僅限導入本地已有的數據(已分類放置)的方法)
先使用Dataset(包含init,getitem,len函數),其中我們所需要設定的就是init函數和getitem函數。定義init函數,使其根據我們所輸入的存儲主路徑將每一張圖片的存儲路徑和圖片類別存放于列表中。定義getitem函數(需要在DataLoader中通過index才能進行下述操作),使其能夠根據列表中的路徑提取圖片信息,并執行我們所設定的transform函數,進行圖片信息的變換。
再使用DataLoader,這一步不需要我們去定義什么,只需要輸入Dataset并設定一些參數的值即可(如批大小,每個epoch是否亂序等等)
2.模型初定義
因為是繼承了nn.Module這個父類的,所以我們只需要設定init函數和forward函數,其中init函數中設定自己想要的卷積層和線性層,結構如下:
self.conv1 = nn.Conv2d(輸入層數, 輸出層數, 卷積核大小)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? self.fc1 = nn.Linear(層數*長*寬, 想要的數值)(最終目的是縮小為分類的種類數,但不能直接一步成,必須分成幾次達成)
而forward函數則是制定數據信息變化過程先是依次進行以下操作,直到無法繼續縮小圖片信息為止(長寬不滿足執行條件) ????????
out = F.relu(self.conv1(x)) (長寬減少,層數增加)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?執行條件:滿足卷積神將網絡的計算公式: ???????? N=(W-F+2P)/S+1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?其中N:輸出大小 ????W:輸入大小 ? ? ?F:卷積核大小 ? ? P:填充值的大小? ? ? S:步長大小? ? ? ?out = F.max_pool2d(out, 2) (長寬減半,層數不變)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 執行條件:長寬為偶數? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
當無法繼續縮小圖片信息后,執行設定好的線性層即可。
3.定義損失函數和優化器
損失函數到沒什么需要我們去操作的,直接用現成的就行。
優化器(optimizer)也直接用現成的,只需要設定以下學習率的大小即可。再將optimizer作為輸入,放在scheduler中,同時再設定學習率下降策略,即學習率縮小倍數即可。
4.訓練過程
定義數據集循環次數,每輪循環中,將數據集中的圖片信息導入模型得到outputs,將該結果與實際結果導入loss函數,并進行backward,根據梯度,通過優化器改變圖片每個信息點對應的權重值。比較outputs中的不同分類的數值,得出其中每張圖片的最大可能分類(即預測結果),將其與實際情況比較,得出識別正確率。
二、對RMB分類模型進行fgsm攻擊
1.fgsm原理
具體內容參考此鏈接,寫的很詳細??https://blog.csdn.net/qq_35414569
一種基于梯度生成對抗樣本的算法,屬于對抗攻擊中的無目標攻擊(即不要求對抗樣本經過model預測指定的類別,只要與原樣本預測的不一樣即可)
? ? ? ? ? ? ?圖1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖二(噪聲)? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖三(對抗樣本)
把圖一喂給模型,模型告訴你57.7%的概率是熊貓,別看概率小,機器總會輸出概率值最大的那個結果。隨后把圖二加入圖一中,生成一張新的圖三,把圖三喂給模型,模型告訴你99.3%是金絲猴,但肉眼看依然是熊貓,這就是FGSM攻擊方法
?2.大致思路流程概述
前提:已有一個已經訓練好的模型
1.求數據集中每個數據集的梯度(以供fgsm生成噪聲)
將數據集代入模型,求得outputs,將結果與數據集實際類別輸入到選定的loss函數中,進行backward,并將每張圖片對應梯度收集入列表。
2.通過fgsm,得到對抗樣本數據集
將數據集,收集的梯度列表,當前設定的擾動量輸入定義的fgsm中,得到最終的對抗樣本數據集
3.檢驗fgsm攻擊效果
將抗樣本數據集輸入進模型中,得到攻擊后的outputs,比較outputs中的不同分類的數值,得出其中每張圖片的最大可能分類(即預測結果),統計該結果同實際類別的吻合度,得到收到攻擊后的模型識別的準確度
3.設定擾動量epsilon和識別準確度accuracies
內容如圖所示:
# 這里的擾動量先設定為幾個值,后面可視化展示不同的擾動量影響以及成像效果 epsilons = [0, .05, .1, .15, .2, .25, .3, .35, .4] # 將epsilons中的每個eps所對應的識別準確度放入列表中以供線形圖展示 accuracies = list()4.定義FGSM攻擊函數(原理超級通俗)
如圖所示,我們可以假象為每個圖片信息就是這根曲線上的點,該點對應的位置就會影響對其類別的判斷,fgsm攻擊的目的就是以盡可能小的移動幅度讓該點盡可能的遠離當前位置,故而就得順著梯度最大的方向走,才能達到最佳效果,即讓每個圖片信息點所增加的噪聲都能對其遠離的行為產生正向作用。
?對應代碼及解釋如下所示:
def fgsm_attack(image, epsilon, data_grad):# 使用sign(符號)函數,將對x求了偏導的梯度進行符號化(正數為1,零為0,負數為-1)sign_data_grad = data_grad.sign()# 通過epsilon生成對抗樣本perturbed_image = image + epsilon * sign_data_grad# 噪聲越來越大,機器越來越難以識別,但人眼可以看出差別# 做一個剪裁的工作,將torch.clamp內部大于1的數值變為1,小于0的數值等于0,防止image越界perturbed_image = torch.clamp(perturbed_image, 0, 1)# 返回對抗樣本return perturbed_image5.具體攻擊過程(僅展示思路,詳細代碼顯示于文末)
1.設定循環的最大輪數
2.每一輪都將數據集中的一個batch的圖片信息代入模型,求得outputs
3.通過outputs與圖片實際類別,輸入loss函數并進行backward,收集每張圖片的梯度信息
4..將數據,梯度信息,設定的擾動量輸入fgsm函數中,最終得到對抗樣本數據。
5.可以設定當運行了幾個batch時,顯示當前的攻擊信息(如顯示當前多個batch計算得出的loss的平均值,對比預測結果與實際類別得出準確度等等)
6.攻擊結果實例化
注意:x,y值必須是列表的形式
代碼展示
valid_x = epsilons # 設定的幾個eps valid_y = accuracies # 每個eps對應的準確度plt.plot(valid_x, valid_y, label='Valid')plt.legend(loc='upper right') plt.ylabel('Acc') plt.xlabel('Epsilon') plt.show()成果展示
?三.完整代碼
import os import random import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from torch.utils.data import DataLoader from torch.utils.data import Dataset import torchvision.transforms as transforms import torch.optim as optim from matplotlib import pyplot as plt from PIL import Imagedef set_seed(seed=1):random.seed(seed)np.random.seed(seed)torch.manual_seed(seed)torch.cuda.manual_seed(seed)class RMBDataset(Dataset):def __init__(self, data_dir, transform=None):self.label_name = {"1": 0, "100": 1}self.data_info = self.get_img_info(data_dir) # data_info存儲所有圖片路徑和標簽,在DataLoader中通過index讀取樣本self.transform = transformdef __getitem__(self, index):path_img, label = self.data_info[index]img = Image.open(path_img).convert('RGB') # 0~255if self.transform is not None:img = self.transform(img) # 在這里做transform,轉為tensor等等return img, labeldef __len__(self):return len(self.data_info)@staticmethoddef get_img_info(data_dir):data_info = list()for root, dirs, _ in os.walk(data_dir):# 遍歷類別for sub_dir in dirs:img_names = os.listdir(os.path.join(root, sub_dir))img_names = list(filter(lambda x: x.endswith('.jpg'), img_names))# 遍歷圖片for i in range(len(img_names)):img_name = img_names[i]path_img = os.path.join(root, sub_dir, img_name)label = rmb_label[sub_dir]data_info.append((path_img, int(label)))return data_infoclass LeNet(nn.Module):def __init__(self, classes):super(LeNet, self).__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16*5*5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, classes)def forward(self, x):out = F.relu(self.conv1(x))out = F.max_pool2d(out, 2)out = F.relu(self.conv2(out))out = F.max_pool2d(out, 2)out = out.view(out.size(0), -1)out = F.relu(self.fc1(out))out = F.relu(self.fc2(out))out = self.fc3(out)return outdef initialize_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.xavier_normal_(m.weight.data)if m.bias is not None:m.bias.data.zero_()elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()elif isinstance(m, nn.Linear):nn.init.normal_(m.weight.data, 0, 0.1)m.bias.data.zero_()set_seed() # 設置隨機種子 rmb_label = {"1": 0, "100": 1}# 參數設置 MAX_EPOCH = 10 BATCH_SIZE = 5 LR = 0.001 log_interval = 10 val_interval = 1# ============================ step 1/5 數據 ============================split_dir = os.path.join(".", "RMB_data", "rmb_split") train_dir = os.path.join(split_dir, "train") valid_dir = os.path.join(split_dir, "valid")norm_mean = [0.485, 0.456, 0.406] norm_std = [0.229, 0.224, 0.225]train_transform = transforms.Compose([transforms.Resize((32, 32)),transforms.RandomCrop(32, padding=4),transforms.ToTensor(),transforms.Normalize(norm_mean, norm_std), ])valid_transform = transforms.Compose([transforms.Resize((32, 32)),transforms.ToTensor(),transforms.Normalize(norm_mean, norm_std), ])# 構建MyDataset實例 train_data = RMBDataset(data_dir=train_dir, transform=train_transform) valid_data = RMBDataset(data_dir=valid_dir, transform=valid_transform)# 構建DataLoder train_loader = DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True) valid_loader = DataLoader(dataset=valid_data, batch_size=BATCH_SIZE)# ============================ step 2/5 模型 ============================ net = LeNet(classes=2) net.initialize_weights()# ============================ step 3/5 損失函數 ============================ criterion = nn.CrossEntropyLoss() # 選擇損失函數# ============================ step 4/5 優化器 ============================ optimizer = optim.SGD(net.parameters(), lr=LR, momentum=0.9) # 選擇優化器 scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1) # 設置學習率下降策略# ============================ step 5/5 訓練 ============================ train_curve = list() valid_curve = list()for epoch in range(MAX_EPOCH):loss_mean = 0.correct = 0.total = 0.net.train()for i, data in enumerate(train_loader):# forwardinputs, labels = dataoutputs = net(inputs)# backwardoptimizer.zero_grad()loss = criterion(outputs, labels)loss.backward()# update weightsoptimizer.step()# 統計分類情況_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).squeeze().sum().numpy()# 打印訓練信息loss_mean += loss.item()train_curve.append(loss.item())if (i+1) % log_interval == 0:loss_mean = loss_mean / log_intervalprint("Training:Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(epoch, MAX_EPOCH, i+1, len(train_loader), loss_mean, correct / total))loss_mean = 0.scheduler.step() # 更新學習率def fgsm_attack(image, epsilon, data_grad):# 使用sign(符號)函數,將對x求了偏導的梯度進行符號化(正數為1,零為0,負數為-1)sign_data_grad = data_grad.sign()# 通過epsilon生成對抗樣本perturbed_image = image + epsilon * sign_data_grad# 噪聲越來越大,機器越來越難以識別,但人眼可以看出差別# 做一個剪裁的工作,將torch.clamp內部大于1的數值變為1,小于0的數值等于0,防止image越界perturbed_image = torch.clamp(perturbed_image, 0, 1)# 返回對抗樣本return perturbed_image# 這里的擾動量先設定為幾個值,后面可視化展示不同的擾動量影響以及成像效果 epsilons = [0, .05, .1, .15, .2, .25, .3, .35, .4] # epsilons = [0, .05, .1, .15, .2, ] accuracies = list() for eps in epsilons:loss_mean = 0.correct = 0.total = 0.log_interval = 10MAX_EPOCH = 3for epoch in range(MAX_EPOCH):net.train()for j, data in enumerate(valid_loader):inputs, labels = data# 圖像數據梯度可以獲取inputs.requires_grad = Trueoutputs = net(inputs)optimizer.zero_grad()loss = criterion(outputs, labels)loss.backward()# 收集datagraddata_grad = inputs.grad.data# 調用FGSM攻擊perturbed_data = fgsm_attack(inputs, eps, data_grad)# 對受擾動的圖像進行重新分類output = net(perturbed_data)# 統計分類情況_, final_pred = torch.max(output.data, 1) # 得到最大對數概率的索引total += labels.size(0)correct += (final_pred == labels).squeeze().sum().numpy()# 打印訓練信息loss_mean += loss.item()valid_curve.append(loss.item())if (j + 1) % log_interval == 0:loss_mean = loss_mean / log_intervalprint("Validing:Epsilon: {:} Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(eps, epoch, MAX_EPOCH, j + 1, len(valid_loader), loss_mean, correct / total))loss_mean = 0.accuracies.append(correct / total * 100)valid_x = epsilons valid_y = accuraciesplt.plot(valid_x, valid_y, label='Valid')plt.legend(loc='upper right') plt.ylabel('Acc') plt.xlabel('Epsilon') plt.show()總結
本周學習了fgsm攻擊的基本原理,并將之與之前學習的RMB識別模型進行結合(使用了原先選擇的loss函數及訓練好的模型),學有所獲并詳細記錄了其中的思路流程。之后,會學習如何使用cifar-10和? imagenet數據集進行FGSM攻擊,以及其他評價模型的指標等等。
總結
以上是生活随笔為你收集整理的FGSM实例:利用fgsm攻击RMB识别模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高级Bash脚本编程入门
- 下一篇: 2060显卡驱动最新版本_教程:怎么安装