class_docstr: Given a latent variable generating a given adversarial sample, either inferred by an inverse GAN or randomly
  generated, the InverseGAN optimizes that latent variable to project a sample as close as possible to the adversarial
  sample without the adversarial noise.
class_docstr_tok: ["Given","a","latent","variable","generating","a","given","adversarial","sample",",","either","inferred","by","an","inverse","GAN","or","randomly","generated",",","the","InverseGAN","optimizes","that","latent","variable","to","project","a","sample","as","close","as","possible","to","the","adversarial","sample","without","the","adversarial","noise","."]
docstr: Applies the :class:`.InverseGAN` defence upon the sample input.
  
  :param x: Sample input.
  :param y: Labels of the sample `x`. This function does not affect them in any way.
  :return: Defended input.
docstr_tok: ["Applies","the",":","class",":","`",".InverseGAN","`","defence","upon","the","sample","input",".",":","param","x",":","Sample","input",".",":","param","y",":","Labels","of","the","sample","`","x","`",".","This","function","does","not","affect","them","in","any","way",".",":","return",":","Defended","input","."]
code: def __call__(
      self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs
  ) -> Tuple[np.ndarray, Optional[np.ndarray]]:
      """
      Applies the :class:`.InverseGAN` defence upon the sample input.
  
      :param x: Sample input.
      :param y: Labels of the sample `x`. This function does not affect them in any way.
      :return: Defended input.
      """
      batch_size = x.shape[0]
      iteration_count = 0
  
      if self.inverse_gan is not None:
          logger.info("Encoding x_adv into starting z encoding")
          initial_z_encoding = self.inverse_gan.predict(x)
      else:
          logger.info("Choosing a random starting z encoding")
          initial_z_encoding = np.random.rand(
              batch_size, self.gan.encoding_length
          )
  
      def func_gen_gradients(z_i):
          z_i_reshaped = np.reshape(
              z_i, [batch_size, self.gan.encoding_length]
          )
          grad = self.estimate_gradient(z_i_reshaped, x)
          grad = np.float64(
              grad
          )  # scipy fortran code seems to expect float64 not 32 https://github.com/scipy/scipy/issues/5832
  
          return grad.flatten()
  
      def func_loss(z_i):
          nonlocal iteration_count
          iteration_count += 1
          logging.info("Iteration: %d", iteration_count)
          z_i_reshaped = np.reshape(
              z_i, [batch_size, self.gan.encoding_length]
          )
          loss = self.compute_loss(z_i_reshaped, x)
  
          return loss
  
      options_allowed_keys = [
          "disp",
          "maxcor",
          "ftol",
          "gtol",
          "eps",
          "maxfun",
          "maxiter",
          "iprint",
          "callback",
          "maxls",
      ]
  
      for key in kwargs:
          if key not in options_allowed_keys:
              raise KeyError(
                  f"The argument `{key}` in kwargs is not allowed as option for `scipy.optimize.minimize` using "
                  f'`method="L-BFGS-B".`'
              )
  
      options = kwargs.copy()
      optimized_z_encoding_flat = minimize(
          func_loss,
          initial_z_encoding,
          jac=func_gen_gradients,
          method="L-BFGS-B",
          options=options,
      )
      optimized_z_encoding = np.reshape(
          optimized_z_encoding_flat.x,
          [batch_size, self.gan.encoding_length],
      )
      y = self.gan.predict(optimized_z_encoding)
  
      return x, y
  
file_path: adversarial-robustness-toolbox/art/defences/preprocessor/inverse_gan.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import Optional, Tuple, TYPE_CHECKING
  import numpy
  from scipy.optimize import minimize
  from art.defences.preprocessor.preprocessor import Preprocessor
label_desc: Use image node_id 2 for calling the InverseGAN obj's underlying member method code with example usage: obj.__call__(x, y) and returns: x,  y, grad, loss