TensorFlow 2-GPU медленнее, чем один GPU

У меня два gpu (TitanX (Pascal) и GTX 1080). Я пытаюсь запустить однопоточное вычисление графа. Граф представляет собой две отдельные цепочки умножения матриц (каждая назначена соответствующему графическому процессору).

Вот код, который я использую:

импортировать тензорный поток как tf импортировать numpy как np импортировать случайное время импорта

from tensorflow.python.ops import init_ops
from tensorflow.python.client import timeline


def test():
    n = 5000

    with tf.Graph().as_default():
        A1 = tf.placeholder(tf.float32, shape=[n, n], name='A')
        A2 = tf.placeholder(tf.float32, shape=[n, n], name='A')
        with tf.device('/gpu:0'):
            B1 = A1
            for l in xrange(10):
                B1 = tf.matmul(B1, A1)

        with tf.device('/gpu:1'):
            B2 = A2
            for l in xrange(10):
                B2 = tf.matmul(B2, A2)
            C = tf.matmul(B1, B2)

        run_metadata = tf.RunMetadata()
        with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as sess:
            start = time.time()
            logging.info('started')
            A1_ = np.random.rand(n, n)
            A2_ = np.random.rand(n, n)
            sess.run([C],
                     feed_dict={A1: A1_, A2: A2_},
                     options=tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE),
                     run_metadata=run_metadata)
            logging.info('writing trace')
            trace = timeline.Timeline(step_stats=run_metadata.step_stats)
            trace_file = open('timeline.ctf.json', 'w')
            trace_file.write(trace.generate_chrome_trace_format())
            logging.info('trace written')
            end = time.time()
            logging.info('computed')
            logging.info(end - start)


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
    test()
  • Это займет 20,4 секунды, чтобы закончить.
  • Для завершения требуется 14 секунд, если я установлю все операции на gpu0 (TitanX).
  • Для завершения потребуется 19,8 секунды, если я установлю все операции на gpu1 (GTX 1080).

Я вижу, что тензор потока нашел оба gpus и правильно настроил все устройства. Почему нет ускорения использования двух графических процессоров вместо одного? Может быть проблема в том, что у gpus разные модели (AFAIK cuda это позволяет)?

Благодарю.

РЕДАКТИРОВАТЬ Я обновил код, чтобы использовать разные исходные матрицы для обеих цепочек, так как в противном случае тензор потока, кажется, делает некоторые оптимизации.

Вот ссылка на json-файл профиля временной шкалы: https://api.myjson.com/bins/23csi

Скриншот

Этот график вызывает больше вопросов, чем ответов:

  1. Почему pid 7 (gpu0) имеет две строки исполнения?
  2. Какие длинные матмулы в пиде 3 и 5? (input0 "_recv_A_0/_3", input1 "_recv_A_0/_3", имя "MatMul", оп "MatMul")
  3. Кажется, что каждая операция выполняется на gpu0, кроме pid 5.
  4. Есть много маленьких операций MatMul (не видно из скриншота) сразу после длинных операций MatMuls из pid 3 и pid 5. Что это?

2 ответа

Решение

При первом запуске ядра на графическом процессоре существует значительная задержка, возможно, вызванная компиляцией PTXAS. Эта задержка может составлять порядка секунд и накапливается, когда вы используете более 1 графического процессора, поэтому в вашем случае запуск выполняется медленнее, поскольку во времени преобладает дополнительный "начальный запуск ядра". Один из способов измерения чистого времени вычислений - это "предварительный прогрев", выполняя каждую операцию cuda, по крайней мере, один раз на каждом графическом процессоре. Я наблюдал такую ​​же медлительность, запустив ваш тест на двух картах TitanX, но эта задержка исчезла, когда я "прогрел" ядра.

Вот перед предварительным прогревом: введите описание изображения здесь

Вот после предварительного прогрева: введите описание изображения здесь Ниже приведен код, модифицированный для предварительного прогрева, а также для удаления любых передач TensorFlow<->Python.

import tensorflow as tf

from tensorflow.python.ops import init_ops
from tensorflow.python.client import timeline
import logging, time
import numpy as np

def test():
    n = 5000

    with tf.device('/gpu:0'):
        A1 = tf.Variable(tf.ones_initializer(shape=[n, n]), name='A1')
        B1 = A1
        for l in xrange(10):
            B1 = tf.matmul(A1, B1, name="chain1")

    with tf.device('/gpu:1'):
        A2 = tf.Variable(tf.ones_initializer(shape=[n, n]), name='A2')
        B2 = A2
        for l in xrange(10):
            B2 = tf.matmul(A2, B2, name="chain2")
        C = tf.matmul(B1, B2)

    run_metadata = tf.RunMetadata()
    start = time.time()
    logging.info('started')
    sess = tf.InteractiveSession(config=tf.ConfigProto(allow_soft_placement=False, log_device_placement=True))
    sess.run(tf.initialize_all_variables())
    # do warm-run
    sess.run([C.op],
             options=tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE),
             run_metadata=run_metadata)
    run_metadata = tf.RunMetadata()
    sess.run([C.op],
             options=tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE),
             run_metadata=run_metadata)
    logging.info('writing trace')
    trace = timeline.Timeline(step_stats=run_metadata.step_stats)
    trace_file = open('timeline.ctf.json', 'w')
    trace_file.write(trace.generate_chrome_trace_format(show_memory=True))
    logging.info('trace written')
    end = time.time()
    logging.info('computed')
    logging.info(end - start)


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
    test()

Разве это не потому, что вам нужно передавать данные между графическими процессорами при вычислении C? Вы можете попробовать положить C на процессоре?

with tf.device('/cpu:0'):
  C = tf.matmul(B1, B2)
Другие вопросы по тегам