class_docstr: Implementation of the white-box PyTorch GRAPHITE attack from Feng et al. (2022). This is a physical attack
  that generates robust physical perturbations that can be applied as stickers.
  
  | Paper link: https://arxiv.org/abs/2002.07088
  | Original github link: https://github.com/ryan-feng/GRAPHITE
class_docstr_tok: ["Implementation","of","the","white-box","PyTorch","GRAPHITE","attack","from","Feng","et","al",".","(","2022",")",".","This","is","a","physical","attack","that","generates","robust","physical","perturbations","that","can","be","applied","as","stickers",".","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/2002.07088","|","Original","github","link",":","https",":","\/\/github.com\/ryan-feng\/GRAPHITE"]
docstr: Internal attack function for one example.
  
  :param x: An array with one original input to be attacked.
  :param y: The target label.
  :param mask: An array with a mask to be applied to the adversarial perturbations. Shape needs to be
               broadcastable to the shape of x. Any features for which the mask is zero will not be adversarially
               perturbed.
  :param obj_width: Estimated width of object in inches for perspective transform.
  :param focal: Estimated focal length in ft for perspective transform.
  :param clip_min: Minimum value of an example.
  :param clip_max: Maximum value of an example.
  :param pts: Optional. A set of points that will set the crop size in the perspective transform.
  :return: An adversarial example.
docstr_tok: ["Internal","attack","function","for","one","example",".",":","param","x",":","An","array","with","one","original","input","to","be","attacked",".",":","param","y",":","The","target","label",".",":","param","mask",":","An","array","with","a","mask","to","be","applied","to","the","adversarial","perturbations",".","Shape","needs","to","be","broadcastable","to","the","shape","of","x",".","Any","features","for","which","the","mask","is","zero","will","not","be","adversarially","perturbed",".",":","param","obj_width",":","Estimated","width","of","object","in","inches","for","perspective","transform",".",":","param","focal",":","Estimated","focal","length","in","ft","for","perspective","transform",".",":","param","clip_min",":","Minimum","value","of","an","example",".",":","param","clip_max",":","Maximum","value","of","an","example",".",":","param","pts",":","Optional",".","A","set","of","points","that","will","set","the","crop","size","in","the","perspective","transform",".",":","return",":","An","adversarial","example","."]
code: def _perturb(
      self,
      x: np.ndarray,
      y: np.ndarray,
      mask: np.ndarray,
      obj_width: float,
      focal: float,
      clip_min: float,
      clip_max: float,
      pts: Optional[np.ndarray],
  ) -> np.ndarray:
      """
      Internal attack function for one example.
  
      :param x: An array with one original input to be attacked.
      :param y: The target label.
      :param mask: An array with a mask to be applied to the adversarial perturbations. Shape needs to be
                   broadcastable to the shape of x. Any features for which the mask is zero will not be adversarially
                   perturbed.
      :param obj_width: Estimated width of object in inches for perspective transform.
      :param focal: Estimated focal length in ft for perspective transform.
      :param clip_min: Minimum value of an example.
      :param clip_max: Maximum value of an example.
      :param pts: Optional. A set of points that will set the crop size in the perspective transform.
      :return: An adversarial example.
      """
      import torch
  
      x = (x.copy() - clip_min) / (clip_max - clip_min)
  
      mask = mask / np.max(mask)
      mask = np.where(mask > 0.5, 1.0, 0.0)
  
      x_copy = x.copy()
      mask_copy = mask.copy()
      y_onehot = y.copy()
      y = np.argmax(y, axis=0)
  
      # Load victim img and starting mask.
      img = torch.tensor(
          x_copy, requires_grad=True, device=self.estimator.device
      )
      mask_tensor = torch.tensor(
          mask_copy, requires_grad=True, device=self.estimator.device
      ).to(img.dtype)
      y_onehot_tensor = torch.tensor(
          y_onehot, requires_grad=True, device=self.estimator.device
      )
  
      # Load transforms.
      xforms = get_transform_params(
          self.num_xforms,
          self.rotation_range,
          self.dist_range,
          self.gamma_range,
          self.crop_percent_range,
          self.off_x_range,
          self.off_y_range,
          self.blur_kernels,
          obj_width,
          focal,
      )
  
      target_label = y
      # Attack
      rounds = 0
      transform_robustness = -1.0
      prev_attack = img.detach().clone()
      while True:
          adv_img = img.detach().clone()
          adv_img = torch.where(mask_tensor > 0.5, prev_attack, adv_img)
          rand_start = (
              torch.FloatTensor(*img.size())
              .uniform_(
                  self.rand_start_epsilon_range[0],
                  self.rand_start_epsilon_range[1],
              )
              .to(adv_img.device)
          )
          adv_img = (adv_img + mask_tensor * rand_start).detach()
          adv_img = torch.clamp(adv_img, 0, 1).to(img.dtype)
          adv_img.requires_grad = True
          final_avg_grad = torch.zeros(img.size())
  
          # Do EOT adversarial attack with current mask.
          loop_length = self.steps if rounds > 0 else self.first_steps
          for _ in range(loop_length):
              avg_grad = torch.zeros(adv_img.size()).to(
                  self.estimator.device
              )
              for xform in xforms:
                  xform_img = transform_wb(
                      img.clone().unsqueeze(0),
                      adv_img.unsqueeze(0),
                      mask_tensor,
                      xform,
                      self.net_size,
                      clip_min,
                      clip_max,
                      pts,
                  )
  
                  (
                      logits,
                      _,
                  ) = self.estimator._predict_framework(  # pylint: disable=W0212
                      xform_img.to(self.estimator.device),
                      y_onehot_tensor,
                  )
                  if self.use_logits:
                      loss = torch.nn.functional.cross_entropy(
                          input=logits,
                          target=torch.tensor(target_label)
                          .unsqueeze(0)
                          .to(logits.device),
                          reduction="mean",
                      )
                  else:
                      loss = torch.nn.functional.nll_loss(
                          input=logits,
                          target=torch.tensor(target_label).unsqueeze(
                              0
                          ),
                          reduction="mean",
                      )
  
                  grad = torch.autograd.grad(loss, adv_img)[0]
                  avg_grad += grad
              avg_grad /= len(xforms)
  
              avg_grad_sign = avg_grad.clone()
              avg_grad_sign = torch.sign(avg_grad_sign)
              avg_grad_sign[torch.isnan(avg_grad_sign)] = 0
              adv_img = (
                  adv_img - mask_tensor * self.step_size * avg_grad_sign
              )
  
              adv_img = adv_img.clamp(0, 1)
              transform_robustness = self._eval(
                  img.detach().clone(),
                  adv_img,
                  mask_tensor,
                  target_label,
                  y_onehot_tensor,
                  xforms,
                  clip_min,
                  clip_max,
                  pts,
              )
              final_avg_grad = avg_grad
              if transform_robustness >= self.min_tr:
                  break
  
          if transform_robustness < self.min_tr:
              break
  
          prev_attack = adv_img.detach().clone()
  
          # Remove low-impact pixel-patches or pixels in mask.
          pert = adv_img - img
          final_avg_grad[torch.isnan(final_avg_grad)] = 0
          final_avg_grad = mask_tensor * final_avg_grad * pert
          pixelwise_avg_grads = torch.sum(
              torch.abs(final_avg_grad), dim=0
          )
  
          for _ in range(self.num_patches_to_remove):
              # Find minimum gradient patch and remove it.
              min_patch_grad = None
              min_patch_grad_idx = None
              for i in np.arange(
                  0,
                  pixelwise_avg_grads.shape[0]
                  - self.patch_removal_size
                  + 0.0001,
                  self.patch_removal_interval,
              ):
                  for j in np.arange(
                      0,
                      pixelwise_avg_grads.shape[1]
                      - self.patch_removal_size
                      + 0.0001,
                      self.patch_removal_interval,
                  ):
                      patch_grad = pixelwise_avg_grads[
                          int(round(i)) : int(
                              round(i + self.patch_removal_size)
                          ),
                          int(round(j)) : int(
                              round(j + self.patch_removal_size)
                          ),
                      ].sum()
  
                      if (
                          mask_tensor[
                              0,
                              int(round(i)) : int(
                                  round(i + self.patch_removal_size)
                              ),
                              int(round(j)) : int(
                                  round(j + self.patch_removal_size)
                              ),
                          ].sum()
                          > 0
                      ):
                          patch_grad = (
                              patch_grad
                              / mask_tensor[
                                  0,
                                  int(round(i)) : int(
                                      round(i + self.patch_removal_size)
                                  ),
                                  int(round(j)) : int(
                                      round(j + self.patch_removal_size)
                                  ),
                              ].sum()
                          )  # TODO1
                          if (
                              min_patch_grad is None
                              or patch_grad.item() < min_patch_grad
                          ):
                              min_patch_grad = patch_grad.item()
                              min_patch_grad_idx = (i, j)
              if min_patch_grad_idx is None:
                  break
              i, j = min_patch_grad_idx
              mask_tensor[
                  0,
                  int(round(i)) : int(
                      round(i + self.patch_removal_size)
                  ),
                  int(round(j)) : int(
                      round(j + self.patch_removal_size)
                  ),
              ] = 0
              if img.size()[0] == 3:
                  mask_tensor[
                      1,
                      int(round(i)) : int(
                          round(i + self.patch_removal_size)
                      ),
                      int(round(j)) : int(
                          round(j + self.patch_removal_size)
                      ),
                  ] = 0
                  mask_tensor[
                      2,
                      int(round(i)) : int(
                          round(i + self.patch_removal_size)
                      ),
                      int(round(j)) : int(
                          round(j + self.patch_removal_size)
                      ),
                  ] = 0
  
          rounds += 1
  
      out = prev_attack.detach().clone().cpu().numpy()
      adversarial = np.clip(
          out.copy() * (clip_max - clip_min) + clip_min,
          clip_min,
          clip_max,
      )
      return adversarial
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/graphite/graphite_whitebox_pytorch.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import Optional, Tuple, Union, TYPE_CHECKING, List
  import numpy
  from art.config import ART_NUMPY_DTYPE
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator
  from art.estimators.classification import ClassifierMixin
  from art.utils import compute_success, to_categorical, check_and_transform_label_format, is_probability
  from art.attacks.evasion.graphite.utils import convert_to_network, get_transform_params, transform_wb
label_desc: Use image node_id 4 for calling the GRAPHITEWhiteboxPyTorch obj's underlying member method code with example usage: obj._perturb(x, y, mask, obj_width, focal, clip_min, clip_max, pts) and returns: adversarial