class_docstr: Estimator class for PyTorch models.
class_docstr_tok: ["Estimator","class","for","PyTorch","models","."]
docstr: Apply the backward pass to the gradients through all preprocessing defences that have been applied to `x`
  and `y` in the forward pass. This function is should only be called from function
  `_apply_preprocessing_gradient`.
  
  The method overrides art.estimators.estimator::LossGradientsMixin._apply_preprocessing_gradient().
  It requires all defenses to have a method estimate_forward().
  It converts numpy arrays to PyTorch tensors first, then chains a series of defenses by calling
  defence.estimate_forward() which contains differentiable estimate of the operations. At the end,
  it converts PyTorch tensors back to numpy arrays.
  
  :param x: Samples.
  :type x: Format as expected by the `model`
  :param gradients: Gradients before backward pass through preprocessing defences.
  :type gradients: Format as expected by the `model`
  :param fit: `True` if the gradients are computed during training.
  :return: Gradients after backward pass through preprocessing defences.
  :rtype: Format as expected by the `model`
docstr_tok: ["Apply","the","backward","pass","to","the","gradients","through","all","preprocessing","defences","that","have","been","applied","to","`","x","`","and","`","y","`","in","the","forward","pass",".","This","function","is","should","only","be","called","from","function","`","_apply_preprocessing_gradient","`",".","The","method","overrides","art.estimators.estimator",":",":LossGradientsMixin._apply_preprocessing_gradient","(",")",".","It","requires","all","defenses","to","have","a","method","estimate_forward","(",")",".","It","converts","numpy","arrays","to","PyTorch","tensors","first",",","then","chains","a","series","of","defenses","by","calling","defence.estimate_forward","(",")","which","contains","differentiable","estimate","of","the","operations",".","At","the","end",",","it","converts","PyTorch","tensors","back","to","numpy","arrays",".",":","param","x",":","Samples",".",":","type","x",":","Format","as","expected","by","the","`","model","`",":","param","gradients",":","Gradients","before","backward","pass","through","preprocessing","defences",".",":","type","gradients",":","Format","as","expected","by","the","`","model","`",":","param","fit",":","`","True","`","if","the","gradients","are","computed","during","training",".",":","return",":","Gradients","after","backward","pass","through","preprocessing","defences",".",":","rtype",":","Format","as","expected","by","the","`","model","`"]
code: def _apply_preprocessing_gradient(self, x, gradients, fit=False):
      """
      Apply the backward pass to the gradients through all preprocessing defences that have been applied to `x`
      and `y` in the forward pass. This function is should only be called from function
      `_apply_preprocessing_gradient`.
  
      The method overrides art.estimators.estimator::LossGradientsMixin._apply_preprocessing_gradient().
      It requires all defenses to have a method estimate_forward().
      It converts numpy arrays to PyTorch tensors first, then chains a series of defenses by calling
      defence.estimate_forward() which contains differentiable estimate of the operations. At the end,
      it converts PyTorch tensors back to numpy arrays.
  
      :param x: Samples.
      :type x: Format as expected by the `model`
      :param gradients: Gradients before backward pass through preprocessing defences.
      :type gradients: Format as expected by the `model`
      :param fit: `True` if the gradients are computed during training.
      :return: Gradients after backward pass through preprocessing defences.
      :rtype: Format as expected by the `model`
      """
      import torch
  
      from art.preprocessing.standardisation_mean_std.numpy import (
          StandardisationMeanStd,
      )
      from art.preprocessing.standardisation_mean_std.pytorch import (
          StandardisationMeanStdPyTorch,
      )
  
      if not self.preprocessing_operations:
          return gradients
  
      input_is_tensor = isinstance(x, torch.Tensor)
  
      if self.all_framework_preprocessing and not (
          not input_is_tensor and x.dtype == object
      ):
          # Convert np arrays to torch tensors.
          x = torch.tensor(x, device=self._device, requires_grad=True)
          gradients = torch.tensor(gradients, device=self._device)
          x_orig = x
  
          for preprocess in self.preprocessing_operations:
              if fit:
                  if preprocess.apply_fit:
                      x = preprocess.estimate_forward(x)
              else:
                  if preprocess.apply_predict:
                      x = preprocess.estimate_forward(x)
  
          x.backward(gradients)
  
          # Convert torch tensors back to np arrays.
          gradients = x_orig.grad.detach().cpu().numpy()
          if gradients.shape != x_orig.shape:
              raise ValueError(
                  f"The input shape is {x.shape} while the gradient shape is {gradients.shape}"
              )
  
      elif len(self.preprocessing_operations) == 1 or (
          len(self.preprocessing_operations) == 2
          and isinstance(
              self.preprocessing_operations[-1],
              (StandardisationMeanStd, StandardisationMeanStdPyTorch),
          )
      ):
          # Compatible with non-PyTorch defences if no chaining.
          for preprocess in self.preprocessing_operations[::-1]:
              if fit:
                  if preprocess.apply_fit:
                      gradients = preprocess.estimate_gradient(
                          x, gradients
                      )
              else:
                  if preprocess.apply_predict:
                      gradients = preprocess.estimate_gradient(
                          x, gradients
                      )
  
      else:
          raise NotImplementedError(
              "The current combination of preprocessing types is not supported."
          )
  
      return gradients
  
file_path: adversarial-robustness-toolbox/art/estimators/pytorch.py
imports: import logging
  from typing import TYPE_CHECKING, Any, List, Tuple
  import numpy
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin, NeuralNetworkMixin
label_desc: Use image node_id 8 for calling the PyTorchEstimator obj's underlying member method code with example usage: obj._apply_preprocessing_gradient(x, gradients, fit) and returns: gradients, gradients