class_docstr: Implementation of the imperceptible attack against a speech recognition model.
  
  | Paper link: http://proceedings.mlr.press/v97/qin19a.html
docstr: Create imperceptible, adversarial example with small perturbation.
  
  This method implements the part of the paper by Qin et al. (2019) that is described as the second stage of the
  attack. The resulting adversarial audio samples are able to successfully deceive the ASR estimator and are
  imperceptible to the human ear.
  
  :param x: An array with the original inputs to be attacked.
  :param x_adversarial: An array with the adversarial examples.
  :param y: Target values of shape (batch_size,). Each sample in `y` is a string and it may possess different
      lengths. A possible example of `y` could be: `y = np.array(['SIXTY ONE', 'HELLO'])`.
  :return: An array with the imperceptible, adversarial outputs.
code: def _create_imperceptible(
      self, x: np.ndarray, x_adversarial: np.ndarray, y: np.ndarray
  ) -> np.ndarray:
      """
      Create imperceptible, adversarial example with small perturbation.
  
      This method implements the part of the paper by Qin et al. (2019) that is described as the second stage of the
      attack. The resulting adversarial audio samples are able to successfully deceive the ASR estimator and are
      imperceptible to the human ear.
  
      :param x: An array with the original inputs to be attacked.
      :param x_adversarial: An array with the adversarial examples.
      :param y: Target values of shape (batch_size,). Each sample in `y` is a string and it may possess different
          lengths. A possible example of `y` could be: `y = np.array(['SIXTY ONE', 'HELLO'])`.
      :return: An array with the imperceptible, adversarial outputs.
      """
      batch_size = x.shape[0]
      alpha_min = 0.0005
  
      # for ragged input, use object dtype
      dtype = np.float32 if x.ndim != 1 else object
  
      early_stop = [False] * batch_size
  
      alpha = np.array([self.alpha] * batch_size, dtype=np.float32)
      loss_theta_previous = [np.inf] * batch_size
      x_imperceptible = [None] * batch_size
      # if inputs are *not* ragged, we can't multiply alpha * gradients_theta
      if x.ndim != 1:
          alpha = np.expand_dims(alpha, axis=-1)
  
      (
          masking_threshold,
          psd_maximum,
      ) = self._stabilized_threshold_and_psd_maximum(x)
  
      x_perturbed = x_adversarial.copy()
  
      for i in range(1, self.max_iter_2 + 1):
          # get perturbation
          perturbation = x_perturbed - x
  
          # get loss gradients of both losses
          gradients_net = self.estimator.loss_gradient(
              x_perturbed, y, batch_mode=True
          )
          (
              gradients_theta,
              loss_theta,
          ) = self._loss_gradient_masking_threshold(
              perturbation, x, masking_threshold, psd_maximum
          )
  
          # check shapes match, otherwise unexpected errors can occur
          assert gradients_net.shape == gradients_theta.shape
  
          # perform gradient descent steps
          x_perturbed = x_perturbed - self.learning_rate_2 * (
              gradients_net + alpha * gradients_theta
          )
  
          if (
              i % self.num_iter_increase_alpha == 0
              or i % self.num_iter_decrease_alpha == 0
          ):
              prediction = self.estimator.predict(
                  x_perturbed, batch_size=batch_size
              )
              for j in range(batch_size):
                  # validate if adversarial target succeeds, i.e. f(x_perturbed)=y
                  if (
                      i % self.num_iter_increase_alpha == 0
                      and prediction[j] == y[j].upper()
                  ):
                      # increase alpha
                      alpha[j] *= self.increase_factor_alpha
                      # save current best imperceptible, adversarial example
                      if loss_theta[j] < loss_theta_previous[j]:
                          x_imperceptible[j] = x_perturbed[j]
                          loss_theta_previous[j] = loss_theta[j]
  
                  # validate if adversarial target fails, i.e. f(x_perturbed)!=y
                  if (
                      i % self.num_iter_decrease_alpha == 0
                      and prediction[j] != y[j].upper()
                  ):
                      # decrease alpha
                      alpha[j] = max(
                          alpha[j] * self.decrease_factor_alpha,
                          alpha_min,
                      )
              logger.info(
                  "Current iteration %s, alpha %s, loss theta %s",
                  i,
                  alpha,
                  loss_theta,
              )
  
          # note: avoids nan values in loss theta, which can occur when loss converges to zero.
          for j in range(batch_size):
              if (
                  loss_theta[j] < self.loss_theta_min
                  and not early_stop[j]
              ):
                  logger.warning(
                      "Batch sample %s reached minimum threshold of %s for theta loss.",
                      j,
                      self.loss_theta_min,
                  )
                  early_stop[j] = True
          if all(early_stop):
              logger.warning(
                  "All batch samples reached minimum threshold for theta loss. Stopping early at iteration %s.",
                  i,
              )
              break
  
      # return perturbed x if no adversarial example found
      for j in range(batch_size):
          if x_imperceptible[j] is None:
              logger.critical(
                  "Adversarial attack stage 2 for x_%s was not successful",
                  j,
              )
              x_imperceptible[j] = x_perturbed[j]
  
      return np.array(x_imperceptible, dtype=dtype)
  
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import TYPE_CHECKING, Optional, Tuple, Union
  import numpy
  import scipy.signal
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin, NeuralNetworkMixin
  from art.estimators.pytorch import PyTorchEstimator
  from art.estimators.speech_recognition.speech_recognizer import SpeechRecognizerMixin
  from art.estimators.tensorflow import TensorFlowV2Estimator
  from art.utils import pad_sequence_input
label_desc: Use image node_id 5 for calling the ImperceptibleASR obj's underlying member method code with example usage: obj._create_imperceptible(x, x_adversarial, y) and returns: np