class_docstr: HopSkipJumpAttack was originally proposed by Chen, Jordan and Wainwright.
  It is a decision-based attack that requires access to output
  labels of a model alone.
  Paper link: https://arxiv.org/abs/1904.02144
  At a high level, this attack is an iterative attack composed of three
  steps: Binary search to approach the boundary; gradient estimation;
  stepsize search. HopSkipJumpAttack requires fewer model queries than
  Boundary Attack which was based on rejective sampling.
  :param model: cleverhans.model.Model
  :param sess: tf.Session
  :param dtypestr: dtype of the data
  :param kwargs: passed through to super constructor.
  see parse_params for details.
class_docstr_tok: ["HopSkipJumpAttack","was","originally","proposed","by","Chen",",","Jordan","and","Wainwright",".","It","is","a","decision-based","attack","that","requires","access","to","output","labels","of","a","model","alone",".","Paper","link",":","https",":","\/\/arxiv.org\/abs\/1904.02144","At","a","high","level",",","this","attack","is","an","iterative","attack","composed","of","three","steps",":","Binary","search","to","approach","the","boundary",";","gradient","estimation",";","stepsize","search",".","HopSkipJumpAttack","requires","fewer","model","queries","than","Boundary","Attack","which","was","based","on","rejective","sampling",".",":","param","model",":","cleverhans.model.Model",":","param","sess",":","tf.Session",":","param","dtypestr",":","dtype","of","the","data",":","param","kwargs",":","passed","through","to","super","constructor",".","see","parse_params","for","details","."]
docstr: Main algorithm for HopSkipJumpAttack.
  
  Return a tensor that constructs adversarial examples for the given
  input. Generate uses tf.py_func in order to operate over tensors.
  
  :param sample: input image. Without the batchsize dimension.
  :param target_label: integer for targeted attack,
    None for nontargeted attack. Without the batchsize dimension.
  :param target_image: an array with the same size as sample, or None.
    Without the batchsize dimension.
  
  
  Output:
  perturbed image.
docstr_tok: ["Main","algorithm","for","HopSkipJumpAttack",".","Return","a","tensor","that","constructs","adversarial","examples","for","the","given","input",".","Generate","uses","tf.py_func","in","order","to","operate","over","tensors",".",":","param","sample",":","input","image",".","Without","the","batchsize","dimension",".",":","param","target_label",":","integer","for","targeted","attack",",","None","for","nontargeted","attack",".","Without","the","batchsize","dimension",".",":","param","target_image",":","an","array","with","the","same","size","as","sample",",","or","None",".","Without","the","batchsize","dimension",".","Output",":","perturbed","image","."]
code: def _hsja(self, sample, target_label, target_image):
      """
      Main algorithm for HopSkipJumpAttack.
  
      Return a tensor that constructs adversarial examples for the given
      input. Generate uses tf.py_func in order to operate over tensors.
  
      :param sample: input image. Without the batchsize dimension.
      :param target_label: integer for targeted attack,
        None for nontargeted attack. Without the batchsize dimension.
      :param target_image: an array with the same size as sample, or None.
        Without the batchsize dimension.
  
  
      Output:
      perturbed image.
  
      """
  
      # Original label required for untargeted attack.
      if target_label is None:
          original_label = np.argmax(
              self.sess.run(
                  self.logits, feed_dict={self.input_ph: sample[None]}
              )
          )
      else:
          target_label = np.argmax(target_label)
  
      def decision_function(images):
          """
          Decision function output 1 on the desired side of the boundary,
          0 otherwise.
          """
          images = clip_image(images, self.clip_min, self.clip_max)
          prob = []
          for i in range(0, len(images), self.batch_size):
              batch = images[i : i + self.batch_size]
              prob_i = self.sess.run(
                  self.logits, feed_dict={self.input_ph: batch}
              )
              prob.append(prob_i)
          prob = np.concatenate(prob, axis=0)
          if target_label is None:
              return np.argmax(prob, axis=1) != original_label
          else:
              return np.argmax(prob, axis=1) == target_label
  
      # Initialize.
      if target_image is None:
          perturbed = initialize(
              decision_function,
              sample,
              self.shape,
              self.clip_min,
              self.clip_max,
          )
      else:
          perturbed = target_image
  
      # Project the initialization to the boundary.
      perturbed, dist_post_update = binary_search_batch(
          sample,
          np.expand_dims(perturbed, 0),
          decision_function,
          self.shape,
          self.constraint,
          self.theta,
      )
  
      dist = compute_distance(perturbed, sample, self.constraint)
  
      for j in np.arange(self.num_iterations):
          current_iteration = j + 1
  
          # Choose delta.
          delta = select_delta(
              dist_post_update,
              current_iteration,
              self.clip_max,
              self.clip_min,
              self.d,
              self.theta,
              self.constraint,
          )
  
          # Choose number of evaluations.
          num_evals = int(
              min(
                  [
                      self.initial_num_evals * np.sqrt(j + 1),
                      self.max_num_evals,
                  ]
              )
          )
  
          # approximate gradient.
          gradf = approximate_gradient(
              decision_function,
              perturbed,
              num_evals,
              delta,
              self.constraint,
              self.shape,
              self.clip_min,
              self.clip_max,
          )
          if self.constraint == "linf":
              update = np.sign(gradf)
          else:
              update = gradf
  
          # search step size.
          if self.stepsize_search == "geometric_progression":
              # find step size.
              epsilon = geometric_progression_for_stepsize(
                  perturbed,
                  update,
                  dist,
                  decision_function,
                  current_iteration,
              )
  
              # Update the sample.
              perturbed = clip_image(
                  perturbed + epsilon * update,
                  self.clip_min,
                  self.clip_max,
              )
  
              # Binary search to return to the boundary.
              perturbed, dist_post_update = binary_search_batch(
                  sample,
                  perturbed[None],
                  decision_function,
                  self.shape,
                  self.constraint,
                  self.theta,
              )
  
          elif self.stepsize_search == "grid_search":
              # Grid search for stepsize.
              epsilons = (
                  np.logspace(-4, 0, num=20, endpoint=True) * dist
              )
              epsilons_shape = [20] + len(self.shape) * [1]
              perturbeds = (
                  perturbed + epsilons.reshape(epsilons_shape) * update
              )
              perturbeds = clip_image(
                  perturbeds, self.clip_min, self.clip_max
              )
              idx_perturbed = decision_function(perturbeds)
  
              if np.sum(idx_perturbed) > 0:
                  # Select the perturbation that yields the minimum distance # after binary search.
                  perturbed, dist_post_update = binary_search_batch(
                      sample,
                      perturbeds[idx_perturbed],
                      decision_function,
                      self.shape,
                      self.constraint,
                      self.theta,
                  )
  
          # compute new distance.
          dist = compute_distance(perturbed, sample, self.constraint)
          if self.verbose:
              print(
                  "iteration: {:d}, {:s} distance {:.4E}".format(
                      j + 1, self.constraint, dist
                  )
              )
  
      perturbed = np.expand_dims(perturbed, 0)
      return perturbed
  
imports: import logging
  import numpy
  import tensorflow
  from warnings import warn
  from cleverhans.attacks import Attack
  from cleverhans.model import CallableModelWrapper, Model, wrapper_warning_logits
  from cleverhans import utils, utils_tf
label_desc: Use image node_id 5 for calling the HopSkipJumpAttack obj's underlying member method code with example usage: obj._hsja(sample, target_label, target_image) and returns: perturbed, unknown, unknown