class_docstr: Implementation of a particular variation of the DPatch attack.
  It follows Lee & Kolter (2019) in using sign gradients with expectations over transformations.
  The particular transformations supported in this implementation are cropping, rotations by multiples of 90 degrees,
  and changes in the brightness of the image.
  
  | Paper link (original DPatch): https://arxiv.org/abs/1806.02299v4
  | Paper link (physical-world patch from Lee & Kolter): https://arxiv.org/abs/1906.11897
class_docstr_tok: ["Implementation","of","a","particular","variation","of","the","DPatch","attack",".","It","follows","Lee","&","Kolter","(","2019",")","in","using","sign","gradients","with","expectations","over","transformations",".","The","particular","transformations","supported","in","this","implementation","are","cropping",",","rotations","by","multiples","of","90","degrees",",","and","changes","in","the","brightness","of","the","image",".","|","Paper","link","(","original","DPatch",")",":","https",":","\/\/arxiv.org\/abs\/1806.02299v4","|","Paper","link","(","physical-world","patch","from","Lee","&","Kolter",")",":","https",":","\/\/arxiv.org\/abs\/1906.11897"]
docstr: Revert transformation on gradients.
  
  :param gradients: The gradients to be reverse transformed.
  :param transforms: The transformations in forward direction.
  :param channels_first: Set channels first or last.
docstr_tok: ["Revert","transformation","on","gradients",".",":","param","gradients",":","The","gradients","to","be","reverse","transformed",".",":","param","transforms",":","The","transformations","in","forward","direction",".",":","param","channels_first",":","Set","channels","first","or","last","."]
code: def _untransform_gradients(
      self,
      gradients: np.ndarray,
      transforms: Dict[str, Union[int, float]],
      channels_first: bool,
  ) -> np.ndarray:
      """
      Revert transformation on gradients.
  
      :param gradients: The gradients to be reverse transformed.
      :param transforms: The transformations in forward direction.
      :param channels_first: Set channels first or last.
      """
  
      if channels_first:
          gradients = np.transpose(gradients, (0, 2, 3, 1))
  
      # Account for brightness adjustment:
      gradients = transforms["brightness"] * gradients
  
      # Undo rotations:
      rot90 = int((4 - transforms["rot90"]) % 4)
      gradients = np.rot90(gradients, k=rot90, axes=(1, 2))
  
      # Account for cropping when considering the upper left point of the patch:
      x_1 = self.patch_location[0] - int(transforms["crop_x"])
      y_1 = self.patch_location[1] - int(transforms["crop_y"])
      if channels_first:
          x_2 = x_1 + self.patch_shape[1]
          y_2 = y_1 + self.patch_shape[2]
      else:
          x_2 = x_1 + self.patch_shape[0]
          y_2 = y_1 + self.patch_shape[1]
      gradients = gradients[:, x_1:x_2, y_1:y_2, :]
  
      if channels_first:
          gradients = np.transpose(gradients, (0, 3, 1, 2))
  
      return gradients
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/dpatch_robust.py
imports: import logging
  import math
  import random
  from typing import Dict, List, Optional, Tuple, Union, TYPE_CHECKING
  import numpy
  from tqdm.auto import trange
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin
  from art.estimators.object_detection.object_detector import ObjectDetectorMixin
  from art import config
  from art.summary_writer import SummaryWriter
label_desc: Use image node_id 4 for calling the RobustDPatch obj's underlying member method code with example usage: obj._untransform_gradients(gradients, transforms, channels_first) and returns: gradients