-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdf_attack.py
More file actions
111 lines (84 loc) · 3.8 KB
/
Copy pathdf_attack.py
File metadata and controls
111 lines (84 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
import numpy as np
import copy
class DeepFool():
r"""
'DeepFool: A Simple and Accurate Method to Fool Deep Neural Networks'
[https://arxiv.org/abs/1511.04599]
Arguments:
model (nn.Module): model to attack.
steps (int): number of steps. (DEFALUT : 3)
Shape:
- images: :math:`(N, C, H, W)` where `N = number of batches`, `C = number of channels`, `H = height` and `W = width`. It must have a range [0, 1].
- labels: :math:`(N)` where each value :math:`y_i` is :math:`0 \leq y_i \leq` `number of labels`.
- output: :math:`(N, C, H, W)`.
Examples::
>>> attack = torchattacks.DeepFool(model, steps=3)
>>> adv_images = attack(images, labels)
"""
def __init__(self, steps=50):
self.steps = steps
def __call__(self, model, images):
adv_images = images.detach().clone()
for b in range(images.shape[0]):
r_tot, loop_i, label, k_i, pert_image = deepfool(images[b], model, num_classes=10, overshoot=0.02, max_iter=self.steps)
adv_images[b:b+1] = pert_image
return adv_images
def deepfool(image, net, num_classes=10, overshoot=0.02, max_iter=50):
"""
:param image: Image of size HxWx3
:param net: network (input: images, output: values of activation **BEFORE** softmax).
:param num_classes: num_classes (limits the number of classes to test against, by default = 10)
:param overshoot: used as a termination criterion to prevent vanishing updates (default = 0.02).
:param max_iter: maximum number of iterations for deepfool (default = 50)
:return: minimal perturbation that fools the classifier, number of iterations that it required, new estimated_label and perturbed image
"""
from torch.autograd.gradcheck import zero_gradients
f_image = net.forward(Variable(image[None, :, :, :], requires_grad=True)).data.cpu().numpy().flatten()
I = (np.array(f_image)).flatten().argsort()[::-1]
I = I[0:num_classes]
label = I[0]
input_shape = image.cpu().numpy().shape
pert_image = copy.deepcopy(image)
w = np.zeros(input_shape)
r_tot = np.zeros(input_shape)
loop_i = 0
x = Variable(pert_image[None, :], requires_grad=True)
fs = net.forward(x)
fs_list = [fs[0,I[k]] for k in range(num_classes)]
k_i = label
while k_i == label and loop_i < max_iter:
pert = np.inf
fs[0, I[0]].backward(retain_graph=True)
grad_orig = x.grad.data.cpu().numpy().copy()
for k in range(1, num_classes):
zero_gradients(x)
fs[0, I[k]].backward(retain_graph=True)
cur_grad = x.grad.data.cpu().numpy().copy()
# set new w_k and new f_k
w_k = cur_grad - grad_orig
f_k = (fs[0, I[k]] - fs[0, I[0]]).data.cpu().numpy()
pert_k = abs(f_k)/np.linalg.norm(w_k.flatten())
# determine which w_k to use
if pert_k < pert:
pert = pert_k
w = w_k
# compute r_i and r_tot
# Added 1e-4 for numerical stability
r_i = (pert+1e-4) * w / np.linalg.norm(w)
r_tot = np.float32(r_tot + r_i)
# if is_cuda:
# pert_image = image + (1+overshoot)*torch.from_numpy(r_tot).cuda()
# else:
# pert_image = image + (1+overshoot)*torch.from_numpy(r_tot)
pert_image = image + (1+overshoot)*torch.from_numpy(r_tot).to(image.device)
pert_image = pert_image.clamp(0,1)
x = Variable(pert_image, requires_grad=True)
fs = net.forward(x)
k_i = np.argmax(fs.data.cpu().numpy().flatten())
loop_i += 1
r_tot = (1+overshoot)*r_tot
return r_tot, loop_i, label, k_i, pert_image