class_docstr: Implementation of the 'Auto Conjugate Gradient' attack.
  The original implementation is https://github.com/yamamura-k/ACG.
  
  | Paper link: https://arxiv.org/abs/2206.09628
class_docstr_tok: ["Implementation","of","the","'Auto","Conjugate","Gradient","'","attack",".","The","original","implementation","is","https",":","\/\/github.com\/yamamura-k\/ACG",".","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/2206.09628"]
docstr: Create a :class:`.AutoConjugateGradient` 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.
docstr_tok: ["Create","a",":","class",":","`",".AutoConjugateGradient","`","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","."]
code: 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:`.AutoConjugateGradient` 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 isinstance(estimator, TensorFlowClassifier):
          raise ValueError(
              "This attack does not support TensorFlow  v1."
          )
  
      if loss_type not in self._predefined_losses:
          raise ValueError(
              f"The argument loss_type has an invalid value. The following options for `loss_type` are currently "
              f"supported: {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(  # pragma: no cover
                  "AutoProjectedGradientDescent is expecting logits as estimator output, the provided "
                  "estimator seems to predict probabilities."
              )
  
          estimator_acg = estimator
      else:
          if isinstance(estimator, TensorFlowV2Classifier):
              import tensorflow as tf
  
              class TensorFlowV2Loss:
                  """abstract class of loss function of tensorflow v2"""
  
                  @abc.abstractmethod
                  def __call__(
                      self,
                      y_true: tf.Tensor,
                      y_pred: tf.Tensor,
                      *args,
                      **kwargs,
                  ) -> tf.Tensor:
                      raise NotImplementedError
  
              if loss_type == "cross_entropy":
  
                  class CrossEntropyLossV2(TensorFlowV2Loss):
                      """Class defining cross entropy loss with reduction options."""
  
                      def __init__(self, from_logits, reduction="sum"):
                          self.ce_loss = tf.keras.losses.CategoricalCrossentropy(
                              from_logits=from_logits,
                              reduction=tf.keras.losses.Reduction.NONE,
                          )
                          self.reduction = reduction
  
                      def __call__(
                          self,
                          y_true: tf.Tensor,
                          y_pred: tf.Tensor,
                          *args,
                          **kwargs,
                      ) -> tf.Tensor:
                          if self.reduction == "mean":
                              return tf.reduce_mean(
                                  self.ce_loss(y_true, y_pred)
                              )
                          if self.reduction == "sum":
                              return tf.reduce_sum(
                                  self.ce_loss(y_true, y_pred)
                              )
                          if self.reduction == "none":
                              return self.ce_loss(y_true, y_pred)
                          raise NotImplementedError()
  
                  if is_probability(
                      estimator.predict(
                          x=np.ones(shape=(1, *estimator.input_shape))
                      )
                  ):
                      _loss_object_tf: TensorFlowV2Loss = (
                          CrossEntropyLossV2(from_logits=False)
                      )
                  else:
                      _loss_object_tf = CrossEntropyLossV2(
                          from_logits=True
                      )
              elif loss_type == "difference_logits_ratio":
                  if is_probability(
                      estimator.predict(
                          x=np.ones(shape=(1, *estimator.input_shape))
                      )
                  ):
                      raise ValueError(  # pragma: no cover
                          "The provided estimator seems to predict probabilities. "
                          "If loss_type='difference_logits_ratio' the estimator has to to predict logits."
                      )
  
                  class DifferenceLogitsRatioTensorFlowV2(
                      TensorFlowV2Loss
                  ):
                      """
                      Callable class for Difference Logits Ratio loss in TensorFlow v2.
                      """
  
                      def __init__(self):
                          self.reduction = "sum"
  
                      def __call__(
                          self,
                          y_true: tf.Tensor,
                          y_pred: tf.Tensor,
                          *args,
                          **kwargs,
                      ) -> tf.Tensor:
                          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 = []
  
                          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)
                          if self.reduction == "mean":
                              return tf.reduce_mean(dlr)
                          if self.reduction == "sum":
                              return tf.reduce_sum(dlr)
                          if self.reduction == "none":
                              return dlr
                          raise NotImplementedError()
  
                  _loss_object_tf = DifferenceLogitsRatioTensorFlowV2()
  
              estimator_acg = TensorFlowV2Classifier(
                  model=estimator.model,
                  nb_classes=estimator.nb_classes,
                  input_shape=estimator.input_shape,
                  loss_object=_loss_object_tf,
                  optimizer=estimator.optimizer,
                  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(  # pragma: no cover
                          "The provided estimator seems to predict probabilities. If loss_type='cross_entropy' "
                          "the estimator has to to predict logits."
                      )
  
                  class CrossEntropyLossTorch(
                      torch.nn.modules.loss._Loss
                  ):  # pylint: disable=W0212
                      """Class defining cross entropy loss with reduction options."""
  
                      def __init__(self, reduction="sum"):
                          super().__init__()
                          self.ce_loss = torch.nn.CrossEntropyLoss(
                              reduction="none"
                          )
                          self.reduction = reduction
  
                      def __call__(
                          self,
                          y_true: torch.Tensor,
                          y_pred: torch.Tensor,
                          *args,
                          **kwargs,
                      ) -> torch.Tensor:
                          if self.reduction == "mean":
                              return self.ce_loss(y_true, y_pred).mean()
                          if self.reduction == "sum":
                              return self.ce_loss(y_true, y_pred).sum()
                          if self.reduction == "none":
                              return self.ce_loss(y_true, y_pred)
                          raise NotImplementedError()
  
                      def forward(
                          self,
                          input: torch.Tensor,
                          target: torch.Tensor,  # pylint: disable=W0622
                      ) -> torch.Tensor:
                          """
                          Forward method.
                          :param input: Predicted labels of shape (nb_samples, nb_classes).
                          :param target: Target labels of shape (nb_samples, nb_classes).
                          :return: Difference Logits Ratio Loss.
                          """
                          return self.__call__(
                              y_true=target, y_pred=input
                          )
  
                  _loss_object_pt: torch.nn.modules.loss._Loss = (
                      CrossEntropyLossTorch(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(  # pragma: no cover
                          "The provided estimator seems to predict probabilities. "
                          "If loss_type='difference_logits_ratio' the estimator has to to predict logits."
                      )
  
                  class DifferenceLogitsRatioPyTorch(
                      torch.nn.modules.loss._Loss
                  ):  # pylint: disable=W0212
                      """
                      Callable class for Difference Logits Ratio loss in PyTorch.
                      """
  
                      def __init__(self):
                          super().__init__()
                          self.reduction = "sum"
  
                      def __call__(
                          self,
                          y_pred: torch.Tensor,
                          y_true: torch.Tensor,
                      ) -> torch.Tensor:
                          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, dim=1)
                          i_y_pred_arg = torch.argsort(y_pred, dim=1)
                          i_z_i_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)).float()
                          if self.reduction == "mean":
                              return dlr.mean()
                          if self.reduction == "sum":
                              return dlr.sum()
                          if self.reduction == "none":
                              return dlr
                          raise NotImplementedError()
  
                      def forward(
                          self,
                          input: torch.Tensor,
                          target: torch.Tensor,  # pylint: disable=W0622
                      ) -> torch.Tensor:
                          """
                          Forward method.
                          :param input: Predicted labels of shape (nb_samples, nb_classes).
                          :param target: Target labels of shape (nb_samples, nb_classes).
                          :return: Difference Logits Ratio Loss.
                          """
                          return self.__call__(
                              y_true=target, y_pred=input
                          )
  
                  _loss_object_pt = DifferenceLogitsRatioPyTorch()
              else:
                  raise NotImplementedError()
  
              estimator_acg = PyTorchClassifier(
                  model=estimator.model,
                  loss=_loss_object_pt,
                  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=str(estimator._device),
              )
  
          else:  # pragma: no cover
              raise ValueError(
                  f"The loss type {loss_type} is not supported for the provided estimator."
              )
  
      super().__init__(estimator=estimator_acg)
      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()
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/auto_conjugate_gradient.py
imports: import abc
  import logging
  import math
  from typing import Optional, Union, TYPE_CHECKING
  import numpy
  from tqdm.auto import trange
  from art.config import ART_NUMPY_DTYPE
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin
  from art.estimators.classification.classifier import ClassifierMixin
  from art.utils import check_and_transform_label_format, projection, random_sphere, is_probability, get_labels_np_array
label_desc: Use image node_id 1 to create a new AutoConjugateGradient object from inherited base classes: EvasionAttack with example: obj = AutoConjugateGradient(estimator, norm, eps, eps_step, max_iter, targeted, nb_random_init, batch_size, loss_type, verbose)