File size: 4,232 Bytes
4113c4d |
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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
import numpy as np
from torch.autograd import Variable
import torch as torch
import copy
#from torch.autograd.gradcheck import zero_gradients
from deeprobust.image.attack.base_attack import BaseAttack
def zero_gradients(x):
if isinstance(x, torch.Tensor):
if x.grad is not None:
x.grad.detach_()
x.grad.zero_()
elif isinstance(x, collections.abc.Iterable):
for elem in x:
zero_gradients(elem)
class DeepFool(BaseAttack):
"""DeepFool attack.
"""
def __init__(self, model, device = 'cuda' ):
super(DeepFool, self).__init__(model, device)
self.model = model
self.device = device
def generate(self, image, label, **kwargs):
"""
Call this function to generate adversarial examples.
Parameters
----------
image : 1*H*W*3
original image
label : int
target label
kwargs :
user defined paremeters
Returns
-------
adv_img :
adversarial examples
"""
#check type device
assert self.check_type_device(image, label)
is_cuda = torch.cuda.is_available()
if (is_cuda and self.device == 'cuda'):
self.image = image.cuda()
self.model = self.model.cuda()
else:
self.image = image
assert self.parse_params(**kwargs)
adv_img, self.r, self.ite = deepfool(self.model,
self.image,
self.num_classes,
self.overshoot,
self.max_iteration,
self.device)
return adv_img
def getpert(self):
return self.r, self.ite
def parse_params(self,
num_classes = 10,
overshoot = 0.02,
max_iteration = 50):
"""
Parse the user defined parameters
Parameters
----------
num_classes : int
limits the number of classes to test against. (default = 10)
overshoot : float
used as a termination criterion to prevent vanishing updates (default = 0.02).
max_iteration : int
maximum number of iteration for deepfool (default = 50)
"""
self.num_classes = num_classes
self.overshoot = overshoot
self.max_iteration = max_iteration
return True
def deepfool(model, image, num_classes, overshoot, max_iter, device):
f_image = model.forward(image).data.cpu().numpy().flatten()
output = (np.array(f_image)).flatten().argsort()[::-1]
output = output[0:num_classes]
label = output[0]
input_shape = image.cpu().numpy().shape
x = copy.deepcopy(image).requires_grad_(True)
w = np.zeros(input_shape)
r_tot = np.zeros(input_shape)
fs = model.forward(x)
fs_list = [fs[0,output[k]] for k in range(num_classes)]
current_pred_label = label
for i in range(max_iter):
pert = np.inf
fs[0, output[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, output[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, output[k]] - fs[0, output[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)
pert_image = image + (1+overshoot)*torch.from_numpy(r_tot).to(device)
x = pert_image.detach().requires_grad_(True)
fs = model.forward(x)
if (not np.argmax(fs.data.cpu().numpy().flatten()) == label):
break
r_tot = (1+overshoot)*r_tot
return pert_image, r_tot, i
|