class_docstr: Implementation of Randomized Smoothing applied to classifier predictions and gradients, as introduced
  in Cohen et al. (2019).
  
  | Paper link: https://arxiv.org/abs/1902.02918
class_docstr_tok: ["Implementation","of","Randomized","Smoothing","applied","to","classifier","predictions","and","gradients",",","as","introduced","in","Cohen","et","al",".","(","2019",")",".","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/1902.02918"]
docstr: Compute the gradient of the loss function w.r.t. `x`.
  
  :param x: Sample input with shape as expected by the model.
  :param y: Target values (class labels) one-hot-encoded of shape (nb_samples, nb_classes) or indices of shape
            (nb_samples,).
  :param training_mode: `True` for model set to training mode and `'False` for model set to evaluation mode.
  :param sampling: True if loss gradients should be determined with Monte Carlo sampling.
  :type sampling: `bool`
  :return: Array of gradients of the same shape as `x`.
docstr_tok: ["Compute","the","gradient","of","the","loss","function","w.r.t",".","`","x","`",".",":","param","x",":","Sample","input","with","shape","as","expected","by","the","model",".",":","param","y",":","Target","values","(","class","labels",")","one-hot-encoded","of","shape","(","nb_samples",",","nb_classes",")","or","indices","of","shape","(","nb_samples",",",")",".",":","param","training_mode",":","`","True","`","for","model","set","to","training","mode","and","`","'False","`","for","model","set","to","evaluation","mode",".",":","param","sampling",":","True","if","loss","gradients","should","be","determined","with","Monte","Carlo","sampling",".",":","type","sampling",":","`","bool","`",":","return",":","Array","of","gradients","of","the","same","shape","as","`","x","`","."]
code: def loss_gradient(  # type: ignore
      self,
      x: np.ndarray,
      y: np.ndarray,
      training_mode: bool = False,
      **kwargs,
  ) -> np.ndarray:
      """
      Compute the gradient of the loss function w.r.t. `x`.
  
      :param x: Sample input with shape as expected by the model.
      :param y: Target values (class labels) one-hot-encoded of shape (nb_samples, nb_classes) or indices of shape
                (nb_samples,).
      :param training_mode: `True` for model set to training mode and `'False` for model set to evaluation mode.
      :param sampling: True if loss gradients should be determined with Monte Carlo sampling.
      :type sampling: `bool`
      :return: Array of gradients of the same shape as `x`.
      """
      import torch
  
      sampling = kwargs.get("sampling")
  
      if sampling:
          self._model.train(mode=training_mode)
  
          # Apply preprocessing
          x_preprocessed, y_preprocessed = self._apply_preprocessing(
              x, y, fit=False
          )
  
          # Check label shape
          if self._reduce_labels:
              y_preprocessed = np.argmax(y_preprocessed, axis=1)
  
          # Convert the inputs to Tensors
          inputs_t = torch.from_numpy(x_preprocessed).to(self._device)
          inputs_t.requires_grad = True
  
          # Convert the labels to Tensors
          labels_t = torch.from_numpy(y_preprocessed).to(self._device)
          inputs_repeat_t = inputs_t.repeat_interleave(
              self.sample_size, 0
          )
  
          noise = (
              torch.randn_like(inputs_repeat_t, device=self._device)
              * self.scale
          )
          inputs_noise_t = inputs_repeat_t + noise
          if self.clip_values is not None:
              inputs_noise_t.clamp(
                  torch.tensor(self.clip_values[0]),
                  torch.tensor(self.clip_values[1]),
              )
  
          model_outputs = self._model(inputs_noise_t)[-1]
          softmax = torch.nn.functional.softmax(model_outputs, dim=1)
          average_softmax = (
              softmax.reshape(
                  -1, self.sample_size, model_outputs.shape[-1]
              )
              .mean(1, keepdim=True)
              .squeeze(1)
          )
          log_softmax = torch.log(average_softmax.clamp(min=1e-20))
          loss = torch.nn.functional.nll_loss(log_softmax, labels_t)
  
          # Clean gradients
          self._model.zero_grad()
  
          # Compute gradients
          loss.backward()
          gradients = inputs_t.grad.cpu().numpy().copy()  # type: ignore
          gradients = self._apply_preprocessing_gradient(x, gradients)
          assert gradients.shape == x.shape
  
      else:
          gradients = PyTorchClassifier.loss_gradient(
              self, x=x, y=y, training_mode=training_mode, **kwargs
          )
  
      return gradients
  
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import List, Optional, Tuple, Union, TYPE_CHECKING
  import warnings
  from tqdm.auto import trange
  import numpy
  from art.config import ART_NUMPY_DTYPE
  from art.estimators.classification.pytorch import PyTorchClassifier
  from art.estimators.certification.randomized_smoothing.randomized_smoothing import RandomizedSmoothingMixin
  from art.utils import check_and_transform_label_format
label_desc: Use image node_id 6 for calling the PyTorchRandomizedSmoothing obj's underlying member method code with example usage: obj.loss_gradient(x, y, training_mode) and returns: gradients