class_docstr: A multi-GPU version of the Projected Gradient Descent Attack
  (Madry et al. 2017).
  Paper link: https://arxiv.org/pdf/1706.06083.pdf
  
  This attack is designed to run on multiple GPUs for generating adversarial
  examples.
  Comparing to data parallelism, using this parallelization we can get
  very close to optimal n times speed up using n GPUs. The current
  implementation gets close to 6x speed up on 8 GPUs.
docstr: Facilitates testing this attack.
code: def generate_np(self, x_val, **kwargs):
      """
      Facilitates testing this attack.
      """
      _, feedable, _feedable_types, hash_key = self.construct_variables(
          kwargs
      )
  
      if hash_key not in self.graphs:
          with tf.variable_scope(None, "attack_%d" % len(self.graphs)):
              # x is a special placeholder we always want to have
              with tf.device("/gpu:0"):
                  x = tf.placeholder(
                      tf.float32, shape=x_val.shape, name="x"
                  )
  
              inputs, outputs = self.generate(x, **kwargs)
  
              from runner import RunnerMultiGPU
  
              runner = RunnerMultiGPU(inputs, outputs, sess=self.sess)
              self.graphs[hash_key] = runner
  
      runner = self.graphs[hash_key]
      feed_dict = {"x": x_val}
      for name in feedable:
          feed_dict[name] = feedable[name]
      fvals = runner.run(feed_dict)
      while not runner.is_finished():
          fvals = runner.run()
  
      return fvals["adv_x"]
  
file_path: cleverhans/cleverhans_v3.1.0/examples/multigpu_advtrain/attacks_multigpu.py
imports: from collections import OrderedDict
  import tensorflow
  from cleverhans.attacks import MadryEtAl
  from cleverhans.utils_tf import clip_eta
  from model import clone_variable
label_desc: Use image node_id 4 for calling the MadryEtAlMultiGPU obj's underlying member method code with example usage: obj.generate_np(x_val) and returns: fvals