class_docstr: This class implements either the Basic Iterative Method
  (Kurakin et al. 2016) when rand_init is set to 0. or the
  Madry et al. (2017) method when rand_minmax is larger than 0.
  Paper link (Kurakin et al. 2016): https://arxiv.org/pdf/1607.02533.pdf
  Paper link (Madry et al. 2017): https://arxiv.org/pdf/1706.06083.pdf
  
  :param model: cleverhans.model.Model
  :param sess: optional tf.Session
  :param dtypestr: dtype of the data
  :param default_rand_init: whether to use random initialization by default
  :param kwargs: passed through to super constructor
class_docstr_tok: ["This","class","implements","either","the","Basic","Iterative","Method","(","Kurakin","et","al",".","2016",")","when","rand_init","is","set","to","0.","or","the","Madry","et","al",".","(","2017",")","method","when","rand_minmax","is","larger","than","0",".","Paper","link","(","Kurakin","et","al",".","2016",")",":","https",":","\/\/arxiv.org\/pdf\/1607.02533.pdf","Paper","link","(","Madry","et","al",".","2017",")",":","https",":","\/\/arxiv.org\/pdf\/1706.06083.pdf",":","param","model",":","cleverhans.model.Model",":","param","sess",":","optional","tf.Session",":","param","dtypestr",":","dtype","of","the","data",":","param","default_rand_init",":","whether","to","use","random","initialization","by","default",":","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),
              self.ord,
              tf.cast(self.rand_init_eps, x.dtype),
              dtype=x.dtype,
          )
      else:
          eta = tf.zeros(tf.shape(x))
  
      # Clip eta
      eta = clip_eta(eta, self.ord, 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"
  
      fgm_params = {
          "eps": self.eps_iter,
          y_kwarg: y,
          "ord": self.ord,
          "loss_fn": self.loss_fn,
          "clip_min": self.clip_min,
          "clip_max": self.clip_max,
          "clip_grad": self.clip_grad,
      }
      if self.ord == 1:
          raise NotImplementedError(
              "FGM is not a good inner loop step for PGD "
              " when ord=1, because ord=1 FGM changes only "
              " one pixel at a time. Use the SparseL1Descent "
              " attack instead, which allows fine-grained "
              " control over the sparsity of the gradient "
              " updates."
          )
  
      # Use getattr() to avoid errors in eager execution attacks
      FGM = self.FGM_CLASS(
          self.model,
          sess=getattr(self, "sess", None),
          dtypestr=self.dtypestr,
      )
  
      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"""
          adv_x = FGM.generate(adv_x, **fgm_params)
  
          # Clipping perturbation eta to self.ord norm ball
          eta = adv_x - x
          eta = clip_eta(eta, self.ord, self.eps)
          adv_x = x + eta
  
          # Redo the clipping.
          # FGM already did it, but 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.ord == np.inf and self.clip_min is not None:
          # The 1e-6 is needed to compensate for numerical error.
          # Without the 1e-6 this fails when e.g. eps=.2, clip_min=.5,
          # clip_max=.7
          asserts.append(
              utils_tf.assert_less_equal(
                  tf.cast(self.eps, x.dtype),
                  1e-6
                  + tf.cast(self.clip_max, x.dtype)
                  - tf.cast(self.clip_min, x.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/projected_gradient_descent.py
imports: import warnings
  import numpy
  import tensorflow
  from cleverhans.attacks.attack import Attack
  from cleverhans.attacks.fast_gradient_method import FastGradientMethod
  from cleverhans import utils_tf
  from cleverhans.compat import softmax_cross_entropy_with_logits
  from cleverhans.utils_tf import clip_eta, random_lp_vector
label_desc: Use image node_id 2 for calling the ProjectedGradientDescent obj's underlying member method code with example usage: obj.generate(x) and returns: adv_x, tf, unknown,  adv_x