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