class_docstr: The Projected Gradient Descent attack is an iterative method in which, after each iteration, the perturbation is
  projected on an lp-ball of specified radius (in addition to clipping the values of the adversarial sample so that it
  lies in the permitted data range). This is the attack proposed by Madry et al. for adversarial training.
  
  | Paper link: https://arxiv.org/abs/1706.06083
class_docstr_tok: ["The","Projected","Gradient","Descent","attack","is","an","iterative","method","in","which",",","after","each","iteration",",","the","perturbation","is","projected","on","an","lp-ball","of","specified","radius","(","in","addition","to","clipping","the","values","of","the","adversarial","sample","so","that","it","lies","in","the","permitted","data","range",")",".","This","is","the","attack","proposed","by","Madry","et","al",".","for","adversarial","training",".","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/1706.06083"]
docstr: Generate adversarial samples and return them in an array.
  
  :param x: An array with the original inputs.
  :param y: Target values (class labels) one-hot-encoded of shape `(nb_samples, nb_classes)` or indices of shape
            (nb_samples,). Only provide this parameter if you'd like to use true labels when crafting adversarial
            samples. Otherwise, model predictions are used as labels to avoid the "label leaking" effect
            (explained in this paper: https://arxiv.org/abs/1611.01236). Default is `None`.
  :param mask: An array with a mask broadcastable to input `x` defining where to apply adversarial perturbations.
               Shape needs to be broadcastable to the shape of x and can also be of the same shape as `x`. Any
               features for which the mask is zero will not be adversarially perturbed.
  :type mask: `np.ndarray`
  :return: An array holding the adversarial examples.
docstr_tok: ["Generate","adversarial","samples","and","return","them","in","an","array",".",":","param","x",":","An","array","with","the","original","inputs",".",":","param","y",":","Target","values","(","class","labels",")","one-hot-encoded","of","shape","`","(","nb_samples",",","nb_classes",")","`","or","indices","of","shape","(","nb_samples",",",")",".","Only","provide","this","parameter","if","you","'d","like","to","use","true","labels","when","crafting","adversarial","samples",".","Otherwise",",","model","predictions","are","used","as","labels","to","avoid","the","``","label","leaking","''","effect","(","explained","in","this","paper",":","https",":","\/\/arxiv.org\/abs\/1611.01236",")",".","Default","is","`","None","`",".",":","param","mask",":","An","array","with","a","mask","broadcastable","to","input","`","x","`","defining","where","to","apply","adversarial","perturbations",".","Shape","needs","to","be","broadcastable","to","the","shape","of","x","and","can","also","be","of","the","same","shape","as","`","x","`",".","Any","features","for","which","the","mask","is","zero","will","not","be","adversarially","perturbed",".",":","type","mask",":","`","np.ndarray","`",":","return",":","An","array","holding","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.
  
      :param x: An array with the original inputs.
      :param y: Target values (class labels) one-hot-encoded of shape `(nb_samples, nb_classes)` or indices of shape
                (nb_samples,). Only provide this parameter if you'd like to use true labels when crafting adversarial
                samples. Otherwise, model predictions are used as labels to avoid the "label leaking" effect
                (explained in this paper: https://arxiv.org/abs/1611.01236). Default is `None`.
      :param mask: An array with a mask broadcastable to input `x` defining where to apply adversarial perturbations.
                   Shape needs to be broadcastable to the shape of x and can also be of the same shape as `x`. Any
                   features for which the mask is zero will not be adversarially perturbed.
      :type mask: `np.ndarray`
      :return: An array holding the adversarial examples.
      """
      import torch
  
      mask = self._get_mask(x, **kwargs)
  
      # Ensure eps is broadcastable
      self._check_compatibility_input_and_eps(x=x)
  
      # Check whether random eps is enabled
      self._random_eps()
  
      # Set up targets
      targets = self._set_targets(x, y)
  
      # Create dataset
      if mask is not None:
          # Here we need to make a distinction: if the masks are different for each input, we need to index
          # those for the current batch. Otherwise (i.e. mask is meant to be broadcasted), keep it as it is.
          if len(mask.shape) == len(x.shape):
              dataset = torch.utils.data.TensorDataset(
                  torch.from_numpy(x.astype(ART_NUMPY_DTYPE)),
                  torch.from_numpy(targets.astype(ART_NUMPY_DTYPE)),
                  torch.from_numpy(mask.astype(ART_NUMPY_DTYPE)),
              )
  
          else:
              dataset = torch.utils.data.TensorDataset(
                  torch.from_numpy(x.astype(ART_NUMPY_DTYPE)),
                  torch.from_numpy(targets.astype(ART_NUMPY_DTYPE)),
                  torch.from_numpy(
                      np.array(
                          [mask.astype(ART_NUMPY_DTYPE)] * x.shape[0]
                      )
                  ),
              )
  
      else:
          dataset = torch.utils.data.TensorDataset(
              torch.from_numpy(x.astype(ART_NUMPY_DTYPE)),
              torch.from_numpy(targets.astype(ART_NUMPY_DTYPE)),
          )
  
      data_loader = torch.utils.data.DataLoader(
          dataset=dataset,
          batch_size=self.batch_size,
          shuffle=False,
          drop_last=False,
      )
  
      # Start to compute adversarial examples
      adv_x = x.astype(ART_NUMPY_DTYPE)
  
      # Compute perturbation with batching
      for batch_id, batch_all in enumerate(
          tqdm(
              data_loader,
              desc="PGD - Batches",
              leave=False,
              disable=not self.verbose,
          )
      ):
          self._batch_id = batch_id
  
          if mask is not None:
              (batch, batch_labels, mask_batch) = (
                  batch_all[0],
                  batch_all[1],
                  batch_all[2],
              )
          else:
              (batch, batch_labels, mask_batch) = (
                  batch_all[0],
                  batch_all[1],
                  None,
              )
  
          batch_index_1, batch_index_2 = (
              batch_id * self.batch_size,
              (batch_id + 1) * self.batch_size,
          )
  
          batch_eps: Union[int, float, np.ndarray]
          batch_eps_step: Union[int, float, np.ndarray]
  
          # Compute batch_eps and batch_eps_step
          if isinstance(self.eps, np.ndarray) and isinstance(
              self.eps_step, np.ndarray
          ):
              if (
                  len(self.eps.shape) == len(x.shape)
                  and self.eps.shape[0] == x.shape[0]
              ):
                  batch_eps = self.eps[batch_index_1:batch_index_2]
                  batch_eps_step = self.eps_step[
                      batch_index_1:batch_index_2
                  ]
  
              else:
                  batch_eps = self.eps
                  batch_eps_step = self.eps_step
  
          else:
              batch_eps = self.eps
              batch_eps_step = self.eps_step
  
          for rand_init_num in range(max(1, self.num_random_init)):
              if rand_init_num == 0:
                  # first iteration: use the adversarial examples as they are the only ones we have now
                  adv_x[
                      batch_index_1:batch_index_2
                  ] = self._generate_batch(
                      x=batch,
                      targets=batch_labels,
                      mask=mask_batch,
                      eps=batch_eps,
                      eps_step=batch_eps_step,
                  )
              else:
                  adversarial_batch = self._generate_batch(
                      x=batch,
                      targets=batch_labels,
                      mask=mask_batch,
                      eps=batch_eps,
                      eps_step=batch_eps_step,
                  )
  
                  # return the successful adversarial examples
                  attack_success = compute_success_array(
                      self.estimator,
                      batch,
                      batch_labels,
                      adversarial_batch,
                      self.targeted,
                      batch_size=self.batch_size,
                  )
                  adv_x[batch_index_1:batch_index_2][
                      attack_success
                  ] = adversarial_batch[attack_success]
  
      logger.info(
          "Success rate of attack: %.2f%%",
          100
          * compute_success(
              self.estimator,
              x,
              targets,
              adv_x,
              self.targeted,
              batch_size=self.batch_size,
          ),
      )
  
      if self.summary_writer is not None:
          self.summary_writer.reset()
  
      return adv_x
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import Optional, Union, TYPE_CHECKING
  import numpy
  from tqdm.auto import tqdm
  from art.config import ART_NUMPY_DTYPE
  from art.summary_writer import SummaryWriter
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin
  from art.estimators.classification.classifier import ClassifierMixin
  from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent_numpy import ProjectedGradientDescentCommon
  from art.utils import compute_success, random_sphere, compute_success_array
label_desc: Use image node_id 2 for calling the ProjectedGradientDescentPyTorch obj's underlying member method code with example usage: obj.generate(x, y) and returns: adv_x