| import numpy as np |
| from torch.autograd import Variable |
| import torch as torch |
| import copy |
| |
|
|
| 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 |
| """ |
|
|
|
|
| |
| 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() |
|
|
| |
| 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()) |
|
|
| |
| if pert_k < pert: |
| pert = pert_k |
| w = w_k |
|
|
| |
| |
| 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 |
|
|
|
|