class_docstr: Class performing adversarial training following Oracle Aligned Adversarial Training (OAAT) protocol.
  
  | Paper link: https://link.springer.com/chapter/10.1007/978-3-031-20065-6_18
class_docstr_tok: ["Class","performing","adversarial","training","following","Oracle","Aligned","Adversarial","Training","(","OAAT",")","protocol",".","|","Paper","link",":","https",":","\/\/link.springer.com\/chapter\/10.1007\/978-3-031-20065-6_18"]
docstr: Compute perturbations.
  
  :param x: Current adversarial examples.
  :param x_init: initial input samples.
  :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 training_mode: training mode of classifier for attack generation. training_mode=False puts classifier in
                          eval mode
docstr_tok: ["Compute","perturbations",".",":","param","x",":","Current","adversarial","examples",".",":","param","x_init",":","initial","input","samples",".",":","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","training_mode",":","training","mode","of","classifier","for","attack","generation",".","training_mode=False","puts","classifier","in","eval","mode"]
code: def _compute_perturbation(
      self,
      x: "torch.Tensor",
      x_init: "torch.Tensor",
      y: "torch.Tensor",
      training_mode: bool = False,
  ) -> "torch.Tensor":
      """
      Compute perturbations.
  
      :param x: Current adversarial examples.
      :param x_init: initial input samples.
      :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 training_mode: training mode of classifier for attack generation. training_mode=False puts classifier in
                              eval mode
      """
      import torch
  
      self._classifier.model.train(mode=training_mode)
      self._lpips_classifier.model.train(mode=training_mode)
  
      # Backpropagation through RNN modules in eval mode raises RuntimeError due to cudnn issues and require training
      # mode, i.e. RuntimeError: cudnn RNN backward can only be called in training mode. Therefore, if the model is
      # an RNN type we always use training mode but freeze batch-norm and dropout layers if training_mode=False.
      if self._classifier.is_rnn:
          self._classifier.model.train(mode=True)
          if not training_mode:
              logger.debug(
                  "Freezing batch-norm and dropout layers for gradient calculation in train mode with eval parameters"
                  "of batch-norm and dropout."
              )
              self._classifier.set_batchnorm(train=False)
              self._classifier.set_dropout(train=False)
  
      if self._lpips_classifier.is_rnn:
          self._lpips_classifier.model.train(mode=True)
          if not training_mode:
              logger.debug(
                  "Freezing batch-norm and dropout layers for gradient calculation in train mode with eval parameters"
                  "of batch-norm and dropout."
              )
              self._lpips_classifier.set_batchnorm(train=False)
              self._lpips_classifier.set_dropout(train=False)
  
      # Apply preprocessing
      if self._classifier.all_framework_preprocessing:
          if isinstance(x, torch.Tensor):
              x_grad = x.clone().detach().requires_grad_(True)
          else:
              x_grad = torch.tensor(x).to(self._classifier.device)
              x_grad.requires_grad = True
          if isinstance(y, torch.Tensor):
              y_grad = y.clone().detach()
          else:
              y_grad = torch.tensor(y).to(self._classifier.device)
          if isinstance(x_init, torch.Tensor):
              x_init = x_init.clone().detach()
          else:
              x_init = torch.tensor(x_init).to(self._classifier.device)
          (
              inputs_t,
              y_preprocessed,
          ) = self._classifier._apply_preprocessing(  # pylint: disable=W0212
              x_grad, y=y_grad, fit=False, no_grad=False
          )
          (
              inputs_init,
              _,
          ) = self._classifier._apply_preprocessing(  # pylint: disable=W0212
              x_init, y=y_grad, fit=False, no_grad=False
          )
      elif isinstance(x, np.ndarray):
          (
              x_preprocessed,
              y_preprocessed,
          ) = self._classifier._apply_preprocessing(  # pylint: disable=W0212
              x, y=y, fit=False, no_grad=True
          )
          x_grad = torch.from_numpy(x_preprocessed).to(
              self._classifier.device
          )
          x_grad.requires_grad = True
          inputs_t = x_grad
          (
              x_init_preprocessed,
              _,
          ) = self._classifier._apply_preprocessing(  # pylint: disable=W0212
              x_init, y=y, fit=False, no_grad=True
          )
          x_init = torch.from_numpy(x_init_preprocessed).to(
              self._classifier.device
          )
          x_init.requires_grad = False
          inputs_init = x_init
      else:
          raise NotImplementedError(
              "Combination of inputs and preprocessing not supported."
          )
  
      # Check label shape
      if self._classifier._reduce_labels:  # pylint: disable=W0212
          y_preprocessed = self._classifier.reduce_labels(
              y_preprocessed
          )
  
      if isinstance(y_preprocessed, np.ndarray):
          labels_t = torch.from_numpy(y_preprocessed).to(
              self._classifier.device
          )
      else:
          labels_t = y_preprocessed
  
      # Compute the gradient and return
      model_outputs = self._classifier.model(inputs_t)
  
      lpips_distance = self.calculate_lpips_distance(
          p_classifier=self._lpips_classifier,
          input_1=inputs_t,
          input_2=inputs_init,
          layers=self._train_params["layer_names_activation"],
      )
      loss = self._classifier.loss(
          model_outputs, labels_t
      ) - self._train_params["i_lpips_weight"] * torch.mean(
          lpips_distance
      )
  
      # Clean gradients
      self._classifier.model.zero_grad()
      self._lpips_classifier.model.zero_grad()
  
      loss.backward()
  
      if x_grad.grad is not None:
          grad = x_grad.grad
      else:
          raise ValueError("Gradient term in PyTorch model is `None`.")
  
      if not self._classifier.all_framework_preprocessing:
          grad = self._classifier._apply_preprocessing_gradient(
              x, grad
          )  # pylint: disable=W0212
      assert grad.shape == x.shape
  
      # Check for nan before normalisation and replace with 0
      if torch.any(grad.isnan()):  # pragma: no cover
          logger.warning(
              "Elements of the loss gradient are NaN and have been replaced with 0.0."
          )
          grad[grad.isnan()] = 0.0
  
      # Apply norm bound
      if self._train_params["norm"] in ["inf", np.inf]:
          grad = grad.sign()
  
      elif self._train_params["norm"] == 1:
          ind = tuple(range(1, len(x.shape)))
          grad = grad / (torch.sum(grad.abs(), dim=ind, keepdims=True) + EPS)  # type: ignore
  
      elif self._train_params["norm"] == 2:
          ind = tuple(range(1, len(x.shape)))
          grad = grad / (torch.sqrt(torch.sum(grad * grad, axis=ind, keepdims=True)) + EPS)  # type: ignore
  
      assert x.shape == grad.shape
  
      return grad
  
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  from collections import OrderedDict
  import logging
  import os
  import time
  from typing import Optional, Tuple, TYPE_CHECKING, List, Dict, Union
  import six
  import numpy
  from tqdm.auto import trange
  from art import config
  from art.defences.trainer.adversarial_trainer_oaat import AdversarialTrainerOAAT
  from art.estimators.classification.pytorch import PyTorchClassifier
  from art.data_generators import DataGenerator
  from art.attacks.attack import EvasionAttack
  from art.utils import check_and_transform_label_format, random_sphere
  from art.config import ART_NUMPY_DTYPE
label_desc: Use image node_id 14 for calling the AdversarialTrainerOAATPyTorch obj's underlying member method code with example usage: obj._compute_perturbation(x, x_init, y, training_mode) and returns: grad