bat.attacks.bandits_attack API documentation

# bat.attacks.bandits_attack

View Source

      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

def PREPROCESS(x): View Source

    10PREPROCESS = lambda x: x

def eg_step(x, g, lr): View Source

    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): View Source

    26def linf_step(x, g, lr):
    27    return x + lr * np.sign(g)

def cross_entropy(y_pred, y_true): View Source

    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: View Source

     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) View Source

    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

def init(self, x): View Source

    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): View Source

     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): View Source

    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): View Source

    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