TensorFlow на нескольких GPU

Недавно я попытался узнать, как использовать 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 и вычислить каждый градиент. Я думаю, что этот процесс сериализован, а не параллелен. Если что-то не так с моим пониманием? Кстати, я также могу использовать итератор для подачи изображения в мою модель, а не для удаления из очереди, верно?

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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
1 946
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это распространенное заблуждение с моделью кодирования 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()): вы просто даете инструкции о том, как должны передаваться данные.

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

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

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

Что ж, спасибо за ваше терпеливое объяснение, и я понял то, о чем вы упомянули выше. Фактически, после построения графика ЦП будет собирать градиенты от каждого графического процессора и усреднять их, чтобы обновить переменные. Кстати, в этом случае автор использует batch_queue_dequeue () для подачи нового пакета для каждого графического процессора. Однако я думаю, что могу просто создать итератор прямо на моем графике, верно?

Sean 19.12.2018 03:06

Другие вопросы по теме