TensorFlow на нескольких графических процессорах - PullRequest
0 голосов
/ 18 декабря 2018

В последнее время я пытаюсь научиться использовать Tensorflow на нескольких графических процессорах, прочитав официальный учебник.Однако есть кое-что, что меня смущает.Следующий код является частью официального учебника, который рассчитывает потери на одном графическом процессоре.

def tower_loss(scope, images, labels):

  # Build inference Graph.
  logits = cifar10.inference(images)

  # Build the portion of the Graph calculating the losses. Note that we will
  # assemble the total_loss using a custom function below.
  _ = cifar10.loss(logits, labels)

  # Assemble all of the losses for the current tower only.
  losses = tf.get_collection('losses', scope)

  # Calculate the total loss for the current tower.
  total_loss = tf.add_n(losses, name='total_loss')

  # Attach a scalar summary to all individual losses and the total loss; do the
  # same for the averaged version of the losses.
  for l in losses + [total_loss]:
    # Remove 'tower_[0-9]/' from the name in case this is a multi-GPU training
    # session. This helps the clarity of presentation on tensorboard.
    loss_name = re.sub('%s_[0-9]*/' % cifar10.TOWER_NAME, '', l.op.name)
    tf.summary.scalar(loss_name, l)

  return total_loss

Процесс обучения заключается в следующем.

def train():
with tf.device('/cpu:0'):
    # Create a variable to count the number of train() calls. This equals the
    # number of batches processed * FLAGS.num_gpus.
global_step = tf.get_variable(
    'global_step', [],
    initializer=tf.constant_initializer(0), trainable=False)

# Calculate the learning rate schedule.
num_batches_per_epoch = (cifar10.NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN /
                         FLAGS.batch_size / FLAGS.num_gpus)
decay_steps = int(num_batches_per_epoch * cifar10.NUM_EPOCHS_PER_DECAY)

# Decay the learning rate exponentially based on the number of steps.
lr = tf.train.exponential_decay(cifar10.INITIAL_LEARNING_RATE,
                                global_step,
                                decay_steps,
                                cifar10.LEARNING_RATE_DECAY_FACTOR,
                                staircase=True)

# Create an optimizer that performs gradient descent.
opt = tf.train.GradientDescentOptimizer(lr)

# Get images and labels for CIFAR-10.
images, labels = cifar10.distorted_inputs()
batch_queue = tf.contrib.slim.prefetch_queue.prefetch_queue(
      [images, labels], capacity=2 * FLAGS.num_gpus)
# Calculate the gradients for each model tower.
tower_grads = []
with tf.variable_scope(tf.get_variable_scope()):
  for i in xrange(FLAGS.num_gpus):
    with tf.device('/gpu:%d' % i):
      with tf.name_scope('%s_%d' % (cifar10.TOWER_NAME, i)) as scope:
        # Dequeues one batch for the GPU
        image_batch, label_batch = batch_queue.dequeue()
        # Calculate the loss for one tower of the CIFAR model. This function
        # constructs the entire CIFAR model but shares the variables across
        # all towers.
        loss = tower_loss(scope, image_batch, label_batch)

        # Reuse variables for the next tower.
        tf.get_variable_scope().reuse_variables()

        # Retain the summaries from the final tower.
        summaries = tf.get_collection(tf.GraphKeys.SUMMARIES, scope)

Тем не менее, я запутался в цикле for относительно 'for i in xrange (FLAGS.num_gpus)'.Кажется, мне нужно получить новое пакетное изображение из batch_queue и рассчитать каждый градиент.Я думаю, что этот процесс сериализуется, а не параллельно.Если что-то не так с моим собственным пониманием?Кстати, я также могу использовать итератор для передачи изображения в мою модель, а не в правую очередь?

Спасибо всем!

1 Ответ

0 голосов
/ 18 декабря 2018

Это распространенное заблуждение в модели кодирования Tensorflow.Здесь вы видите конструкцию графа вычислений , НЕ фактическое выполнение.

Блок:

for i in xrange(FLAGS.num_gpus):
    with tf.device('/gpu:%d' % i):
      with tf.name_scope('%s_%d' % (cifar10.TOWER_NAME, i)) as scope:
        # Dequeues one batch for the GPU
        image_batch, label_batch = batch_queue.dequeue()
        # Calculate the loss for one tower of the CIFAR model. This function
        # constructs the entire CIFAR model but shares the variables across
        # all towers.
        loss = tower_loss(scope, image_batch, label_batch)

переводится в:

For each GPU device (`for i in range..` & `with device...`):
    - build operations needed to dequeue a batch
    - build operations needed to run the batch through the network and compute the loss

Обратите внимание, как с помощью tf.get_variable_scope().reuse_variables() вы сообщаете графику, что переменные, используемые для графического графического процессора, должны быть общими для всех (т. Е. Все графики на нескольких устройствах «повторно используют» одни и те же переменные).

Ничто из этого на самом деле не запускает сеть один раз (обратите внимание, что sess.run() нет): вы просто даете инструкции о том, как должны поступать данные.

Затем, когда вы начнете реальное обучение (я полагаю,вы пропустили этот фрагмент кода при копировании здесь) каждый графический процессор будет извлекать свой пакет и генерировать потери для каждой башни.Я предполагаю, что эти потери усредняются где-то в последующем коде, и среднее значение - это потери, передаваемые оптимизатору.

Вплоть до того момента, пока потери в башне не будут усреднены вместе, все не зависит от других устройств, поэтомуПакет и вычисление потерь может быть сделано параллельно.Затем обновление градиентов и параметров выполняется только один раз, переменные обновляются, и цикл повторяется.

Итак, чтобы ответить на ваш вопрос, no , вычисление потерь для каждой партии не сериализуется, нопоскольку это синхронное распределенное вычисление, вам нужно собрать все потери со всех графических процессоров, прежде чем продолжить работу по вычислению градиентов и обновлению параметров, поэтому у вас все еще есть некоторая часть графика, которая не может быть независимой.

...