class_docstr: This class implements a variant of Projected Gradient Descent for the l1-norm
  (Tramer and Boneh 2019). The l1-norm case is more tricky than the l-inf and l2
  cases covered by the ProjectedGradientDescent class, because the steepest
  descent direction for the l1-norm is too sparse (it updates a single
  coordinate in the adversarial perturbation in each step). This attack has an
  additional parameter that controls the sparsity of the update step. For
  moderately sparse update steps, the attack vastly outperforms Projected
  Steepest Descent and is competitive with other attacks targeted at the l1-norm
  such as the ElasticNetMethod attack (which is much more computationally
  expensive).
  Paper link (Tramer and Boneh 2019): https://arxiv.org/pdf/1904.13000.pdf
  
  :param model: cleverhans.model.Model
  :param sess: optional tf.Session
  :param dtypestr: dtype of the data
  :param kwargs: passed through to super constructor
class_docstr_tok: ["This","class","implements","a","variant","of","Projected","Gradient","Descent","for","the","l1-norm","(","Tramer","and","Boneh","2019",")",".","The","l1-norm","case","is","more","tricky","than","the","l-inf","and","l2","cases","covered","by","the","ProjectedGradientDescent","class",",","because","the","steepest","descent","direction","for","the","l1-norm","is","too","sparse","(","it","updates","a","single","coordinate","in","the","adversarial","perturbation","in","each","step",")",".","This","attack","has","an","additional","parameter","that","controls","the","sparsity","of","the","update","step",".","For","moderately","sparse","update","steps",",","the","attack","vastly","outperforms","Projected","Steepest","Descent","and","is","competitive","with","other","attacks","targeted","at","the","l1-norm","such","as","the","ElasticNetMethod","attack","(","which","is","much","more","computationally","expensive",")",".","Paper","link","(","Tramer","and","Boneh","2019",")",":","https",":","\/\/arxiv.org\/pdf\/1904.13000.pdf",":","param","model",":","cleverhans.model.Model",":","param","sess",":","optional","tf.Session",":","param","dtypestr",":","dtype","of","the","data",":","param","kwargs",":","passed","through","to","super","constructor"]
docstr: Generate symbolic graph for adversarial examples and return.
  
  :param x: The model's symbolic inputs.
  :param kwargs: See `parse_params`
docstr_tok: ["Generate","symbolic","graph","for","adversarial","examples","and","return",".",":","param","x",":","The","model","'s","symbolic","inputs",".",":","param","kwargs",":","See","`","parse_params","`"]
code: def generate(self, x, **kwargs):
      """
      Generate symbolic graph for adversarial examples and return.
  
      :param x: The model's symbolic inputs.
      :param kwargs: See `parse_params`
      """
      # Parse and save attack-specific parameters
      assert self.parse_params(**kwargs)
  
      asserts = []
  
      # If a data range was specified, check that the input was in that range
      if self.clip_min is not None:
          asserts.append(
              utils_tf.assert_greater_equal(
                  x, tf.cast(self.clip_min, x.dtype)
              )
          )
  
      if self.clip_max is not None:
          asserts.append(
              utils_tf.assert_less_equal(
                  x, tf.cast(self.clip_max, x.dtype)
              )
          )
  
      # Initialize loop variables
      if self.rand_init:
          eta = random_lp_vector(
              tf.shape(x),
              ord=1,
              eps=tf.cast(self.eps, x.dtype),
              dtype=x.dtype,
          )
      else:
          eta = tf.zeros(tf.shape(x))
  
      # Clip eta
      eta = clip_eta(eta, ord=1, eps=self.eps)
      adv_x = x + eta
      if self.clip_min is not None or self.clip_max is not None:
          adv_x = utils_tf.clip_by_value(
              adv_x, self.clip_min, self.clip_max
          )
  
      if self.y_target is not None:
          y = self.y_target
          targeted = True
      elif self.y is not None:
          y = self.y
          targeted = False
      else:
          model_preds = self.model.get_probs(x)
          preds_max = tf.reduce_max(model_preds, 1, keepdims=True)
          y = tf.to_float(tf.equal(model_preds, preds_max))
          y = tf.stop_gradient(y)
          targeted = False
          del model_preds
  
      y_kwarg = "y_target" if targeted else "y"
  
      def cond(i, _):
          """Iterate until requested number of iterations is completed"""
          return tf.less(i, self.nb_iter)
  
      def body(i, adv_x):
          """Do a projected gradient step"""
  
          labels, _ = self.get_or_guess_labels(adv_x, {y_kwarg: y})
          logits = self.model.get_logits(adv_x)
  
          adv_x = sparse_l1_descent(
              adv_x,
              logits,
              y=labels,
              eps=self.eps_iter,
              q=self.grad_sparsity,
              clip_min=self.clip_min,
              clip_max=self.clip_max,
              clip_grad=self.clip_grad,
              targeted=(self.y_target is not None),
              sanity_checks=self.sanity_checks,
          )
  
          # Clipping perturbation eta to the l1-ball
          eta = adv_x - x
          eta = clip_eta(eta, ord=1, eps=self.eps)
          adv_x = x + eta
  
          # Redo the clipping.
          # Subtracting and re-adding eta can add some small numerical error.
          if self.clip_min is not None or self.clip_max is not None:
              adv_x = utils_tf.clip_by_value(
                  adv_x, self.clip_min, self.clip_max
              )
  
          return i + 1, adv_x
  
      _, adv_x = tf.while_loop(
          cond,
          body,
          (tf.zeros([]), adv_x),
          back_prop=True,
          maximum_iterations=self.nb_iter,
      )
  
      # Asserts run only on CPU.
      # When multi-GPU eval code tries to force all PGD ops onto GPU, this
      # can cause an error.
      common_dtype = tf.float32
      asserts.append(
          utils_tf.assert_less_equal(
              tf.cast(self.eps_iter, dtype=common_dtype),
              tf.cast(self.eps, dtype=common_dtype),
          )
      )
  
      if self.sanity_checks:
          with tf.control_dependencies(asserts):
              adv_x = tf.identity(adv_x)
  
      return adv_x
  
file_path: cleverhans/cleverhans_v3.1.0/cleverhans/attacks/sparse_l1_descent.py
imports: import warnings
  from distutils.version import LooseVersion
  import tensorflow
  from cleverhans.attacks.attack import Attack
  from cleverhans import utils_tf
  from cleverhans.utils_tf import clip_eta, random_lp_vector
  from cleverhans.compat import reduce_max, reduce_sum, softmax_cross_entropy_with_logits
label_desc: Use image node_id 2 for calling the SparseL1Descent obj's underlying member method code with example usage: obj.generate(x) and returns: adv_x, tf, unknown,  adv_x