def cnn_mnist_tf(input_shape): labels_tf = tf.placeholder(tf.float32, [None, 10]) inputs_tf = tf.placeholder(tf.float32, [None] + list(input_shape)) # Define the TensorFlow graph conv = tf.layers.conv2d(inputs_tf, 4, 5, activation=tf.nn.relu) conv = tf.layers.max_pooling2d(conv, 2, 2) fc = tf.contrib.layers.flatten(conv) # Logits layer logits = tf.layers.dense(fc, 10) # Train operator loss = tf.reduce_mean( tf.losses.softmax_cross_entropy(logits=logits, onehot_labels=labels_tf)) optimizer = tf.train.AdamOptimizer(learning_rate=0.01) train_tf = optimizer.minimize(loss) sess = tf.Session() sess.run(tf.global_variables_initializer()) classifier = TensorFlowClassifier(clip_values=(0, 1), input_ph=inputs_tf, output=logits, loss=loss, train=train_tf, labels_ph=labels_tf, sess=sess) return classifier
def create_ts1_art_mnist_classifier(min_pixel_value, max_pixel_value): input_ph = tf.placeholder(tf.float32, shape=[None, 28, 28, 1]) labels_ph = tf.placeholder(tf.int32, shape=[None, 10]) x = tf.layers.conv2d(input_ph, filters=4, kernel_size=5, activation=tf.nn.relu) x = tf.layers.max_pooling2d(x, 2, 2) x = tf.layers.conv2d(x, filters=10, kernel_size=5, activation=tf.nn.relu) x = tf.layers.max_pooling2d(x, 2, 2) x = tf.contrib.layers.flatten(x) x = tf.layers.dense(x, 100, activation=tf.nn.relu) logits = tf.layers.dense(x, 10) loss = tf.reduce_mean( tf.losses.softmax_cross_entropy(logits=logits, onehot_labels=labels_ph)) optimizer = tf.train.AdamOptimizer(learning_rate=0.01) train = optimizer.minimize(loss) sess.run(tf.global_variables_initializer()) classifier = TensorFlowClassifier( clip_values=(min_pixel_value, max_pixel_value), input_ph=input_ph, output=logits, labels_ph=labels_ph, train=train, loss=loss, learning=None, sess=sess, preprocessing_defences=[], ) return classifier
def __init__( self, estimator: "CLASSIFIER_LOSS_GRADIENTS_TYPE", norm: Union[int, float, str] = np.inf, eps: float = 0.3, eps_step: float = 0.1, max_iter: int = 100, targeted: bool = False, nb_random_init: int = 5, batch_size: int = 32, loss_type: Optional[str] = None, verbose: bool = True, ): """ Create a :class:`.AutoProjectedGradientDescent` instance. :param estimator: An trained estimator. :param norm: The norm of the adversarial perturbation. Possible values: "inf", np.inf, 1 or 2. :param eps: Maximum perturbation that the attacker can introduce. :param eps_step: Attack step size (input variation) at each iteration. :param max_iter: The maximum number of iterations. :param targeted: Indicates whether the attack is targeted (True) or untargeted (False). :param nb_random_init: Number of random initialisations within the epsilon ball. For num_random_init=0 starting at the original input. :param batch_size: Size of the batch on which adversarial samples are generated. :param loss_type: Defines the loss to attack. Available options: None (Use loss defined by estimator), "cross_entropy", or "difference_logits_ratio" :param verbose: Show progress bars. """ from art.estimators.classification import TensorFlowClassifier, TensorFlowV2Classifier, PyTorchClassifier if loss_type not in self._predefined_losses: raise ValueError( "The argument loss_type has an invalid value. The following options for `loss_type` are currently " "supported: {}".format(self._predefined_losses) ) if loss_type is None: if hasattr(estimator, "predict") and is_probability( estimator.predict(x=np.ones(shape=(1, *estimator.input_shape), dtype=np.float32)) ): raise ValueError( "AutoProjectedGradientDescent is expecting logits as estimator output, the provided " "estimator seems to predict probabilities." ) estimator_apgd = estimator else: if isinstance(estimator, TensorFlowClassifier): import tensorflow as tf if loss_type == "cross_entropy": if is_probability(estimator.predict(x=np.ones(shape=(1, *estimator.input_shape)))): raise NotImplementedError("Cross-entropy loss is not implemented for probability output.") self._loss_object = tf.reduce_mean( tf.keras.losses.categorical_crossentropy( y_pred=estimator._output, y_true=estimator._labels_ph, from_logits=True ) ) elif loss_type == "difference_logits_ratio": if is_probability(estimator.predict(x=np.ones(shape=(1, *estimator.input_shape)))): raise ValueError( "The provided estimator seems to predict probabilities. " "If loss_type='difference_logits_ratio' the estimator has to to predict logits." ) raise ValueError( "The loss `difference_logits_ratio` has not been validate completely. It seems that the " "commented implemented below is failing to selected the second largest logit for cases " "where the largest logit is the true logit. For future work `difference_logits_ratio` and " "loss_fn should return the same loss value." ) # def difference_logits_ratio(y_true, y_pred): # i_y_true = tf.cast(tf.math.argmax(tf.cast(y_true, tf.int32), axis=1), tf.int32) # i_y_pred_arg = tf.argsort(y_pred, axis=1) # # Not completely sure if the following line is correct. # # `i_y_pred_arg[:, -2], i_y_pred_arg[:, -1]` seems closer to the output of `loss_fn` than # # `i_y_pred_arg[:, -1], i_y_pred_arg[:, -2]` # i_z_i = tf.where(i_y_pred_arg[:, -1] != i_y_true[:], i_y_pred_arg[:, -2], # i_y_pred_arg[:, -1]) # # z_1 = tf.gather(y_pred, i_y_pred_arg[:, -1], axis=1, batch_dims=0) # z_3 = tf.gather(y_pred, i_y_pred_arg[:, -3], axis=1, batch_dims=0) # z_i = tf.gather(y_pred, i_z_i, axis=1, batch_dims=0) # z_y = tf.gather(y_pred, i_y_true, axis=1, batch_dims=0) # # z_1 = tf.linalg.diag_part(z_1) # z_3 = tf.linalg.diag_part(z_3) # z_i = tf.linalg.diag_part(z_i) # z_y = tf.linalg.diag_part(z_y) # # dlr = -(z_y - z_i) / (z_1 - z_3) # # return tf.reduce_mean(dlr) # # def loss_fn(y_true, y_pred): # i_y_true = np.argmax(y_true, axis=1) # i_y_pred_arg = np.argsort(y_pred, axis=1) # i_z_i = np.where(i_y_pred_arg[:, -1] != i_y_true[:], i_y_pred_arg[:, -1], # i_y_pred_arg[:, -2]) # # z_1 = y_pred[:, i_y_pred_arg[:, -1]] # z_3 = y_pred[:, i_y_pred_arg[:, -3]] # z_i = y_pred[:, i_z_i] # z_y = y_pred[:, i_y_true] # # z_1 = np.diag(z_1) # z_3 = np.diag(z_3) # z_i = np.diag(z_i) # z_y = np.diag(z_y) # # dlr = -(z_y - z_i) / (z_1 - z_3) # # return np.mean(dlr) # # self._loss_fn = loss_fn # self._loss_object = difference_logits_ratio(y_true=estimator._labels_ph, # y_pred=estimator._output) estimator_apgd = TensorFlowClassifier( input_ph=estimator._input_ph, output=estimator._output, labels_ph=estimator._labels_ph, train=estimator._train, loss=self._loss_object, learning=estimator._learning, sess=estimator._sess, channels_first=estimator.channels_first, clip_values=estimator.clip_values, preprocessing_defences=estimator.preprocessing_defences, postprocessing_defences=estimator.postprocessing_defences, preprocessing=estimator.preprocessing, feed_dict=estimator._feed_dict, ) elif isinstance(estimator, TensorFlowV2Classifier): import tensorflow as tf if loss_type == "cross_entropy": if is_probability(estimator.predict(x=np.ones(shape=(1, *estimator.input_shape)))): self._loss_object = tf.keras.losses.CategoricalCrossentropy(from_logits=False) else: self._loss_object = tf.keras.losses.CategoricalCrossentropy(from_logits=True) elif loss_type == "difference_logits_ratio": if is_probability(estimator.predict(x=np.ones(shape=(1, *estimator.input_shape)))): raise ValueError( "The provided estimator seems to predict probabilities. " "If loss_type='difference_logits_ratio' the estimator has to to predict logits." ) class difference_logits_ratio: def __init__(self): self.reduction = "mean" def __call__(self, y_true, y_pred): i_y_true = tf.cast(tf.math.argmax(tf.cast(y_true, tf.int32), axis=1), tf.int32) i_y_pred_arg = tf.argsort(y_pred, axis=1) i_z_i_list = list() for i in range(y_true.shape[0]): if i_y_pred_arg[i, -1] != i_y_true[i]: i_z_i_list.append(i_y_pred_arg[i, -1]) else: i_z_i_list.append(i_y_pred_arg[i, -2]) i_z_i = tf.stack(i_z_i_list) z_1 = tf.gather(y_pred, i_y_pred_arg[:, -1], axis=1, batch_dims=0) z_3 = tf.gather(y_pred, i_y_pred_arg[:, -3], axis=1, batch_dims=0) z_i = tf.gather(y_pred, i_z_i, axis=1, batch_dims=0) z_y = tf.gather(y_pred, i_y_true, axis=1, batch_dims=0) z_1 = tf.linalg.diag_part(z_1) z_3 = tf.linalg.diag_part(z_3) z_i = tf.linalg.diag_part(z_i) z_y = tf.linalg.diag_part(z_y) dlr = -(z_y - z_i) / (z_1 - z_3) return tf.reduce_mean(dlr) self._loss_fn = difference_logits_ratio() self._loss_object = difference_logits_ratio() estimator_apgd = TensorFlowV2Classifier( model=estimator.model, nb_classes=estimator.nb_classes, input_shape=estimator.input_shape, loss_object=self._loss_object, train_step=estimator._train_step, channels_first=estimator.channels_first, clip_values=estimator.clip_values, preprocessing_defences=estimator.preprocessing_defences, postprocessing_defences=estimator.postprocessing_defences, preprocessing=estimator.preprocessing, ) elif isinstance(estimator, PyTorchClassifier): import torch if loss_type == "cross_entropy": if is_probability( estimator.predict(x=np.ones(shape=(1, *estimator.input_shape), dtype=np.float32)) ): raise ValueError( "The provided estimator seems to predict probabilities. If loss_type='cross_entropy' " "the estimator has to to predict logits." ) self._loss_object = torch.nn.CrossEntropyLoss(reduction="mean") elif loss_type == "difference_logits_ratio": if is_probability( estimator.predict(x=np.ones(shape=(1, *estimator.input_shape), dtype=ART_NUMPY_DTYPE)) ): raise ValueError( "The provided estimator seems to predict probabilities. " "If loss_type='difference_logits_ratio' the estimator has to to predict logits." ) class difference_logits_ratio: def __init__(self): self.reduction = "mean" def __call__(self, y_pred, y_true): # type: ignore if isinstance(y_true, np.ndarray): y_true = torch.from_numpy(y_true) if isinstance(y_pred, np.ndarray): y_pred = torch.from_numpy(y_pred) y_true = y_true.float() i_y_true = torch.argmax(y_true, axis=1) i_y_pred_arg = torch.argsort(y_pred, axis=1) i_z_i_list = list() for i in range(y_true.shape[0]): if i_y_pred_arg[i, -1] != i_y_true[i]: i_z_i_list.append(i_y_pred_arg[i, -1]) else: i_z_i_list.append(i_y_pred_arg[i, -2]) i_z_i = torch.stack(i_z_i_list) z_1 = y_pred[:, i_y_pred_arg[:, -1]] z_3 = y_pred[:, i_y_pred_arg[:, -3]] z_i = y_pred[:, i_z_i] z_y = y_pred[:, i_y_true] z_1 = torch.diagonal(z_1) z_3 = torch.diagonal(z_3) z_i = torch.diagonal(z_i) z_y = torch.diagonal(z_y) dlr = -(z_y - z_i) / (z_1 - z_3) return torch.mean(dlr.float()) self._loss_object = difference_logits_ratio() estimator_apgd = PyTorchClassifier( model=estimator.model, loss=self._loss_object, input_shape=estimator.input_shape, nb_classes=estimator.nb_classes, optimizer=None, channels_first=estimator.channels_first, clip_values=estimator.clip_values, preprocessing_defences=estimator.preprocessing_defences, postprocessing_defences=estimator.postprocessing_defences, preprocessing=estimator.preprocessing, device_type=estimator._device, ) else: raise ValueError("The loss type {} is not supported for the provided estimator.".format(loss_type)) super().__init__(estimator=estimator_apgd) self.norm = norm self.eps = eps self.eps_step = eps_step self.max_iter = max_iter self.targeted = targeted self.nb_random_init = nb_random_init self.batch_size = batch_size self.loss_type = loss_type self.verbose = verbose self._check_params()
def __init__( self, estimator: "CLASSIFIER_LOSS_GRADIENTS_TYPE", norm: Union[int, float, str] = np.inf, eps: float = 0.3, eps_step: float = 0.1, max_iter: int = 100, targeted: bool = False, nb_random_init: int = 5, batch_size: int = 32, loss_type: Optional[str] = None, ): """ Create a :class:`.AutoProjectedGradientDescent` instance. :param estimator: An trained estimator. :param norm: The norm of the adversarial perturbation. Possible values: "inf", np.inf, 1 or 2. :param eps: Maximum perturbation that the attacker can introduce. :param eps_step: Attack step size (input variation) at each iteration. :param max_iter: The maximum number of iterations. :param targeted: Indicates whether the attack is targeted (True) or untargeted (False). :param nb_random_init: Number of random initialisations within the epsilon ball. For num_random_init=0 starting at the original input. :param batch_size: Size of the batch on which adversarial samples are generated. """ from art.estimators.classification import TensorFlowClassifier, TensorFlowV2Classifier, PyTorchClassifier if isinstance(estimator, TensorFlowClassifier): import tensorflow as tf if loss_type == "cross_entropy": if is_probability( estimator.predict(x=np.ones( shape=(1, *estimator.input_shape)))): raise NotImplementedError( "Cross-entropy loss is not implemented for probability output." ) else: self._loss_object = tf.reduce_mean( tf.keras.losses.categorical_crossentropy( y_pred=estimator._output, y_true=estimator._labels_ph, from_logits=True)) def loss_fn(y_true, y_pred): y_pred_norm = y_pred - np.amax( y_pred, axis=1, keepdims=True) loss_value = -(y_true * y_pred_norm - np.log( np.sum(np.exp(y_pred_norm), axis=1, keepdims=True))) return np.mean(loss_value) self._loss_fn = loss_fn elif loss_type == "difference_logits_ratio": if is_probability( estimator.predict(x=np.ones( shape=(1, *estimator.input_shape)))): raise ValueError( "The provided estimator seems to predict probabilities. If loss_type='difference_logits_ratio' " "the estimator has to to predict logits.") else: def difference_logits_ratio(y_true, y_pred): i_y_true = tf.cast( tf.math.argmax(tf.cast(y_true, tf.int32), axis=1), tf.int32) i_y_pred_arg = tf.argsort(y_pred, axis=1) i_z_i = tf.where(i_y_pred_arg[:, -1] != i_y_true[:], i_y_pred_arg[:, -2], i_y_pred_arg[:, -1]) z_1 = tf.gather(y_pred, i_y_pred_arg[:, -1], axis=1, batch_dims=0) z_3 = tf.gather(y_pred, i_y_pred_arg[:, -3], axis=1, batch_dims=0) z_i = tf.gather(y_pred, i_z_i, axis=1, batch_dims=0) z_y = tf.gather(y_pred, i_y_true, axis=1, batch_dims=0) z_1 = tf.linalg.diag_part(z_1) z_3 = tf.linalg.diag_part(z_3) z_i = tf.linalg.diag_part(z_i) z_y = tf.linalg.diag_part(z_y) dlr = -(z_y - z_i) / (z_1 - z_3) return tf.reduce_mean(dlr) def loss_fn(y_true, y_pred): i_y_true = np.argmax(y_true, axis=1) i_y_pred_arg = np.argsort(y_pred, axis=1) i_z_i = np.where(i_y_pred_arg[:, -1] != i_y_true[:], i_y_pred_arg[:, -1], i_y_pred_arg[:, -2]) z_1 = y_pred[:, i_y_pred_arg[:, -1]] z_3 = y_pred[:, i_y_pred_arg[:, -3]] z_i = y_pred[:, i_z_i] z_y = y_pred[:, i_y_true] z_1 = np.diag(z_1) z_3 = np.diag(z_3) z_i = np.diag(z_i) z_y = np.diag(z_y) dlr = -(z_y - z_i) / (z_1 - z_3) return np.mean(dlr) self._loss_fn = loss_fn self._loss_object = difference_logits_ratio( y_true=estimator._labels_ph, y_pred=estimator._output) elif loss_type is None: self._loss_object = estimator._loss_object else: raise ValueError( "The argument loss_type has an invalid value. The following options for loss_type are " "supported: {}".format( [None, "cross_entropy", "difference_logits_ratio"])) estimator_apgd = TensorFlowClassifier( input_ph=estimator._input_ph, output=estimator._output, labels_ph=estimator._labels_ph, train=estimator._train, loss=self._loss_object, learning=estimator._learning, sess=estimator._sess, channels_first=estimator.channels_first, clip_values=estimator.clip_values, preprocessing_defences=estimator.preprocessing_defences, postprocessing_defences=estimator.postprocessing_defences, preprocessing=estimator.preprocessing, feed_dict=estimator._feed_dict, ) elif isinstance(estimator, TensorFlowV2Classifier): import tensorflow as tf if loss_type == "cross_entropy": if is_probability( estimator.predict(x=np.ones( shape=(1, *estimator.input_shape)))): self._loss_object = tf.keras.losses.CategoricalCrossentropy( from_logits=False) self._loss_fn = self._loss_object else: self._loss_object = tf.keras.losses.CategoricalCrossentropy( from_logits=True) self._loss_fn = self._loss_object elif loss_type == "difference_logits_ratio": if is_probability( estimator.predict(x=np.ones( shape=(1, *estimator.input_shape)))): raise ValueError( "The provided estimator seems to predict probabilities. If loss_type='difference_logits_ratio' " "the estimator has to to predict logits.") else: def difference_logits_ratio(y_true, y_pred): i_y_true = tf.cast( tf.math.argmax(tf.cast(y_true, tf.int32), axis=1), tf.int32) i_y_pred_arg = tf.argsort(y_pred, axis=1) i_z_i_list = list() for i in range(y_true.shape[0]): if i_y_pred_arg[i, -1] != i_y_true[i]: i_z_i_list.append(i_y_pred_arg[i, -1]) else: i_z_i_list.append(i_y_pred_arg[i, -2]) i_z_i = tf.stack(i_z_i_list) z_1 = tf.gather(y_pred, i_y_pred_arg[:, -1], axis=1, batch_dims=0) z_3 = tf.gather(y_pred, i_y_pred_arg[:, -3], axis=1, batch_dims=0) z_i = tf.gather(y_pred, i_z_i, axis=1, batch_dims=0) z_y = tf.gather(y_pred, i_y_true, axis=1, batch_dims=0) z_1 = tf.linalg.diag_part(z_1) z_3 = tf.linalg.diag_part(z_3) z_i = tf.linalg.diag_part(z_i) z_y = tf.linalg.diag_part(z_y) dlr = -(z_y - z_i) / (z_1 - z_3) return tf.reduce_mean(dlr) self._loss_fn = difference_logits_ratio self._loss_object = difference_logits_ratio elif loss_type is None: self._loss_object = estimator._loss_object else: raise ValueError( "The argument loss_type has an invalid value. The following options for loss_type are " "supported: {}".format( [None, "cross_entropy", "difference_logits_ratio"])) estimator_apgd = TensorFlowV2Classifier( model=estimator.model, nb_classes=estimator.nb_classes, input_shape=estimator.input_shape, loss_object=self._loss_object, train_step=estimator._train_step, channels_first=estimator.channels_first, clip_values=estimator.clip_values, preprocessing_defences=estimator.preprocessing_defences, postprocessing_defences=estimator.postprocessing_defences, preprocessing=estimator.preprocessing, ) elif isinstance(estimator, PyTorchClassifier): import torch if loss_type == "cross_entropy": if is_probability( estimator.predict( x=np.ones(shape=(1, *estimator.input_shape), dtype=np.float32))): raise ValueError( "The provided estimator seems to predict probabilities. If loss_type='cross_entropy' " "the estimator has to to predict logits.") else: def loss_fn(y_true, y_pred): return torch.nn.CrossEntropyLoss()( torch.from_numpy(y_pred), torch.from_numpy(np.argmax(y_true, axis=1))) self._loss_fn = loss_fn self._loss_object = torch.nn.CrossEntropyLoss() elif loss_type == "difference_logits_ratio": if is_probability( estimator.predict( x=np.ones(shape=(1, *estimator.input_shape), dtype=ART_NUMPY_DTYPE))): raise ValueError( "The provided estimator seems to predict probabilities. If loss_type='difference_logits_ratio' " "the estimator has to to predict logits.") else: # def difference_logits_ratio(y_true, y_pred): def difference_logits_ratio(y_pred, y_true): # type: ignore if isinstance(y_true, np.ndarray): y_true = torch.from_numpy(y_true) if isinstance(y_pred, np.ndarray): y_pred = torch.from_numpy(y_pred) y_true = y_true.float() # dlr = torch.mean((y_pred - y_true) ** 2) # return loss i_y_true = torch.argmax(y_true, axis=1) i_y_pred_arg = torch.argsort(y_pred, axis=1) i_z_i_list = list() for i in range(y_true.shape[0]): if i_y_pred_arg[i, -1] != i_y_true[i]: i_z_i_list.append(i_y_pred_arg[i, -1]) else: i_z_i_list.append(i_y_pred_arg[i, -2]) i_z_i = torch.stack(i_z_i_list) z_1 = y_pred[:, i_y_pred_arg[:, -1]] z_3 = y_pred[:, i_y_pred_arg[:, -3]] z_i = y_pred[:, i_z_i] z_y = y_pred[:, i_y_true] z_1 = torch.diagonal(z_1) z_3 = torch.diagonal(z_3) z_i = torch.diagonal(z_i) z_y = torch.diagonal(z_y) dlr = -(z_y - z_i) / (z_1 - z_3) return torch.mean(dlr.float()) self._loss_fn = difference_logits_ratio self._loss_object = difference_logits_ratio elif loss_type is None: self._loss_object = estimator._loss_object else: raise ValueError( "The argument loss_type has an invalid value. The following options for loss_type are " "supported: {}".format( [None, "cross_entropy", "difference_logits_ratio"])) estimator_apgd = PyTorchClassifier( model=estimator.model, loss=self._loss_object, input_shape=estimator.input_shape, nb_classes=estimator.nb_classes, optimizer=None, channels_first=estimator.channels_first, clip_values=estimator.clip_values, preprocessing_defences=estimator.preprocessing_defences, postprocessing_defences=estimator.postprocessing_defences, preprocessing=estimator.preprocessing, device_type=estimator._device, ) else: estimator_apgd = None super().__init__(estimator=estimator_apgd) self.norm = norm self.eps = eps self.eps_step = eps_step self.max_iter = max_iter self.targeted = targeted self.nb_random_init = nb_random_init self.batch_size = batch_size self.loss_type = loss_type self._check_params()
loss = tf.reduce_mean( tf.losses.softmax_cross_entropy(logits=logits, onehot_labels=labels_ph)) optimizer = tf.train.AdamOptimizer(learning_rate=0.01) train = optimizer.minimize(loss) sess = tf.Session() sess.run(tf.global_variables_initializer()) # Step 3: Create the ART classifier classifier = TensorFlowClassifier( clip_values=(min_pixel_value, max_pixel_value), input_ph=input_ph, output=logits, labels_ph=labels_ph, train=train, loss=loss, learning=None, sess=sess, preprocessing_defences=[], ) # Step 4: Train the ART classifier classifier.fit(x_train, y_train, batch_size=64, nb_epochs=3) # Step 5: Evaluate the ART classifier on benign test examples predictions = classifier.predict(x_test) accuracy = np.sum( np.argmax(predictions, axis=1) == np.argmax(y_test, axis=1)) / len(y_test)
from art.estimators.classification import TensorFlowClassifier from generate_folder_npy import generate # Step 1: Load the Vimeo90K dataset # Load from directory here path = "" (x_train, y_train), (x_test, y_test), min_pixel_value, max_pixel_value = generate() # Step 2: Create the model (in this case, load from pretrained model_path = "" # load model here # Step 3: Create the ART classifier classifier = TensorFlowClassifier(model=model_path, ) # Step 4: Train the ART classifier classifier.fit(x_train, y_train, batch_size=4, nb_epochs=3) # Step 5: Evaluate the ART classifier on benign test examples predictions = classifier.predict(x_test) accuracy = np.sum( np.argmax(predictions, axis=1) == np.argmax(y_test, axis=1)) / len(y_test) print("Accuracy on benign test examples: {}%".format(accuracy * 100)) # Step 6: Generate adversarial test examples attack = FrameSaliencyAttack(classifier=classifier, attacker=FastGradientMethod(estimator=classifier),