bat.attacks.bandits_attack

  1import os
  2import gc
  3import numpy as np
  4from tqdm import tqdm
  5
  6import concurrent.futures
  7
  8SCALE = 255
  9PREPROCESS = lambda x: x
 10
 11###
 12# Different optimization steps
 13# All take the form of func(x, g, lr)
 14# eg: exponentiated gradients
 15# l2/linf: projected gradient descent
 16###
 17
 18def eg_step(x, g, lr):
 19    real_x = (x + 1) / 2 # from [-1, 1] to [0, 1]
 20    pos = real_x * np.exp(lr * g)
 21    neg = (1 - real_x) * np.exp(-lr * g)
 22    new_x = pos / (pos + neg)
 23    return new_x * 2 - 1
 24
 25def linf_step(x, g, lr):
 26    return x + lr * np.sign(g)
 27
 28# def l2_prior_step(x, g, lr):
 29#     new_x = x + lr * g / np.linalg.norm(g)
 30#     norm_new_x = np.linalg.norm(new_x)
 31#     norm_mask = (norm_new_x < 1.0).float()
 32#     return new_x * norm_mask + (1 - norm_mask) * new_x / norm_new_x
 33
 34# def gd_prior_step(x, g, lr):
 35#     return x + lr * g
 36
 37# def l2_image_step(x, g, lr):
 38#     return x + lr * g / np.linalg.norm(g)
 39
 40def cross_entropy(y_pred, y_true):
 41    """
 42    y_pred is the softmax output of the model
 43    y_true is labels (num_examples x 1)
 44    	Note that y is not one-hot encoded vector. 
 45    	It can be computed as y.argmax(axis=1) from one-hot encoded vectors of labels if required.
 46    """
 47
 48    y_true = np.array(y_true)
 49    m = y_true.shape[0]
 50
 51    # We dont need to compute softmax, since y_pred is already softmaxed
 52    # from scipy.special import softmax
 53    # p = softmax(y_pred)
 54    p = y_pred
 55
 56    # We use multidimensional array indexing to extract 
 57    # softmax probability of the correct label for each sample.
 58    # Refer to https://docs.scipy.org/doc/numpy/user/basics.indexing.html#indexing-multi-dimensional-arrays for understanding multidimensional array indexing.
 59    log_likelihood = -np.log(p[range(m), y_true])
 60
 61    # No reduction
 62    # loss = np.sum(log_likelihood) / m
 63
 64    return log_likelihood
 65
 66class BanditsAttack():
 67    def __init__(self,  classifier):
 68        """
 69        Create a class: `BanditAttack` instance.
 70        - classifier: model to attack
 71        """
 72        self.classifier = classifier
 73
 74    def init(self, x):
 75        """
 76        Initialize the attack.
 77        """
 78        y_pred = self.classifier.predict(PREPROCESS(x))
 79
 80        x_adv = x.copy()
 81
 82        priors = []
 83        for i in range(len(x)):
 84            h, w, c = x[i].shape
 85            priors.append(np.zeros((h, w, c)))
 86    
 87        return x_adv, y_pred, priors
 88
 89    def step(self, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration):
 90
 91        x_query_1 = []
 92        x_query_2 = []
 93
 94        exp_noises = []
 95
 96        for i, img in enumerate(x_adv):
 97            ## Updating the prior: 
 98            # Create noise for exporation, estimate the gradient, and take a PGD step
 99            h, w, c = img.shape
100            dim = h * w * c
101            exp_noise = exploration * np.random.normal(0.0, 1.0, size = priors[i].shape) / (dim ** 0.5) * SCALE
102
103            # Query deltas for finite difference estimator
104            q1 = priors[i] + exp_noise
105            q2 = priors[i] - exp_noise
106
107            norm_q1 = np.linalg.norm(q1)
108            norm_q2 = np.linalg.norm(q2)
109
110            # The original paper did not clip the noise
111            # x_query_1.append(img + fd_eta * (q1 / (1e-8 if norm_q1 == 0.0 else norm_q1)))
112            # x_query_2.append(img + fd_eta * (q2 / (1e-8 if norm_q2 == 0.0 else norm_q2)))
113
114            x_query_1.append(np.uint8(np.clip(img + fd_eta * (q1 / (1e-8 if norm_q1 == 0.0 else norm_q1)), 0, 1.0 * SCALE)))
115            x_query_2.append(np.uint8(np.clip(img + fd_eta * (q2 / (1e-8 if norm_q2 == 0.0 else norm_q2)), 0, 1.0 * SCALE)))
116
117            exp_noises.append(exp_noise)
118
119        # Loss points for finite difference estimator
120        l1 = cross_entropy(self.classifier.predict(PREPROCESS(x_query_1)), y) # L(prior + c*noise)
121        l2 = cross_entropy(self.classifier.predict(PREPROCESS(x_query_2)), y) # L(prior - c*noise)
122
123        for i, img in enumerate(x_adv):
124            # Finite differences estimate of directional derivative
125            est_deriv = (l1[i] - l2[i]) / (fd_eta * exploration)
126            # 2-query gradient estimate
127            est_grad = est_deriv * exp_noises[i]
128            # Update the prior with the estimated gradient
129
130            priors[i] = eg_step(priors[i], est_grad, online_lr)
131
132            ## Update the image:
133            # take a pgd step using the prior
134            img = linf_step(img, priors[i], image_lr)
135            img = x[i] + np.clip(img - x[i], -epsilon, epsilon)
136            img = np.clip(img, 0, 1 * SCALE)
137
138            x_adv[i] = img
139
140        return x_adv, priors
141
142    def batch(self, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration, concurrency):
143
144        assert len(x) == len(x_adv) == len(y) == len(priors) == 1
145
146        noises_new = []
147        priors_new = []
148
149        with concurrent.futures.ThreadPoolExecutor() as executor:
150            future_to_url = {executor.submit(self.step, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration): j for j in range(0, concurrency)}
151            for future in concurrent.futures.as_completed(future_to_url):
152                j = future_to_url[future]
153                try:
154                    xn, pn = future.result()
155                    noises_new.append(xn[0] - x_adv[0])
156                    priors_new.append(pn[0] - priors[0])
157                except Exception as exc:
158                    print('Task %r generated an exception: %s' % (j, exc))
159                else:
160                    pass
161
162        for i in range(0, len(noises_new)):
163            x_adv[0] = x_adv[0] + noises_new[i] / concurrency
164            priors[0] = priors[0] + priors_new[i] / concurrency
165
166        x_adv[0] = x_adv[0] + np.clip(x_adv[0] - x[0], -epsilon, epsilon)
167        x_adv[0] = np.clip(x_adv[0], 0, 1 * SCALE)
168
169        return x_adv, priors
170
171    def attack(self, x, y, epsilon=0.05, fd_eta=0.1, image_lr=0.01, online_lr=100, exploration=1.0, max_it=10000, concurrency=1):
172        """
173        Initiate the attack.
174
175        - x: input data
176        - y: input labels
177        - epsilon: perturbation on each pixel
178        - max_it: number of iterations
179        """
180
181        n_targets = 0
182        if type(x) == list:
183            n_targets = len(x)
184        elif type(x) == np.ndarray:
185            n_targets = x.shape[0]
186        else:
187            raise ValueError('Input type not supported...')
188
189        assert n_targets > 0
190
191        x_adv, y_pred, priors = self.init(x)
192
193        # Continue query count
194        y_pred_classes = np.argmax(y_pred, axis=1)
195        correct_classified_mask = (y_pred_classes == y)
196        not_dones_mask = correct_classified_mask.copy()
197
198        correct_classified = [i for i, v in enumerate(correct_classified_mask) if v]
199
200        print('Clean accuracy: {:.2%}'.format(np.mean(correct_classified_mask)))
201
202        if np.mean(correct_classified_mask) == 0:
203            print('No clean examples classified correctly. Aborting...')
204            n_queries = np.ones(len(x))  # ones because we have already used 1 query
205
206            mean_nq, mean_nq_ae = np.mean(n_queries), np.mean(n_queries)
207
208            return x_adv
209
210        if n_targets > 1:
211            # Horizontally Distributed Attack
212            pbar = tqdm(range(0, max_it), desc="Distributed Bandits Attack (Horizontal)")
213        else:
214            # Vertically Distributed Attack
215            pbar = tqdm(range(0, max_it, concurrency), desc="Distributed Bandits Attack (Vertical)")
216
217        total_queries = np.zeros(len(x))
218
219        for i_iter in pbar:
220
221            not_dones = [i for i, v in enumerate(not_dones_mask) if v]
222
223            x_curr = [x[idx] for idx in not_dones]
224            x_adv_curr = [x_adv[idx] for idx in not_dones]
225            y_curr = [y[idx] for idx in not_dones]
226            prior_curr = [priors[idx] for idx in not_dones]
227
228            if n_targets > 1:
229                # Horizontally Distributed Attack
230                x_adv_curr, prior_curr = self.step(x_curr, x_adv_curr, y_curr, prior_curr, epsilon * SCALE, fd_eta * SCALE, image_lr * SCALE, online_lr, exploration)
231            else:
232                # Vertically Distributed Attack
233                x_adv_curr, prior_curr = self.batch(x_curr, x_adv_curr, y_curr, prior_curr, epsilon * SCALE, fd_eta * SCALE, image_lr * SCALE, online_lr, exploration, concurrency)
234
235            y_pred_curr = self.classifier.predict(PREPROCESS(x_adv_curr))
236            y_curr = np.argmax(y_pred_curr, axis=1)
237
238            for i in range(len(not_dones)):
239                x_adv[not_dones[i]] = x_adv_curr[i]
240                priors[not_dones[i]] = prior_curr[i]
241                y_pred[not_dones[i]] = y_pred_curr[i]
242                y_pred_classes[not_dones[i]] = y_curr[i]
243
244            # Logging stuff
245            total_queries += 3 * not_dones_mask * concurrency
246
247            not_dones_mask = not_dones_mask * (y_pred_classes == y)
248
249            # max_curr_queries = total_queries.max()
250
251            success_mask = correct_classified_mask * (1 - not_dones_mask)
252            num_success = success_mask.sum()
253            current_success_rate = (num_success / correct_classified_mask.sum())
254
255            if num_success == 0:
256                success_queries = -1
257            else:
258                success_queries = ((success_mask * total_queries).sum() / num_success)
259
260            pbar.set_postfix({'Total Queries': total_queries.sum(), 'Mean Higest Prediction': y_pred[correct_classified].max(axis=1).mean(), 'Attack Success Rate': current_success_rate, 'Avg Queries': success_queries})
261
262            acc = not_dones_mask.sum() / correct_classified_mask.sum()
263            mean_nq, mean_nq_ae = np.mean(total_queries), np.mean(total_queries *success_mask)
264
265            # Early break
266            if current_success_rate == 1.0:
267                break
268
269            gc.collect()
270
271        return x_adv
SCALE = 255
def PREPROCESS(x):
10PREPROCESS = lambda x: x
def eg_step(x, g, lr):
19def eg_step(x, g, lr):
20    real_x = (x + 1) / 2 # from [-1, 1] to [0, 1]
21    pos = real_x * np.exp(lr * g)
22    neg = (1 - real_x) * np.exp(-lr * g)
23    new_x = pos / (pos + neg)
24    return new_x * 2 - 1
def linf_step(x, g, lr):
26def linf_step(x, g, lr):
27    return x + lr * np.sign(g)
def cross_entropy(y_pred, y_true):
41def cross_entropy(y_pred, y_true):
42    """
43    y_pred is the softmax output of the model
44    y_true is labels (num_examples x 1)
45    	Note that y is not one-hot encoded vector. 
46    	It can be computed as y.argmax(axis=1) from one-hot encoded vectors of labels if required.
47    """
48
49    y_true = np.array(y_true)
50    m = y_true.shape[0]
51
52    # We dont need to compute softmax, since y_pred is already softmaxed
53    # from scipy.special import softmax
54    # p = softmax(y_pred)
55    p = y_pred
56
57    # We use multidimensional array indexing to extract 
58    # softmax probability of the correct label for each sample.
59    # Refer to https://docs.scipy.org/doc/numpy/user/basics.indexing.html#indexing-multi-dimensional-arrays for understanding multidimensional array indexing.
60    log_likelihood = -np.log(p[range(m), y_true])
61
62    # No reduction
63    # loss = np.sum(log_likelihood) / m
64
65    return log_likelihood

y_pred is the softmax output of the model y_true is labels (num_examples x 1) Note that y is not one-hot encoded vector. It can be computed as y.argmax(axis=1) from one-hot encoded vectors of labels if required.

class BanditsAttack:
 67class BanditsAttack():
 68    def __init__(self,  classifier):
 69        """
 70        Create a class: `BanditAttack` instance.
 71        - classifier: model to attack
 72        """
 73        self.classifier = classifier
 74
 75    def init(self, x):
 76        """
 77        Initialize the attack.
 78        """
 79        y_pred = self.classifier.predict(PREPROCESS(x))
 80
 81        x_adv = x.copy()
 82
 83        priors = []
 84        for i in range(len(x)):
 85            h, w, c = x[i].shape
 86            priors.append(np.zeros((h, w, c)))
 87    
 88        return x_adv, y_pred, priors
 89
 90    def step(self, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration):
 91
 92        x_query_1 = []
 93        x_query_2 = []
 94
 95        exp_noises = []
 96
 97        for i, img in enumerate(x_adv):
 98            ## Updating the prior: 
 99            # Create noise for exporation, estimate the gradient, and take a PGD step
100            h, w, c = img.shape
101            dim = h * w * c
102            exp_noise = exploration * np.random.normal(0.0, 1.0, size = priors[i].shape) / (dim ** 0.5) * SCALE
103
104            # Query deltas for finite difference estimator
105            q1 = priors[i] + exp_noise
106            q2 = priors[i] - exp_noise
107
108            norm_q1 = np.linalg.norm(q1)
109            norm_q2 = np.linalg.norm(q2)
110
111            # The original paper did not clip the noise
112            # x_query_1.append(img + fd_eta * (q1 / (1e-8 if norm_q1 == 0.0 else norm_q1)))
113            # x_query_2.append(img + fd_eta * (q2 / (1e-8 if norm_q2 == 0.0 else norm_q2)))
114
115            x_query_1.append(np.uint8(np.clip(img + fd_eta * (q1 / (1e-8 if norm_q1 == 0.0 else norm_q1)), 0, 1.0 * SCALE)))
116            x_query_2.append(np.uint8(np.clip(img + fd_eta * (q2 / (1e-8 if norm_q2 == 0.0 else norm_q2)), 0, 1.0 * SCALE)))
117
118            exp_noises.append(exp_noise)
119
120        # Loss points for finite difference estimator
121        l1 = cross_entropy(self.classifier.predict(PREPROCESS(x_query_1)), y) # L(prior + c*noise)
122        l2 = cross_entropy(self.classifier.predict(PREPROCESS(x_query_2)), y) # L(prior - c*noise)
123
124        for i, img in enumerate(x_adv):
125            # Finite differences estimate of directional derivative
126            est_deriv = (l1[i] - l2[i]) / (fd_eta * exploration)
127            # 2-query gradient estimate
128            est_grad = est_deriv * exp_noises[i]
129            # Update the prior with the estimated gradient
130
131            priors[i] = eg_step(priors[i], est_grad, online_lr)
132
133            ## Update the image:
134            # take a pgd step using the prior
135            img = linf_step(img, priors[i], image_lr)
136            img = x[i] + np.clip(img - x[i], -epsilon, epsilon)
137            img = np.clip(img, 0, 1 * SCALE)
138
139            x_adv[i] = img
140
141        return x_adv, priors
142
143    def batch(self, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration, concurrency):
144
145        assert len(x) == len(x_adv) == len(y) == len(priors) == 1
146
147        noises_new = []
148        priors_new = []
149
150        with concurrent.futures.ThreadPoolExecutor() as executor:
151            future_to_url = {executor.submit(self.step, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration): j for j in range(0, concurrency)}
152            for future in concurrent.futures.as_completed(future_to_url):
153                j = future_to_url[future]
154                try:
155                    xn, pn = future.result()
156                    noises_new.append(xn[0] - x_adv[0])
157                    priors_new.append(pn[0] - priors[0])
158                except Exception as exc:
159                    print('Task %r generated an exception: %s' % (j, exc))
160                else:
161                    pass
162
163        for i in range(0, len(noises_new)):
164            x_adv[0] = x_adv[0] + noises_new[i] / concurrency
165            priors[0] = priors[0] + priors_new[i] / concurrency
166
167        x_adv[0] = x_adv[0] + np.clip(x_adv[0] - x[0], -epsilon, epsilon)
168        x_adv[0] = np.clip(x_adv[0], 0, 1 * SCALE)
169
170        return x_adv, priors
171
172    def attack(self, x, y, epsilon=0.05, fd_eta=0.1, image_lr=0.01, online_lr=100, exploration=1.0, max_it=10000, concurrency=1):
173        """
174        Initiate the attack.
175
176        - x: input data
177        - y: input labels
178        - epsilon: perturbation on each pixel
179        - max_it: number of iterations
180        """
181
182        n_targets = 0
183        if type(x) == list:
184            n_targets = len(x)
185        elif type(x) == np.ndarray:
186            n_targets = x.shape[0]
187        else:
188            raise ValueError('Input type not supported...')
189
190        assert n_targets > 0
191
192        x_adv, y_pred, priors = self.init(x)
193
194        # Continue query count
195        y_pred_classes = np.argmax(y_pred, axis=1)
196        correct_classified_mask = (y_pred_classes == y)
197        not_dones_mask = correct_classified_mask.copy()
198
199        correct_classified = [i for i, v in enumerate(correct_classified_mask) if v]
200
201        print('Clean accuracy: {:.2%}'.format(np.mean(correct_classified_mask)))
202
203        if np.mean(correct_classified_mask) == 0:
204            print('No clean examples classified correctly. Aborting...')
205            n_queries = np.ones(len(x))  # ones because we have already used 1 query
206
207            mean_nq, mean_nq_ae = np.mean(n_queries), np.mean(n_queries)
208
209            return x_adv
210
211        if n_targets > 1:
212            # Horizontally Distributed Attack
213            pbar = tqdm(range(0, max_it), desc="Distributed Bandits Attack (Horizontal)")
214        else:
215            # Vertically Distributed Attack
216            pbar = tqdm(range(0, max_it, concurrency), desc="Distributed Bandits Attack (Vertical)")
217
218        total_queries = np.zeros(len(x))
219
220        for i_iter in pbar:
221
222            not_dones = [i for i, v in enumerate(not_dones_mask) if v]
223
224            x_curr = [x[idx] for idx in not_dones]
225            x_adv_curr = [x_adv[idx] for idx in not_dones]
226            y_curr = [y[idx] for idx in not_dones]
227            prior_curr = [priors[idx] for idx in not_dones]
228
229            if n_targets > 1:
230                # Horizontally Distributed Attack
231                x_adv_curr, prior_curr = self.step(x_curr, x_adv_curr, y_curr, prior_curr, epsilon * SCALE, fd_eta * SCALE, image_lr * SCALE, online_lr, exploration)
232            else:
233                # Vertically Distributed Attack
234                x_adv_curr, prior_curr = self.batch(x_curr, x_adv_curr, y_curr, prior_curr, epsilon * SCALE, fd_eta * SCALE, image_lr * SCALE, online_lr, exploration, concurrency)
235
236            y_pred_curr = self.classifier.predict(PREPROCESS(x_adv_curr))
237            y_curr = np.argmax(y_pred_curr, axis=1)
238
239            for i in range(len(not_dones)):
240                x_adv[not_dones[i]] = x_adv_curr[i]
241                priors[not_dones[i]] = prior_curr[i]
242                y_pred[not_dones[i]] = y_pred_curr[i]
243                y_pred_classes[not_dones[i]] = y_curr[i]
244
245            # Logging stuff
246            total_queries += 3 * not_dones_mask * concurrency
247
248            not_dones_mask = not_dones_mask * (y_pred_classes == y)
249
250            # max_curr_queries = total_queries.max()
251
252            success_mask = correct_classified_mask * (1 - not_dones_mask)
253            num_success = success_mask.sum()
254            current_success_rate = (num_success / correct_classified_mask.sum())
255
256            if num_success == 0:
257                success_queries = -1
258            else:
259                success_queries = ((success_mask * total_queries).sum() / num_success)
260
261            pbar.set_postfix({'Total Queries': total_queries.sum(), 'Mean Higest Prediction': y_pred[correct_classified].max(axis=1).mean(), 'Attack Success Rate': current_success_rate, 'Avg Queries': success_queries})
262
263            acc = not_dones_mask.sum() / correct_classified_mask.sum()
264            mean_nq, mean_nq_ae = np.mean(total_queries), np.mean(total_queries *success_mask)
265
266            # Early break
267            if current_success_rate == 1.0:
268                break
269
270            gc.collect()
271
272        return x_adv
BanditsAttack(classifier)
68    def __init__(self,  classifier):
69        """
70        Create a class: `BanditAttack` instance.
71        - classifier: model to attack
72        """
73        self.classifier = classifier

Create a class: BanditAttack instance.

  • classifier: model to attack
classifier
def init(self, x):
75    def init(self, x):
76        """
77        Initialize the attack.
78        """
79        y_pred = self.classifier.predict(PREPROCESS(x))
80
81        x_adv = x.copy()
82
83        priors = []
84        for i in range(len(x)):
85            h, w, c = x[i].shape
86            priors.append(np.zeros((h, w, c)))
87    
88        return x_adv, y_pred, priors

Initialize the attack.

def step( self, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration):
 90    def step(self, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration):
 91
 92        x_query_1 = []
 93        x_query_2 = []
 94
 95        exp_noises = []
 96
 97        for i, img in enumerate(x_adv):
 98            ## Updating the prior: 
 99            # Create noise for exporation, estimate the gradient, and take a PGD step
100            h, w, c = img.shape
101            dim = h * w * c
102            exp_noise = exploration * np.random.normal(0.0, 1.0, size = priors[i].shape) / (dim ** 0.5) * SCALE
103
104            # Query deltas for finite difference estimator
105            q1 = priors[i] + exp_noise
106            q2 = priors[i] - exp_noise
107
108            norm_q1 = np.linalg.norm(q1)
109            norm_q2 = np.linalg.norm(q2)
110
111            # The original paper did not clip the noise
112            # x_query_1.append(img + fd_eta * (q1 / (1e-8 if norm_q1 == 0.0 else norm_q1)))
113            # x_query_2.append(img + fd_eta * (q2 / (1e-8 if norm_q2 == 0.0 else norm_q2)))
114
115            x_query_1.append(np.uint8(np.clip(img + fd_eta * (q1 / (1e-8 if norm_q1 == 0.0 else norm_q1)), 0, 1.0 * SCALE)))
116            x_query_2.append(np.uint8(np.clip(img + fd_eta * (q2 / (1e-8 if norm_q2 == 0.0 else norm_q2)), 0, 1.0 * SCALE)))
117
118            exp_noises.append(exp_noise)
119
120        # Loss points for finite difference estimator
121        l1 = cross_entropy(self.classifier.predict(PREPROCESS(x_query_1)), y) # L(prior + c*noise)
122        l2 = cross_entropy(self.classifier.predict(PREPROCESS(x_query_2)), y) # L(prior - c*noise)
123
124        for i, img in enumerate(x_adv):
125            # Finite differences estimate of directional derivative
126            est_deriv = (l1[i] - l2[i]) / (fd_eta * exploration)
127            # 2-query gradient estimate
128            est_grad = est_deriv * exp_noises[i]
129            # Update the prior with the estimated gradient
130
131            priors[i] = eg_step(priors[i], est_grad, online_lr)
132
133            ## Update the image:
134            # take a pgd step using the prior
135            img = linf_step(img, priors[i], image_lr)
136            img = x[i] + np.clip(img - x[i], -epsilon, epsilon)
137            img = np.clip(img, 0, 1 * SCALE)
138
139            x_adv[i] = img
140
141        return x_adv, priors
def batch( self, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration, concurrency):
143    def batch(self, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration, concurrency):
144
145        assert len(x) == len(x_adv) == len(y) == len(priors) == 1
146
147        noises_new = []
148        priors_new = []
149
150        with concurrent.futures.ThreadPoolExecutor() as executor:
151            future_to_url = {executor.submit(self.step, x, x_adv, y, priors, epsilon, fd_eta, image_lr, online_lr, exploration): j for j in range(0, concurrency)}
152            for future in concurrent.futures.as_completed(future_to_url):
153                j = future_to_url[future]
154                try:
155                    xn, pn = future.result()
156                    noises_new.append(xn[0] - x_adv[0])
157                    priors_new.append(pn[0] - priors[0])
158                except Exception as exc:
159                    print('Task %r generated an exception: %s' % (j, exc))
160                else:
161                    pass
162
163        for i in range(0, len(noises_new)):
164            x_adv[0] = x_adv[0] + noises_new[i] / concurrency
165            priors[0] = priors[0] + priors_new[i] / concurrency
166
167        x_adv[0] = x_adv[0] + np.clip(x_adv[0] - x[0], -epsilon, epsilon)
168        x_adv[0] = np.clip(x_adv[0], 0, 1 * SCALE)
169
170        return x_adv, priors
def attack( self, x, y, epsilon=0.05, fd_eta=0.1, image_lr=0.01, online_lr=100, exploration=1.0, max_it=10000, concurrency=1):
172    def attack(self, x, y, epsilon=0.05, fd_eta=0.1, image_lr=0.01, online_lr=100, exploration=1.0, max_it=10000, concurrency=1):
173        """
174        Initiate the attack.
175
176        - x: input data
177        - y: input labels
178        - epsilon: perturbation on each pixel
179        - max_it: number of iterations
180        """
181
182        n_targets = 0
183        if type(x) == list:
184            n_targets = len(x)
185        elif type(x) == np.ndarray:
186            n_targets = x.shape[0]
187        else:
188            raise ValueError('Input type not supported...')
189
190        assert n_targets > 0
191
192        x_adv, y_pred, priors = self.init(x)
193
194        # Continue query count
195        y_pred_classes = np.argmax(y_pred, axis=1)
196        correct_classified_mask = (y_pred_classes == y)
197        not_dones_mask = correct_classified_mask.copy()
198
199        correct_classified = [i for i, v in enumerate(correct_classified_mask) if v]
200
201        print('Clean accuracy: {:.2%}'.format(np.mean(correct_classified_mask)))
202
203        if np.mean(correct_classified_mask) == 0:
204            print('No clean examples classified correctly. Aborting...')
205            n_queries = np.ones(len(x))  # ones because we have already used 1 query
206
207            mean_nq, mean_nq_ae = np.mean(n_queries), np.mean(n_queries)
208
209            return x_adv
210
211        if n_targets > 1:
212            # Horizontally Distributed Attack
213            pbar = tqdm(range(0, max_it), desc="Distributed Bandits Attack (Horizontal)")
214        else:
215            # Vertically Distributed Attack
216            pbar = tqdm(range(0, max_it, concurrency), desc="Distributed Bandits Attack (Vertical)")
217
218        total_queries = np.zeros(len(x))
219
220        for i_iter in pbar:
221
222            not_dones = [i for i, v in enumerate(not_dones_mask) if v]
223
224            x_curr = [x[idx] for idx in not_dones]
225            x_adv_curr = [x_adv[idx] for idx in not_dones]
226            y_curr = [y[idx] for idx in not_dones]
227            prior_curr = [priors[idx] for idx in not_dones]
228
229            if n_targets > 1:
230                # Horizontally Distributed Attack
231                x_adv_curr, prior_curr = self.step(x_curr, x_adv_curr, y_curr, prior_curr, epsilon * SCALE, fd_eta * SCALE, image_lr * SCALE, online_lr, exploration)
232            else:
233                # Vertically Distributed Attack
234                x_adv_curr, prior_curr = self.batch(x_curr, x_adv_curr, y_curr, prior_curr, epsilon * SCALE, fd_eta * SCALE, image_lr * SCALE, online_lr, exploration, concurrency)
235
236            y_pred_curr = self.classifier.predict(PREPROCESS(x_adv_curr))
237            y_curr = np.argmax(y_pred_curr, axis=1)
238
239            for i in range(len(not_dones)):
240                x_adv[not_dones[i]] = x_adv_curr[i]
241                priors[not_dones[i]] = prior_curr[i]
242                y_pred[not_dones[i]] = y_pred_curr[i]
243                y_pred_classes[not_dones[i]] = y_curr[i]
244
245            # Logging stuff
246            total_queries += 3 * not_dones_mask * concurrency
247
248            not_dones_mask = not_dones_mask * (y_pred_classes == y)
249
250            # max_curr_queries = total_queries.max()
251
252            success_mask = correct_classified_mask * (1 - not_dones_mask)
253            num_success = success_mask.sum()
254            current_success_rate = (num_success / correct_classified_mask.sum())
255
256            if num_success == 0:
257                success_queries = -1
258            else:
259                success_queries = ((success_mask * total_queries).sum() / num_success)
260
261            pbar.set_postfix({'Total Queries': total_queries.sum(), 'Mean Higest Prediction': y_pred[correct_classified].max(axis=1).mean(), 'Attack Success Rate': current_success_rate, 'Avg Queries': success_queries})
262
263            acc = not_dones_mask.sum() / correct_classified_mask.sum()
264            mean_nq, mean_nq_ae = np.mean(total_queries), np.mean(total_queries *success_mask)
265
266            # Early break
267            if current_success_rate == 1.0:
268                break
269
270            gc.collect()
271
272        return x_adv

Initiate the attack.

  • x: input data
  • y: input labels
  • epsilon: perturbation on each pixel
  • max_it: number of iterations