class_docstr: Data-parallel training in 'ParameterServer' mode.
  It builds one tower on each GPU with
  shared variable scope. It synchronizes the gradients computed
  from each tower, averages them and applies to the shared variables.
  
  It is an equivalent of ``--variable_update=parameter_server`` in
  `tensorflow/benchmarks <https://github.com/tensorflow/benchmarks>`_.
class_docstr_tok: ["Data-parallel","training","in","'ParameterServer","'","mode",".","It","builds","one","tower","on","each","GPU","with","shared","variable","scope",".","It","synchronizes","the","gradients","computed","from","each","tower",",","averages","them","and","applies","to","the","shared","variables",".","It","is","an","equivalent","of","``","--","variable_update=parameter_server","``","in","`","tensorflow\/benchmarks","<","https",":","\/\/github.com\/tensorflow\/benchmarks",">","`","_","."]
docstr: Reduce the gradients, apply them with the optimizer,
  and set self.grads to a list of (g, v), containing the averaged gradients.
  
  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: ["Reduce","the","gradients",",","apply","them","with","the","optimizer",",","and","set","self.grads","to","a","list","of","(","g",",","v",")",",","containing","the","averaged","gradients",".","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):
      """
      Reduce the gradients, apply them with the optimizer,
      and set self.grads to a list of (g, v), containing the averaged gradients.
  
      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)
  
      # debug tower performance:
      # ops = [k[0] for k in grad_list[1]] + [k[0] for k in grad_list[0]]
      # self.train_op = tf.group(*ops)
      # return
  
      self.grads = aggregate_grads_colocate(grad_list)
      # debug tower performance:
      # grads = grad_list[0]
  
      opt = get_opt_fn()
      if self.ps_device == "cpu":
          with tf.device("/cpu:0"):
              train_op = opt.apply_gradients(
                  self.grads, name="train_op"
              )
      else:
          train_op = opt.apply_gradients(self.grads, name="train_op")
      return 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 SyncMultiGPUParameterServerBuilder obj's underlying member method code with example usage: obj.build(grad_list, get_opt_fn) and returns: train_op