class_docstr: This attack was originally implemented by Goodfellow et al. (2015) with the infinity norm (and is known as the "Fast
  Gradient Sign Method"). This implementation extends the attack to other norms, and is therefore called the Fast
  Gradient Method.
  
  | Paper link: https://arxiv.org/abs/1412.6572
class_docstr_tok: ["This","attack","was","originally","implemented","by","Goodfellow","et","al",".","(","2015",")","with","the","infinity","norm","(","and","is","known","as","the","``","Fast","Gradient","Sign","Method","''",")",".","This","implementation","extends","the","attack","to","other","norms",",","and","is","therefore","called","the","Fast","Gradient","Method",".","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/1412.6572"]
code: def _compute_perturbation(
      self,
      x: np.ndarray,
      y: np.ndarray,
      mask: Optional[np.ndarray],
      decay: Optional[float] = None,
      momentum: Optional[np.ndarray] = None,
  ) -> np.ndarray:
      # Pick a small scalar to avoid division by 0
      tol = 10e-8
  
      # Get gradient wrt loss; invert it if attack is targeted
      grad = self.estimator.loss_gradient(x, y) * (
          1 - 2 * int(self.targeted)
      )
  
      # 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,
              patch=None,
              estimator=self.estimator,
              x=x,
              y=y,
              targeted=self.targeted,
          )
  
      # Check for NaN before normalisation an replace with 0
      if (
          grad.dtype != object and np.isnan(grad).any()
      ):  # pragma: no cover
          logger.warning(
              "Elements of the loss gradient are NaN and have been replaced with 0.0."
          )
          grad = np.where(np.isnan(grad), 0.0, grad)
      else:
          for i, _ in enumerate(grad):
              grad_i_array = grad[i].astype(np.float32)
              if np.isnan(grad_i_array).any():
                  grad[i] = np.where(
                      np.isnan(grad_i_array), 0.0, grad_i_array
                  ).astype(object)
  
      # Apply mask
      if mask is not None:
          grad = np.where(mask == 0.0, 0.0, grad)
  
      # Apply norm bound
      def _apply_norm(norm, grad, object_type=False):
          if (
              grad.dtype != object and np.isinf(grad).any()
          ) or np.isnan(  # pragma: no cover
              grad.astype(np.float32)
          ).any():
              logger.info(
                  "The loss gradient array contains at least one positive or negative infinity."
              )
  
          if norm in [np.inf, "inf"]:
              grad = np.sign(grad)
          elif norm == 1:
              if not object_type:
                  ind = tuple(range(1, len(x.shape)))
              else:
                  ind = None
              grad = grad / (
                  np.sum(np.abs(grad), axis=ind, keepdims=True) + tol
              )
          elif norm == 2:
              if not object_type:
                  ind = tuple(range(1, len(x.shape)))
              else:
                  ind = None
              grad = grad / (
                  np.sqrt(
                      np.sum(np.square(grad), axis=ind, keepdims=True)
                  )
                  + tol
              )
          return grad
  
      # Add momentum
      if decay is not None and momentum is not None:
          grad = _apply_norm(norm=1, grad=grad)
          grad = decay * momentum + grad
          momentum += grad
  
      if x.dtype == object:
          for i_sample in range(x.shape[0]):
              grad[i_sample] = _apply_norm(
                  self.norm, grad[i_sample], object_type=True
              )
              assert x[i_sample].shape == grad[i_sample].shape
      else:
          grad = _apply_norm(self.norm, grad)
  
      assert x.shape == grad.shape
  
      return grad
  
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import Optional, Union, TYPE_CHECKING
  import numpy
  from art.config import ART_NUMPY_DTYPE
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin
  from art.estimators.classification.classifier import ClassifierMixin
  from art.utils import compute_success, get_labels_np_array, random_sphere, projection, check_and_transform_label_format
  from art.summary_writer import SummaryWriter
label_desc: Use image node_id 6 for calling the FastGradientMethod obj's underlying member method code with example usage: obj._compute_perturbation(x, y, mask, decay, momentum) and returns: grad, grad