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: Apply perturbation on examples.
  
  :param x: Current adversarial examples.
  :param perturbation: Current perturbations.
  :param eps_step: Attack step size (input variation) at each iteration.
  :return: Adversarial examples.
docstr_tok: ["Apply","perturbation","on","examples",".",":","param","x",":","Current","adversarial","examples",".",":","param","perturbation",":","Current","perturbations",".",":","param","eps_step",":","Attack","step","size","(","input","variation",")","at","each","iteration",".",":","return",":","Adversarial","examples","."]
code: def _apply_perturbation_pytorch(  # pylint: disable=W0221
      self,
      x: "torch.Tensor",
      perturbation: "torch.Tensor",
      eps_step: Union[int, float, np.ndarray],
  ) -> "torch.Tensor":
      """
      Apply perturbation on examples.
  
      :param x: Current adversarial examples.
      :param perturbation: Current perturbations.
      :param eps_step: Attack step size (input variation) at each iteration.
      :return: Adversarial examples.
      """
      import torch
  
      eps_step = np.array(eps_step, dtype=ART_NUMPY_DTYPE)
      perturbation_step = (
          torch.tensor(eps_step).to(self.estimator.device)
          * perturbation
      )
      perturbation_step[torch.isnan(perturbation_step)] = 0
      x = x + perturbation_step
      if self.estimator.clip_values is not None:
          clip_min, clip_max = self.estimator.clip_values
          x = torch.max(
              torch.min(
                  x, torch.tensor(clip_max).to(self.estimator.device)
              ),
              torch.tensor(clip_min).to(self.estimator.device),
          )
  
      return 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 5 for calling the ProjectedGradientDescentPyTorch obj's underlying member method code with example usage: obj._apply_perturbation_pytorch(x, perturbation, eps_step) and returns: x