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: Compute perturbations.
  
  :param x: Current adversarial examples.
  :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.
  :param decay: Decay factor for accumulating the velocity vector when using momentum.
  :param momentum: An array accumulating the velocity vector in the gradient direction for MIFGSM.
  :return: Perturbations.
docstr_tok: ["Compute","perturbations",".",":","param","x",":","Current","adversarial","examples",".",":","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",".",":","param","decay",":","Decay","factor","for","accumulating","the","velocity","vector","when","using","momentum",".",":","param","momentum",":","An","array","accumulating","the","velocity","vector","in","the","gradient","direction","for","MIFGSM",".",":","return",":","Perturbations","."]
code: def _compute_perturbation(  # pylint: disable=W0221
      self,
      x: "tf.Tensor",
      y: "tf.Tensor",
      mask: Optional["tf.Tensor"],
      decay: Optional[float] = None,
      momentum: Optional["tf.Tensor"] = None,
  ) -> "tf.Tensor":
      """
      Compute perturbations.
  
      :param x: Current adversarial examples.
      :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.
      :param decay: Decay factor for accumulating the velocity vector when using momentum.
      :param momentum: An array accumulating the velocity vector in the gradient direction for MIFGSM.
      :return: Perturbations.
      """
      import tensorflow as tf
  
      # Pick a small scalar to avoid division by 0
      tol = 10e-8
  
      # Get gradient wrt loss; invert it if attack is targeted
      grad: tf.Tensor = self.estimator.loss_gradient(
          x, y
      ) * tf.constant(1 - 2 * int(self.targeted), dtype=ART_NUMPY_DTYPE)
  
      # Write summary
      if self.summary_writer is not None:  # pragma: no cover
          self.summary_writer.update(
              batch_id=self._batch_id,
              global_step=self._i_max_iter,
              grad=grad.numpy(),
              patch=None,
              estimator=self.estimator,
              x=x.numpy(),
              y=y.numpy(),
              targeted=self.targeted,
          )
  
      # Check for NaN before normalisation an replace with 0
      if tf.reduce_any(tf.math.is_nan(grad)):  # pragma: no cover
          logger.warning(
              "Elements of the loss gradient are NaN and have been replaced with 0.0."
          )
          grad = tf.where(
              tf.math.is_nan(grad), tf.zeros_like(grad), grad
          )
  
      # Apply mask
      if mask is not None:
          grad = tf.where(mask == 0.0, 0.0, grad)
  
      # Add momentum
      if decay is not None and momentum is not None:
          ind = tuple(range(1, len(x.shape)))
          grad = tf.divide(
              grad,
              (
                  tf.math.reduce_sum(
                      tf.abs(grad), axis=ind, keepdims=True
                  )
                  + tol
              ),
          )
          grad = self.decay * momentum + grad
          # Accumulate the gradient for the next iter
          momentum += grad
  
      # Apply norm bound
      if self.norm == np.inf:
          grad = tf.sign(grad)
  
      elif self.norm == 1:
          ind = tuple(range(1, len(x.shape)))
          grad = tf.divide(
              grad,
              (
                  tf.math.reduce_sum(
                      tf.abs(grad), axis=ind, keepdims=True
                  )
                  + tol
              ),
          )
  
      elif self.norm == 2:
          ind = tuple(range(1, len(x.shape)))
          grad = tf.divide(
              grad,
              (
                  tf.math.sqrt(
                      tf.math.reduce_sum(
                          tf.math.square(grad), axis=ind, keepdims=True
                      )
                  )
                  + tol
              ),
          )
  
      assert x.shape == grad.shape
  
      return grad
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_tensorflow_v2.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.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
  from art.summary_writer import SummaryWriter
label_desc: Use image node_id 4 for calling the ProjectedGradientDescentTensorFlowV2 obj's underlying member method code with example usage: obj._compute_perturbation(x, y, mask, decay, momentum) and returns: grad