class_docstr: Data-parallel training with async update.
  It builds one tower on each GPU with shared variable scope.
  Every tower computes the gradients and independently applies them to the
  variables, without synchronizing and averaging across towers.
class_docstr_tok: ["Data-parallel","training","with","async","update",".","It","builds","one","tower","on","each","GPU","with","shared","variable","scope",".","Every","tower","computes","the","gradients","and","independently","applies","them","to","the","variables",",","without","synchronizing","and","averaging","across","towers","."]
docstr: Args:
      grad_list ([[(grad, var), ...], ...]): #GPU lists to be reduced. Each is the gradients computed on each GPU.
      get_opt_fn (-> tf.train.Optimizer): callable which returns an optimizer
  
  Returns:
      tf.Operation: the training op
docstr_tok: ["Args",":","grad_list","(","[","[","(","grad",",","var",")",",","...","]",",","...","]",")",":","#","GPU","lists","to","be","reduced",".","Each","is","the","gradients","computed","on","each","GPU",".","get_opt_fn","(","-",">","tf.train.Optimizer",")",":","callable","which","returns","an","optimizer","Returns",":","tf.Operation",":","the","training","op"]
code: def build(self, grad_list, get_opt_fn):
      """
      Args:
          grad_list ([[(grad, var), ...], ...]): #GPU lists to be reduced. Each is the gradients computed on each GPU.
          get_opt_fn (-> tf.train.Optimizer): callable which returns an optimizer
  
      Returns:
          tf.Operation: the training op
      """
      assert len(grad_list) == len(self.towers)
      DataParallelBuilder._check_grad_list(grad_list)
  
      if self._scale_gradient and len(self.towers) > 1:
          # pretend to average the grads, in order to make async and
          # sync have consistent effective learning rate
          gradproc = ScaleGradient(
              (".*", 1.0 / len(self.towers)), verbose=False
          )
          grad_list = [gradproc.process(gv) for gv in grad_list]
      # Ngpu x Nvar x 2
  
      train_ops = []
      opt = get_opt_fn()
      with tf.name_scope("async_apply_gradients"):
          for i, grad_and_vars in enumerate(zip(*grad_list)):
              # Ngpu x 2
              v = grad_and_vars[0][1]
              with tf.device(v.device):
                  # will call apply_gradients (therefore gradproc) multiple times
                  train_ops.append(
                      opt.apply_gradients(
                          grad_and_vars, name="apply_grad_{}".format(i)
                      )
                  )
      return tf.group(*train_ops, name="train_op")
  
imports: import copy
  import pprint
  import re
  from abc import ABCMeta, abstractmethod
  from contextlib import contextmanager
  import six
  import tensorflow
  from ..compat import tfv1
  from ..tfutils.common import get_tf_version_tuple
  from ..tfutils.gradproc import ScaleGradient
  from ..tfutils.tower import TrainTowerContext
  from ..utils import logger
  from ..utils.develop import HIDE_DOC
  from .utils import GradientPacker, LeastLoadedDeviceSetter, aggregate_grads_colocate, allreduce_grads_naive, allreduce_grads, allreduce_grads_hierarchical, merge_grad_list, override_to_local_variable, split_grad_list
label_desc: Use image node_id 3 for calling the AsyncMultiGPUBuilder obj's underlying member method code with example usage: obj.build(grad_list, get_opt_fn) and returns: tf