bat.attacks.simba_attack API documentation

# bat.attacks.simba_attack

This module implements the black-box attack `SimBA`.

View Source

      1"""
      2This module implements the black-box attack `SimBA`.
      3"""
      4
      5import os
      6import gc
      7import numpy as np
      8from tqdm import tqdm
      9import concurrent.futures
     10
     11from bat.attacks.base_attack import BaseAttack
     12
     13SCALE = 255
     14PREPROCESS = lambda x: x
     15
     16def proj_lp(v, xi=0.1, p=2):
     17    """
     18    SUPPORTS only p = 2 and p = Inf for now
     19    """
     20    if p == 2:
     21        v = v * min(1, xi/np.linalg.norm(v.flatten('C')))
     22        # v = v / np.linalg.norm(v.flatten(1)) * xi
     23    elif p == np.inf:
     24        v = np.sign(v) * np.minimum(abs(v), xi)
     25    else:
     26        raise ValueError('Values of p different from 2 and Inf are currently not supported...')
     27
     28    return v
     29
     30class SimBA(BaseAttack):
     31    """
     32    Implementation of the `SimBA` attack. Paper link: https://arxiv.org/abs/1905.07121
     33    """
     34
     35    def __init__(self,  classifier):
     36        """
     37        Create a class: `SimBA` instance.
     38        - classifier: model to attack
     39        """
     40        super().__init__(classifier)
     41
     42    def init(self, x, max_it):
     43        """
     44        Initialize the attack.
     45        """
     46
     47        x_adv = x.copy()
     48        y_pred = self.classifier.predict(PREPROCESS(x.copy()))
     49
     50        perm = []
     51        for xi in x:
     52            perm.append(np.random.permutation(xi.reshape(-1).shape[0]))
     53            assert len(perm[-1]) > max_it, 'The maxinum number of iteration should be smaller than the image dimension.'
     54
     55        return x_adv, y_pred, perm
     56
     57    def step(self, x_adv, y_pred, perm, index, epsilon):
     58        """
     59        Single step for non-distributed attack.
     60        """
     61
     62        x_adv_plus = []
     63        x_adv_minus = []
     64        x_adv_diff = []
     65        for i in range(0, len(x_adv)):
     66            diff = np.zeros(x_adv[i].reshape(-1).shape[0])
     67            diff[perm[i][index]] = epsilon
     68            diff = diff.reshape(x_adv[i].shape)
     69            x_adv_plus.append(np.clip(x_adv[i] + diff, 0, 1 * SCALE))
     70            x_adv_minus.append(np.clip(x_adv[i] - diff, 0, 1 * SCALE))
     71            x_adv_diff.append(diff)
     72
     73        plus = self.classifier.predict(PREPROCESS(x_adv_plus.copy()))
     74        minus = self.classifier.predict(PREPROCESS(x_adv_minus.copy()))
     75
     76        for i in range(0, len(x_adv)):
     77            if plus[i][np.argmax(y_pred[i])] < y_pred[i][np.argmax(y_pred[i])]:
     78                x_adv[i] = x_adv[i] + x_adv_diff[i]
     79                y_pred[i] = plus[i]
     80            elif minus[i][np.argmax(y_pred[i])] < y_pred[i][np.argmax(y_pred[i])]:
     81                x_adv[i] = x_adv[i] - x_adv_diff[i]
     82                y_pred[i] = minus[i]
     83            else:
     84                pass
     85
     86        return x_adv, y_pred
     87
     88    def batch(self, x_adv, y_pred, perm, index, epsilon, concurrency):
     89        """
     90        Single step for distributed attack.
     91        """
     92        noises = []
     93        for i in range(0, len(x_adv)):
     94            noises.append(np.zeros(x_adv[i].shape))
     95
     96        with concurrent.futures.ThreadPoolExecutor() as executor:
     97            future_to_url = {executor.submit(self.step, x_adv, y_pred, perm, index+j, epsilon): j for j in range(0, concurrency)}
     98            for future in concurrent.futures.as_completed(future_to_url):
     99                j = future_to_url[future]
    100                try:
    101                    x_adv_new, _ = future.result()
    102                    for i in range(0, len(x_adv)):
    103                        noises[i] = noises[i] + x_adv_new[i] - x_adv[i]
    104                except Exception as exc:
    105                    print('Task %r generated an exception: %s' % (j, exc))
    106                else:
    107                    pass
    108
    109        for i in range(0, len(x_adv)):
    110            if(np.sum(noises[i]) != 0):
    111                noises = proj_lp(noises[i], xi = 10)
    112            x_adv[i] = np.clip(x_adv[i] + noises[i], 0, 1 * SCALE)
    113
    114        y_adv = self.classifier.predict(PREPROCESS(x_adv.copy()))
    115
    116        return x_adv, y_adv
    117
    118    def attack(self, x, y, epsilon=0.05, max_it=1000, concurrency=1):
    119        """
    120        Initiate the attack.
    121
    122        - x: input data
    123        - y: input labels
    124        - epsilon: perturbation on each pixel
    125        - max_it: number of iterations
    126        - concurrency: number of concurrent threads
    127        """
    128
    129        n_targets = 0
    130        if type(x) == list:
    131            n_targets = len(x)
    132        elif type(x) == np.ndarray:
    133            n_targets = x.shape[0]
    134        else:
    135            raise ValueError('Input type not supported...')
    136
    137        assert n_targets > 0
    138
    139        # Initialize attack
    140        x_adv, y_pred, perm = self.init(x, max_it)
    141
    142        # Compute number of images correctly classified
    143        y_pred_classes = np.argmax(y_pred, axis=1)
    144        correct_classified_mask = (y_pred_classes == y)
    145        correct_classified = [i for i, v in enumerate(correct_classified_mask) if v]
    146
    147        # Images to attack
    148        not_dones_mask = correct_classified_mask.copy()
    149
    150        print('Clean accuracy: {:.2%}'.format(np.mean(correct_classified_mask)))
    151
    152        if np.mean(correct_classified_mask) == 0:
    153            print('No clean examples classified correctly. Aborting...')
    154            n_queries = np.ones(len(x))  # ones because we have already used 1 query
    155
    156            mean_nq, mean_nq_ae = np.mean(n_queries), np.mean(n_queries)
    157
    158            return x
    159
    160        else:
    161            if n_targets > 1:
    162                # Horizontally Distributed Attack
    163                pbar = tqdm(range(0, max_it), desc="Distributed SimBA Attack (Horizontal)")
    164            else:
    165                # Vertically Distributed Attack
    166                pbar = tqdm(range(0, max_it, concurrency), desc="Distributed SimBA Attack (Vertical)")
    167
    168        total_queries = np.zeros(len(x))
    169
    170        for i_iter in pbar:
    171
    172            not_dones = [i for i, v in enumerate(not_dones_mask) if v]
    173
    174            x_adv_curr = [x_adv[idx] for idx in not_dones]
    175            y_curr = [y_pred[idx] for idx in not_dones]
    176            perm_curr = [perm[idx] for idx in not_dones]
    177
    178            y_curr = np.array(y_curr)
    179
    180            if n_targets > 1:
    181                # Horizontally Distributed Attack
    182                x_adv_curr, y_curr = self.step(x_adv_curr, y_curr, perm_curr, i_iter, epsilon*SCALE)
    183            else:
    184                # Vertically Distributed Attack
    185                x_adv_curr, y_curr = self.batch(x_adv_curr, y_curr, perm_curr, i_iter, epsilon*SCALE, concurrency)
    186
    187            for i in range(len(not_dones)):
    188                x_adv[not_dones[i]] = x_adv_curr[i]
    189                y_pred[not_dones[i]] = y_curr[i]
    190
    191            # Logging stuff
    192            if n_targets > 1:
    193                # Horizontally Distributed Attack
    194                total_queries += 2 * not_dones_mask
    195            else:
    196                # Vertically Distributed Attack
    197                total_queries += 2 * concurrency * not_dones_mask + 1
    198
    199            y_pred_classes = np.argmax(y_pred, axis=1)
    200            not_dones_mask = not_dones_mask * (y_pred_classes == y)
    201
    202            success_mask = correct_classified_mask * (1 - not_dones_mask)
    203            num_success = success_mask.sum()
    204            current_success_rate = (num_success / correct_classified_mask.sum())
    205
    206            if num_success == 0:
    207                success_queries = -1
    208            else:
    209                success_queries = ((success_mask * total_queries).sum() / num_success)
    210
    211            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})
    212
    213            acc = not_dones_mask.sum() / correct_classified_mask.sum()
    214            mean_nq, mean_nq_ae = np.mean(total_queries), np.mean(total_queries *success_mask)
    215
    216            # Early break
    217            if current_success_rate == 1.0:
    218                break
    219
    220            gc.collect()
    221
    222        return x_adv

def PREPROCESS(x): View Source

    15PREPROCESS = lambda x: x

def proj_lp(v, xi=0.1, p=2): View Source

    17def proj_lp(v, xi=0.1, p=2):
    18    """
    19    SUPPORTS only p = 2 and p = Inf for now
    20    """
    21    if p == 2:
    22        v = v * min(1, xi/np.linalg.norm(v.flatten('C')))
    23        # v = v / np.linalg.norm(v.flatten(1)) * xi
    24    elif p == np.inf:
    25        v = np.sign(v) * np.minimum(abs(v), xi)
    26    else:
    27        raise ValueError('Values of p different from 2 and Inf are currently not supported...')
    28
    29    return v

SUPPORTS only p = 2 and p = Inf for now

class SimBA(bat.attacks.base_attack.BaseAttack): View Source

     31class SimBA(BaseAttack):
     32    """
     33    Implementation of the `SimBA` attack. Paper link: https://arxiv.org/abs/1905.07121
     34    """
     35
     36    def __init__(self,  classifier):
     37        """
     38        Create a class: `SimBA` instance.
     39        - classifier: model to attack
     40        """
     41        super().__init__(classifier)
     42
     43    def init(self, x, max_it):
     44        """
     45        Initialize the attack.
     46        """
     47
     48        x_adv = x.copy()
     49        y_pred = self.classifier.predict(PREPROCESS(x.copy()))
     50
     51        perm = []
     52        for xi in x:
     53            perm.append(np.random.permutation(xi.reshape(-1).shape[0]))
     54            assert len(perm[-1]) > max_it, 'The maxinum number of iteration should be smaller than the image dimension.'
     55
     56        return x_adv, y_pred, perm
     57
     58    def step(self, x_adv, y_pred, perm, index, epsilon):
     59        """
     60        Single step for non-distributed attack.
     61        """
     62
     63        x_adv_plus = []
     64        x_adv_minus = []
     65        x_adv_diff = []
     66        for i in range(0, len(x_adv)):
     67            diff = np.zeros(x_adv[i].reshape(-1).shape[0])
     68            diff[perm[i][index]] = epsilon
     69            diff = diff.reshape(x_adv[i].shape)
     70            x_adv_plus.append(np.clip(x_adv[i] + diff, 0, 1 * SCALE))
     71            x_adv_minus.append(np.clip(x_adv[i] - diff, 0, 1 * SCALE))
     72            x_adv_diff.append(diff)
     73
     74        plus = self.classifier.predict(PREPROCESS(x_adv_plus.copy()))
     75        minus = self.classifier.predict(PREPROCESS(x_adv_minus.copy()))
     76
     77        for i in range(0, len(x_adv)):
     78            if plus[i][np.argmax(y_pred[i])] < y_pred[i][np.argmax(y_pred[i])]:
     79                x_adv[i] = x_adv[i] + x_adv_diff[i]
     80                y_pred[i] = plus[i]
     81            elif minus[i][np.argmax(y_pred[i])] < y_pred[i][np.argmax(y_pred[i])]:
     82                x_adv[i] = x_adv[i] - x_adv_diff[i]
     83                y_pred[i] = minus[i]
     84            else:
     85                pass
     86
     87        return x_adv, y_pred
     88
     89    def batch(self, x_adv, y_pred, perm, index, epsilon, concurrency):
     90        """
     91        Single step for distributed attack.
     92        """
     93        noises = []
     94        for i in range(0, len(x_adv)):
     95            noises.append(np.zeros(x_adv[i].shape))
     96
     97        with concurrent.futures.ThreadPoolExecutor() as executor:
     98            future_to_url = {executor.submit(self.step, x_adv, y_pred, perm, index+j, epsilon): j for j in range(0, concurrency)}
     99            for future in concurrent.futures.as_completed(future_to_url):
    100                j = future_to_url[future]
    101                try:
    102                    x_adv_new, _ = future.result()
    103                    for i in range(0, len(x_adv)):
    104                        noises[i] = noises[i] + x_adv_new[i] - x_adv[i]
    105                except Exception as exc:
    106                    print('Task %r generated an exception: %s' % (j, exc))
    107                else:
    108                    pass
    109
    110        for i in range(0, len(x_adv)):
    111            if(np.sum(noises[i]) != 0):
    112                noises = proj_lp(noises[i], xi = 10)
    113            x_adv[i] = np.clip(x_adv[i] + noises[i], 0, 1 * SCALE)
    114
    115        y_adv = self.classifier.predict(PREPROCESS(x_adv.copy()))
    116
    117        return x_adv, y_adv
    118
    119    def attack(self, x, y, epsilon=0.05, max_it=1000, concurrency=1):
    120        """
    121        Initiate the attack.
    122
    123        - x: input data
    124        - y: input labels
    125        - epsilon: perturbation on each pixel
    126        - max_it: number of iterations
    127        - concurrency: number of concurrent threads
    128        """
    129
    130        n_targets = 0
    131        if type(x) == list:
    132            n_targets = len(x)
    133        elif type(x) == np.ndarray:
    134            n_targets = x.shape[0]
    135        else:
    136            raise ValueError('Input type not supported...')
    137
    138        assert n_targets > 0
    139
    140        # Initialize attack
    141        x_adv, y_pred, perm = self.init(x, max_it)
    142
    143        # Compute number of images correctly classified
    144        y_pred_classes = np.argmax(y_pred, axis=1)
    145        correct_classified_mask = (y_pred_classes == y)
    146        correct_classified = [i for i, v in enumerate(correct_classified_mask) if v]
    147
    148        # Images to attack
    149        not_dones_mask = correct_classified_mask.copy()
    150
    151        print('Clean accuracy: {:.2%}'.format(np.mean(correct_classified_mask)))
    152
    153        if np.mean(correct_classified_mask) == 0:
    154            print('No clean examples classified correctly. Aborting...')
    155            n_queries = np.ones(len(x))  # ones because we have already used 1 query
    156
    157            mean_nq, mean_nq_ae = np.mean(n_queries), np.mean(n_queries)
    158
    159            return x
    160
    161        else:
    162            if n_targets > 1:
    163                # Horizontally Distributed Attack
    164                pbar = tqdm(range(0, max_it), desc="Distributed SimBA Attack (Horizontal)")
    165            else:
    166                # Vertically Distributed Attack
    167                pbar = tqdm(range(0, max_it, concurrency), desc="Distributed SimBA Attack (Vertical)")
    168
    169        total_queries = np.zeros(len(x))
    170
    171        for i_iter in pbar:
    172
    173            not_dones = [i for i, v in enumerate(not_dones_mask) if v]
    174
    175            x_adv_curr = [x_adv[idx] for idx in not_dones]
    176            y_curr = [y_pred[idx] for idx in not_dones]
    177            perm_curr = [perm[idx] for idx in not_dones]
    178
    179            y_curr = np.array(y_curr)
    180
    181            if n_targets > 1:
    182                # Horizontally Distributed Attack
    183                x_adv_curr, y_curr = self.step(x_adv_curr, y_curr, perm_curr, i_iter, epsilon*SCALE)
    184            else:
    185                # Vertically Distributed Attack
    186                x_adv_curr, y_curr = self.batch(x_adv_curr, y_curr, perm_curr, i_iter, epsilon*SCALE, concurrency)
    187
    188            for i in range(len(not_dones)):
    189                x_adv[not_dones[i]] = x_adv_curr[i]
    190                y_pred[not_dones[i]] = y_curr[i]
    191
    192            # Logging stuff
    193            if n_targets > 1:
    194                # Horizontally Distributed Attack
    195                total_queries += 2 * not_dones_mask
    196            else:
    197                # Vertically Distributed Attack
    198                total_queries += 2 * concurrency * not_dones_mask + 1
    199
    200            y_pred_classes = np.argmax(y_pred, axis=1)
    201            not_dones_mask = not_dones_mask * (y_pred_classes == y)
    202
    203            success_mask = correct_classified_mask * (1 - not_dones_mask)
    204            num_success = success_mask.sum()
    205            current_success_rate = (num_success / correct_classified_mask.sum())
    206
    207            if num_success == 0:
    208                success_queries = -1
    209            else:
    210                success_queries = ((success_mask * total_queries).sum() / num_success)
    211
    212            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})
    213
    214            acc = not_dones_mask.sum() / correct_classified_mask.sum()
    215            mean_nq, mean_nq_ae = np.mean(total_queries), np.mean(total_queries *success_mask)
    216
    217            # Early break
    218            if current_success_rate == 1.0:
    219                break
    220
    221            gc.collect()
    222
    223        return x_adv

Implementation of the `SimBA` attack. Paper link: https://arxiv.org/abs/1905.07121

SimBA(classifier) View Source

    36    def __init__(self,  classifier):
    37        """
    38        Create a class: `SimBA` instance.
    39        - classifier: model to attack
    40        """
    41        super().__init__(classifier)

Create a class: `SimBA` instance.

- classifier: model to attack

def init(self, x, max_it): View Source

    43    def init(self, x, max_it):
    44        """
    45        Initialize the attack.
    46        """
    47
    48        x_adv = x.copy()
    49        y_pred = self.classifier.predict(PREPROCESS(x.copy()))
    50
    51        perm = []
    52        for xi in x:
    53            perm.append(np.random.permutation(xi.reshape(-1).shape[0]))
    54            assert len(perm[-1]) > max_it, 'The maxinum number of iteration should be smaller than the image dimension.'
    55
    56        return x_adv, y_pred, perm

Initialize the attack.

def step(self, x_adv, y_pred, perm, index, epsilon): View Source

    58    def step(self, x_adv, y_pred, perm, index, epsilon):
    59        """
    60        Single step for non-distributed attack.
    61        """
    62
    63        x_adv_plus = []
    64        x_adv_minus = []
    65        x_adv_diff = []
    66        for i in range(0, len(x_adv)):
    67            diff = np.zeros(x_adv[i].reshape(-1).shape[0])
    68            diff[perm[i][index]] = epsilon
    69            diff = diff.reshape(x_adv[i].shape)
    70            x_adv_plus.append(np.clip(x_adv[i] + diff, 0, 1 * SCALE))
    71            x_adv_minus.append(np.clip(x_adv[i] - diff, 0, 1 * SCALE))
    72            x_adv_diff.append(diff)
    73
    74        plus = self.classifier.predict(PREPROCESS(x_adv_plus.copy()))
    75        minus = self.classifier.predict(PREPROCESS(x_adv_minus.copy()))
    76
    77        for i in range(0, len(x_adv)):
    78            if plus[i][np.argmax(y_pred[i])] < y_pred[i][np.argmax(y_pred[i])]:
    79                x_adv[i] = x_adv[i] + x_adv_diff[i]
    80                y_pred[i] = plus[i]
    81            elif minus[i][np.argmax(y_pred[i])] < y_pred[i][np.argmax(y_pred[i])]:
    82                x_adv[i] = x_adv[i] - x_adv_diff[i]
    83                y_pred[i] = minus[i]
    84            else:
    85                pass
    86
    87        return x_adv, y_pred

Single step for non-distributed attack.

def batch(self, x_adv, y_pred, perm, index, epsilon, concurrency): View Source

     89    def batch(self, x_adv, y_pred, perm, index, epsilon, concurrency):
     90        """
     91        Single step for distributed attack.
     92        """
     93        noises = []
     94        for i in range(0, len(x_adv)):
     95            noises.append(np.zeros(x_adv[i].shape))
     96
     97        with concurrent.futures.ThreadPoolExecutor() as executor:
     98            future_to_url = {executor.submit(self.step, x_adv, y_pred, perm, index+j, epsilon): j for j in range(0, concurrency)}
     99            for future in concurrent.futures.as_completed(future_to_url):
    100                j = future_to_url[future]
    101                try:
    102                    x_adv_new, _ = future.result()
    103                    for i in range(0, len(x_adv)):
    104                        noises[i] = noises[i] + x_adv_new[i] - x_adv[i]
    105                except Exception as exc:
    106                    print('Task %r generated an exception: %s' % (j, exc))
    107                else:
    108                    pass
    109
    110        for i in range(0, len(x_adv)):
    111            if(np.sum(noises[i]) != 0):
    112                noises = proj_lp(noises[i], xi = 10)
    113            x_adv[i] = np.clip(x_adv[i] + noises[i], 0, 1 * SCALE)
    114
    115        y_adv = self.classifier.predict(PREPROCESS(x_adv.copy()))
    116
    117        return x_adv, y_adv

Single step for distributed attack.

def attack(self, x, y, epsilon=0.05, max_it=1000, concurrency=1): View Source

    119    def attack(self, x, y, epsilon=0.05, max_it=1000, concurrency=1):
    120        """
    121        Initiate the attack.
    122
    123        - x: input data
    124        - y: input labels
    125        - epsilon: perturbation on each pixel
    126        - max_it: number of iterations
    127        - concurrency: number of concurrent threads
    128        """
    129
    130        n_targets = 0
    131        if type(x) == list:
    132            n_targets = len(x)
    133        elif type(x) == np.ndarray:
    134            n_targets = x.shape[0]
    135        else:
    136            raise ValueError('Input type not supported...')
    137
    138        assert n_targets > 0
    139
    140        # Initialize attack
    141        x_adv, y_pred, perm = self.init(x, max_it)
    142
    143        # Compute number of images correctly classified
    144        y_pred_classes = np.argmax(y_pred, axis=1)
    145        correct_classified_mask = (y_pred_classes == y)
    146        correct_classified = [i for i, v in enumerate(correct_classified_mask) if v]
    147
    148        # Images to attack
    149        not_dones_mask = correct_classified_mask.copy()
    150
    151        print('Clean accuracy: {:.2%}'.format(np.mean(correct_classified_mask)))
    152
    153        if np.mean(correct_classified_mask) == 0:
    154            print('No clean examples classified correctly. Aborting...')
    155            n_queries = np.ones(len(x))  # ones because we have already used 1 query
    156
    157            mean_nq, mean_nq_ae = np.mean(n_queries), np.mean(n_queries)
    158
    159            return x
    160
    161        else:
    162            if n_targets > 1:
    163                # Horizontally Distributed Attack
    164                pbar = tqdm(range(0, max_it), desc="Distributed SimBA Attack (Horizontal)")
    165            else:
    166                # Vertically Distributed Attack
    167                pbar = tqdm(range(0, max_it, concurrency), desc="Distributed SimBA Attack (Vertical)")
    168
    169        total_queries = np.zeros(len(x))
    170
    171        for i_iter in pbar:
    172
    173            not_dones = [i for i, v in enumerate(not_dones_mask) if v]
    174
    175            x_adv_curr = [x_adv[idx] for idx in not_dones]
    176            y_curr = [y_pred[idx] for idx in not_dones]
    177            perm_curr = [perm[idx] for idx in not_dones]
    178
    179            y_curr = np.array(y_curr)
    180
    181            if n_targets > 1:
    182                # Horizontally Distributed Attack
    183                x_adv_curr, y_curr = self.step(x_adv_curr, y_curr, perm_curr, i_iter, epsilon*SCALE)
    184            else:
    185                # Vertically Distributed Attack
    186                x_adv_curr, y_curr = self.batch(x_adv_curr, y_curr, perm_curr, i_iter, epsilon*SCALE, concurrency)
    187
    188            for i in range(len(not_dones)):
    189                x_adv[not_dones[i]] = x_adv_curr[i]
    190                y_pred[not_dones[i]] = y_curr[i]
    191
    192            # Logging stuff
    193            if n_targets > 1:
    194                # Horizontally Distributed Attack
    195                total_queries += 2 * not_dones_mask
    196            else:
    197                # Vertically Distributed Attack
    198                total_queries += 2 * concurrency * not_dones_mask + 1
    199
    200            y_pred_classes = np.argmax(y_pred, axis=1)
    201            not_dones_mask = not_dones_mask * (y_pred_classes == y)
    202
    203            success_mask = correct_classified_mask * (1 - not_dones_mask)
    204            num_success = success_mask.sum()
    205            current_success_rate = (num_success / correct_classified_mask.sum())
    206
    207            if num_success == 0:
    208                success_queries = -1
    209            else:
    210                success_queries = ((success_mask * total_queries).sum() / num_success)
    211
    212            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})
    213
    214            acc = not_dones_mask.sum() / correct_classified_mask.sum()
    215            mean_nq, mean_nq_ae = np.mean(total_queries), np.mean(total_queries *success_mask)
    216
    217            # Early break
    218            if current_success_rate == 1.0:
    219                break
    220
    221            gc.collect()
    222
    223        return x_adv

Initiate the attack.

- x: input data
- y: input labels
- epsilon: perturbation on each pixel
- max_it: number of iterations
- concurrency: number of concurrent threads