code: def jacobian_augmentation(
      sess,
      x,
      X_sub_prev,
      Y_sub,
      grads,
      lmbda,
      aug_batch_size=512,
      feed=None,
  ):
      """
      Augment an adversary's substitute training set using the Jacobian
      of a substitute model to generate new synthetic inputs.
      See https://arxiv.org/abs/1602.02697 for more details.
      See cleverhans_tutorials/mnist_blackbox.py for example use case
      :param sess: TF session in which the substitute model is defined
      :param x: input TF placeholder for the substitute model
      :param X_sub_prev: substitute training data available to the adversary
                         at the previous iteration
      :param Y_sub: substitute training labels available to the adversary
                    at the previous iteration
      :param grads: Jacobian symbolic graph for the substitute
                    (should be generated using utils_tf.jacobian_graph)
      :return: augmented substitute data (will need to be labeled by oracle)
      """
      assert len(x.get_shape()) == len(np.shape(X_sub_prev))
      assert len(grads) >= np.max(Y_sub) + 1
      assert len(X_sub_prev) == len(Y_sub)
  
      aug_batch_size = min(aug_batch_size, X_sub_prev.shape[0])
  
      # Prepare input_shape (outside loop) for feeding dictionary below
      input_shape = list(x.get_shape())
      input_shape[0] = 1
  
      # Create new numpy array for adversary training data
      # with twice as many components on the first dimension.
      X_sub = np.vstack([X_sub_prev, X_sub_prev])
      num_samples = X_sub_prev.shape[0]
  
      # Creating and processing as batch
      for p_idxs in range(0, num_samples, aug_batch_size):
          X_batch = X_sub_prev[p_idxs : p_idxs + aug_batch_size, ...]
          feed_dict = {x: X_batch}
          if feed is not None:
              feed_dict.update(feed)
  
          # Compute sign matrix
          grad_val = sess.run([tf.sign(grads)], feed_dict=feed_dict)[0]
  
          # Create new synthetic point in adversary substitute training set
          for indx, ind in zip(
              range(p_idxs, p_idxs + X_batch.shape[0]),
              range(X_batch.shape[0]),
          ):
              X_sub[num_samples + indx] = (
                  X_batch[ind] + lmbda * grad_val[Y_sub[indx], ind, ...]
              )
  
      # Return augmented training data (needs to be labeled afterwards)
      return X_sub
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  import logging
  import math
  import os
  import time
  import warnings
  import numpy
  import six
  from six.moves import xrange
  import tensorflow
  from cleverhans.compat import device_lib
  from cleverhans.compat import reduce_sum, reduce_mean
  from cleverhans.compat import reduce_max
  from cleverhans.compat import softmax_cross_entropy_with_logits
  from cleverhans.utils import batch_indices, _ArgsWrapper, create_logger
label_desc: Use image node_id 27 for calling a global function with example usage: jacobian_augmentation(sess, x, X_sub_prev, Y_sub, grads, lmbda, aug_batch_size, feed) and returns: X_sub