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: Get regularisation loss gradients.
  
  :param perturbation: The perturbation to be regularised.
  :return: The loss gradients of the perturbation.
docstr_tok: ["Get","regularisation","loss","gradients",".",":","param","perturbation",":","The","perturbation","to","be","regularised",".",":","return",":","The","loss","gradients","of","the","perturbation","."]
code: def _get_regularisation_loss_gradients(
      self, perturbation: np.ndarray
  ) -> np.ndarray:
      """
      Get regularisation loss gradients.
  
      :param perturbation: The perturbation to be regularised.
      :return: The loss gradients of the perturbation.
      """
      if not self.estimator.channels_first:
          perturbation = perturbation.transpose((0, 3, 1, 2))
  
      if self.framework == "tensorflow":
          import tensorflow as tf
  
          if tf.executing_eagerly():
              with tf.GradientTape() as tape:
                  perturbation_t = tf.convert_to_tensor(perturbation)
                  tape.watch(perturbation_t)
  
                  x_t = (
                      perturbation_t[:, :, :, 1:]
                      - perturbation_t[:, :, :, :-1]
                  )
                  y_t = (
                      perturbation_t[:, :, 1:, :]
                      - perturbation_t[:, :, :-1, :]
                  )
                  loss_tv = tf.reduce_sum(
                      x_t * x_t, axis=(1, 2, 3)
                  ) + tf.reduce_sum(y_t * y_t, axis=(1, 2, 3))
  
                  if perturbation_t.shape[1] == 1:
                      loss_s = 0.0
                  elif perturbation_t.shape[1] == 3:
                      loss_s = tf.norm(
                          (
                              perturbation_t[:, 0, :, :]
                              - perturbation_t[:, 1, :, :]
                          )
                          ** 2
                          + (
                              perturbation_t[:, 1, :, :]
                              - perturbation_t[:, 2, :, :]
                          )
                          ** 2
                          + (
                              perturbation_t[:, 0, :, :]
                              - perturbation_t[:, 2, :, :]
                          )
                          ** 2,
                          ord=2,
                          axis=(1, 2),
                      )
                  else:
                      raise ValueError(
                          "Value for number of channels in `perturbation_t.shape` not recognized."
                      )
  
                  loss_c = (
                      tf.norm(
                          tf.reduce_mean(
                              tf.abs(perturbation_t), axis=[2, 3]
                          ),
                          ord=2,
                          axis=1,
                      )
                      ** 2
                  )
                  loss = (
                      self.lambda_tv * loss_tv
                      + self.lambda_s * loss_s
                      + self.lambda_c * loss_c
                  )
                  gradients = tape.gradient(
                      loss, perturbation_t
                  ).numpy()
  
          else:  # pragma: no cover
              raise ValueError("Expecting eager execution.")
  
      elif self.framework == "pytorch":
          import torch
  
          perturbation_t = torch.from_numpy(perturbation).to("cpu")
          perturbation_t.requires_grad = True
  
          x_t = (
              perturbation_t[:, :, :, 1:] - perturbation_t[:, :, :, :-1]
          )
          y_t = (
              perturbation_t[:, :, 1:, :] - perturbation_t[:, :, :-1, :]
          )
  
          loss_tv = (x_t * x_t).sum(dim=(1, 2, 3)) + (y_t * y_t).sum(
              dim=(1, 2, 3)
          )
  
          if perturbation_t.shape[1] == 1:
              loss_s = 0.0
          elif perturbation_t.shape[1] == 3:
              loss_s = (
                  (
                      perturbation_t[:, 0, :, :]
                      - perturbation_t[:, 1, :, :]
                  )
                  ** 2
                  + (
                      perturbation_t[:, 1, :, :]
                      - perturbation_t[:, 2, :, :]
                  )
                  ** 2
                  + (
                      perturbation_t[:, 0, :, :]
                      - perturbation_t[:, 2, :, :]
                  )
                  ** 2
              ).norm(p=2, dim=(1, 2))
          else:
              raise ValueError(
                  "Value for number of channels in `perturbation_t.shape` not recognized."
              )
  
          loss_c = perturbation_t.abs().mean([2, 3]).norm(dim=1) ** 2
          loss = torch.mean(
              self.lambda_tv * loss_tv
              + self.lambda_s * loss_s
              + self.lambda_c * loss_c
          )
          loss.backward()
          gradients = perturbation_t.grad.numpy()
      else:
          raise NotImplementedError
  
      if not self.estimator.channels_first:
          gradients = gradients.transpose(0, 2, 3, 1)
  
      return gradients
  
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 3 for calling the ShadowAttack obj's underlying member method code with example usage: obj._get_regularisation_loss_gradients(perturbation) and returns: gradients