class_docstr: Implementation of the Shadow Attack.
  
  | Paper link: https://arxiv.org/abs/2003.08937
class_docstr_tok: ["Implementation","of","the","Shadow","Attack",".","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/2003.08937"]
docstr: Generate adversarial samples and return them in an array. This requires a lot of memory, therefore it accepts
  only a single samples as input, e.g. a batch of size 1.
  
  :param x: An array of a single original input sample.
  :param y: An array of a single target label.
  :return: An array with the adversarial examples.
docstr_tok: ["Generate","adversarial","samples","and","return","them","in","an","array",".","This","requires","a","lot","of","memory",",","therefore","it","accepts","only","a","single","samples","as","input",",","e.g",".","a","batch","of","size","1.",":","param","x",":","An","array","of","a","single","original","input","sample",".",":","param","y",":","An","array","of","a","single","target","label",".",":","return",":","An","array","with","the","adversarial","examples","."]
code: def generate(
      self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs
  ) -> np.ndarray:
      """
      Generate adversarial samples and return them in an array. This requires a lot of memory, therefore it accepts
      only a single samples as input, e.g. a batch of size 1.
  
      :param x: An array of a single original input sample.
      :param y: An array of a single target label.
      :return: An array with the adversarial examples.
      """
      if y is not None:
          y = check_and_transform_label_format(
              y, nb_classes=self.estimator.nb_classes
          )
  
      if y is None:
          # Throw error if attack is targeted, but no targets are provided
          if self.targeted:  # pragma: no cover
              raise ValueError(
                  "Target labels `y` need to be provided for a targeted attack."
              )
  
          logger.info(
              "Using model predictions as correct labels for FGM."
          )
          y = get_labels_np_array(
              self.estimator.predict(x, batch_size=self.batch_size)
          )
      else:
          self.targeted = True
  
      if (
          self.estimator.nb_classes == 2 and y.shape[1] == 1
      ):  # pragma: no cover
          raise ValueError(
              "This attack has not yet been tested for binary classification with a single output classifier."
          )
  
      if x.shape[0] > 1 or y.shape[0] > 1:  # pragma: no cover
          raise ValueError(
              "This attack only accepts a single sample as input."
          )
  
      if x.ndim != 4:  # pragma: no cover
          raise ValueError(
              "Unrecognized input dimension. Shadow Attack can only be applied to image data."
          )
  
      x = x.astype(ART_NUMPY_DTYPE)
      x_batch = np.repeat(x, repeats=self.batch_size, axis=0).astype(
          ART_NUMPY_DTYPE
      )
      x_batch = x_batch + np.random.normal(
          scale=self.sigma, size=x_batch.shape
      ).astype(ART_NUMPY_DTYPE)
      y_batch = np.repeat(y, repeats=self.batch_size, axis=0)
  
      perturbation = (
          np.random.uniform(
              low=self.estimator.clip_values[0],
              high=self.estimator.clip_values[1],
              size=x.shape,
          ).astype(ART_NUMPY_DTYPE)
          - (
              self.estimator.clip_values[1]
              - self.estimator.clip_values[0]
          )
          / 2
      )
  
      for _ in trange(
          self.nb_steps, desc="Shadow attack", disable=not self.verbose
      ):
          gradients_ce = np.mean(
              self.estimator.loss_gradient(
                  x=x_batch + perturbation, y=y_batch, sampling=False
              )
              * (1 - 2 * int(self.targeted)),
              axis=0,
              keepdims=True,
          )
          gradients = (
              gradients_ce
              - self._get_regularisation_loss_gradients(perturbation)
          )
          perturbation += self.learning_rate * gradients
  
      x_p = x + perturbation
      x_adv = np.clip(
          x_p,
          a_min=self.estimator.clip_values[0],
          a_max=self.estimator.clip_values[1],
      ).astype(ART_NUMPY_DTYPE)
  
      return x_adv
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/shadow_attack.py
imports: import logging
  from typing import Optional, Union
  import numpy
  from tqdm.auto import trange
  from art.config import ART_NUMPY_DTYPE
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin
  from art.estimators.classification.classifier import ClassifierMixin
  from art.estimators.classification import TensorFlowV2Classifier, PyTorchClassifier
  from art.estimators.certification.randomized_smoothing import TensorFlowV2RandomizedSmoothing, PyTorchRandomizedSmoothing
  from art.attacks.attack import EvasionAttack
  from art.utils import get_labels_np_array, check_and_transform_label_format
label_desc: Use image node_id 2 for calling the ShadowAttack obj's underlying member method code with example usage: obj.generate(x, y) and returns: x_adv