class_docstr: This class uses a `RunnerMultiGPU` object to train a model on multiple
  GPUs. It mainly overrides the `_create_train_graph` to create a graph
  for adversarial training on multiple GPUs.
class_docstr_tok: ["This","class","uses","a","`","RunnerMultiGPU","`","object","to","train","a","model","on","multiple","GPUs",".","It","mainly","overrides","the","`","_create_train_graph","`","to","create","a","graph","for","adversarial","training","on","multiple","GPUs","."]
code: def _create_train_graph(self):
      super(TrainerMultiGPU, self)._create_train_graph()
      assert "_multigpu" in self.hparams.attack_type_train
  
      hparams = self.hparams
      model = self.model
      sess = self.sess
  
      # Create trainable variables on last gpu.
      # Variables are set to trainable or non-trainable first time they are
      # created. This caused a bug when the last gpu is used both for attack
      # generation and training. With this bug the result of naive training
      # was affected by the length of the unused adversarial generation
      # graph.
      device_name = "/gpu:%d" % (hparams.ngpu - 1)
      model.set_device(device_name)
      with tf.device(device_name):
          x = clone_variable("x", self.g0_inputs["x"])
          model.set_training(training=True)
          preds = model.get_probs(x)
  
      # Generates steps on gpus
      model.set_training(training=False)
      logging.info(
          "Initializing train attack %s" % hparams.attack_type_train
      )
      inputs, outputs = create_adv_by_name(
          model,
          self.g0_inputs["x"],
          hparams.attack_type_train,
          sess,
          y=self.g0_inputs["y"],
          nb_iter=hparams.attack_nb_iter_train,
          dataset=hparams.dataset,
          ngpu=hparams.ngpu,
      )
  
      inputs, outputs = self.clone_g0_inputs_on_ngpus(
          inputs, outputs, self.g0_inputs
      )
  
      # Train step on last gpu
      device_name = "/gpu:%d" % (hparams.ngpu - 1)
      model.set_device(device_name)
      with tf.device(device_name):
          with tf.variable_scope("last"):
              inputs += [OrderedDict()]
              for k, v in outputs[-1].iteritems():
                  v_copy = clone_variable(k, v)
                  inputs[-1][k] = v_copy
              x = inputs[-1]["x"]
              adv_x = inputs[-1]["adv_x"]
              y = inputs[-1]["y"]
              if not hparams.adv_train:
                  model.set_training(training=True)
                  preds = model.get_probs(x)
                  preds_adv = None
              elif not hparams.only_adv_train:
                  model.set_training(training=True)
                  preds = model.get_probs(x)
                  model.set_training(training=True)
                  preds_adv = model.get_probs(adv_x)
              else:
                  preds = None
                  model.set_training(training=True)
                  preds_adv = model.get_probs(adv_x)
              train_fetches = self._build_train_op(preds, y, preds_adv)
  
      outputs += [{"fetches": train_fetches}]
  
      # Create the sync operation
      device_name = "/gpu:%d" % (hparams.ngpu - 1)
      model.set_device(device_name)
      with tf.device(device_name):
          sync_ops = model.create_sync_ops(host_device=device_name)
  
      self.inputs = inputs
      self.outputs = outputs
      self.sync_ops = sync_ops
  
imports: from collections import OrderedDict
  import logging
  import math
  import time
  import os
  import numpy
  import six
  import tensorflow
  from cleverhans.utils_tf import batch_indices
  from cleverhans.utils_mnist import data_mnist
  import utils_cifar
  import utils_svhn
  from utils import preprocess_batch
  from make_model import make_model
  from evaluator import Evaluator
  from evaluator import create_adv_by_name
  from model import clone_variable
label_desc: Use image node_id 3 for calling the TrainerMultiGPU obj's underlying member method code with example usage: obj._create_train_graph() without return types