其他
一个符号引发的讨论,对抗攻击算法FGSM的纯粹版:FGNS,附代码
关注公众号,发现CV技术之美
▊ 1 引言
是基于梯度迭代攻击中生成对抗样本的开创性工作。我第一次接触相关工作的时候,给我困惑最多的就是论文中为什么要给梯度加上这个符号函数,因为这会导致生成的对抗扰动的方向与最速梯度方向有一个锐角偏移。
论文链接:https://arxiv.org/abs/2110.12734
▊ 2 理论分析
根据以上方程组可以得到如下公式:
令,,进而则有:
又因为,在向量所有的范数中1范数是最大的,即,此时则有:
令新的对抗扰动为,且此时该扰动的方向与梯度方向一致即:
根据以上公式则可以推导出:
给定的范围,第步的对抗扰动为:
根据上述推导可以得到具体的算法流程图如下所示:
▊ 3 实验结果
如下图所示,为原始梯度方向和梯度方向的可视化剪头图。从下图发现原始梯度更快更高效收敛到最优点中。然而施加到梯度上会使得它推离最优方向,导致要以更多的迭代次数才能达到最优点。
如下两图所示为不同方法的平均攻击成功率比较。作者使用作为白盒,并计算其它四种黑盒模型(-、、和)的平均攻击成功率,可以发现在各个攻击迭代方法下,应用论文中的方法会取得更好的效果。
▊ 4 程序代码
from torchvision import datasets, transforms
from torch.utils.data import DataLoader, Dataset
import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.optim as optim
import torch.nn.functional as F
import os
class CNN(nn.Module):
def __init__(self):
super().__init__()
self.Sq1 = nn.Sequential(
nn.Conv2d(in_channels=1, out_channels=16,
kernel_size=5, stride=1, padding=2), # output: (16, 28, 28)
nn.ReLU(),
nn.MaxPool2d(kernel_size=2), # (16, 14, 14)
)
self.Sq2 = nn.Sequential(
nn.Conv2d(in_channels=16, out_channels=32,
kernel_size=5, stride=1, padding=2), # (32, 14, 14)
nn.ReLU(),
nn.MaxPool2d(2), # (32, 7, 7)
)
self.out = nn.Linear(32 * 7 * 7, 10)
def forward(self, x):
x = self.Sq1(x)
x = self.Sq2(x)
x = x.view(x.size(0), -1)
output = self.out(x)
return output
def FGM_attack(inputs, targets, net, alpha, epsilon, attack_type):
delta = torch.zeros_like(inputs)
delta.requires_grad = True
outputs = net(inputs + delta)
loss = nn.CrossEntropyLoss()(outputs, targets)
loss.backward()
grad = delta.grad.detach()
if type == 'FGSN':
zeta = (torch.norm(inputs, p=0, dim=(2,3), keepdim=True)
/ torch.norm(inputs, p=2, dim=(2,3), keepdim=True))
* torch.ones(inputs.shape)
delta.data = torch.clamp(delta + alpha * zeta * grad,
-epsilon, epsilon)
else:
delta.data = torch.clamp(delta + alpha * torch.sign(grad),
-epsilon, epsilon)
delta = delta.detach()
return delta
def main():
alpha = 0.2
epsilon = 0.5
total = 0
correct1 = 0
correct2 = 0
model = CNN()
model.load_state_dict(torch.load('model/model.pt'))
use_cuda = torch.cuda.is_available()
mnist_train = datasets.MNIST("mnist-data", train=True,
download=True, transform=transforms.ToTensor())
train_loader = torch.utils.data.DataLoader(mnist_train,
batch_size= 5, shuffle=True)
for batch_idx, (inputs, targets) in enumerate(train_loader):
if use_cuda:
inputs, targets = inputs.cuda(), targets.cuda()
inputs, targets = Variable(inputs), Variable(targets)
total += targets.size(0)
delta1 = FGM_attack(inputs, targets, model, alpha, epsilon, 'FGNM')
adv_image1 = torch.clamp(inputs + delta1, 0, 1)
outputs1 = model(adv_image1)
_, predicted1 = torch.max(outputs1.data, 1)
correct1 += predicted1.eq(targets.data).cpu().sum().item()
print('The FGNM accuracy:', correct1, total, correct1/total)
delta2 = FGM_attack(inputs, targets, model, alpha, epsilon, 'FGSM')
adv_images2 = torch.clamp(inputs + delta1, 0, 1)
outputs2 = model(adv_images2)
_, predicted2 = torch.max(outputs2.data, 1)
correct2 += predicted2.eq(targets.data).cpu().sum().item()
print('The FGSM accuracy:', correct2, total, correct2/total)
print('The FGNM accuracy:', correct1)
print('The FGSM accuracy:', correct2)
if __name__ == '__main__':
main()
当给定的攻击步长,则有如下实验结果:
END
欢迎加入「对抗攻击」交流群👇备注:对抗