Эффективное вычисление теневого потока на пиксельный градиент

Я переопределяю статью " Обучение сопоставлению изображений путем простого просмотра видео с использованием тензорного потока", и у меня возникают серьезные проблемы с производительностью при получении градиентов из сети. Чтобы быстро повторить то, что они делают в статье, у них есть обученная сеть, они делают 1 прямую подпорку, чтобы получить интерполированное изображение, и затем они делают w*h/stepde^2 backprops, чтобы получить градиенты вывода по входу для каждого пиксели. Из-за большого количества обратных распространений это должно быть сделано достаточно эффективно, чтобы получить градиенты за разумное количество времени (в документе 8 минут 150 мс для каждого обратного времени 128*384/16 пикселей (шаг 4 на обе строки и столбцы)). Так как в тензорном потоке множественные backprops не могут быть объединены из-за градиентной агрегации (см., Например, это обсуждение), мне нужно сделать что-то вроде:

for i in range(0, h, stride): 
    for j in range(0, w, stride):
        grad_output[0,i,j,:] = 1 #select current pixel
        grad.append(tf.gradients(predictions, images, grad_output))
        grad_output[grad_output != 0] = 0

получить символьные градиенты для каждого пикселя, где предсказания - это выходной тензор сети, а изображения - это входные данные, объявленные как константа в gpu:

with tf.device('/gpu:0'):
    images = tf.constant(inp, dtype=tf.float32)

где inp - фактический массив с данными.

Каждый звонок tf.gradients Одно это занимает около 0,35 мс, что уже слишком много по сравнению с тем, что авторы сообщают в статье. Но наибольшее количество времени уходит на оценку символического градиента, что-то вроде:

for i in range(0, len(grad)):
    res = sess.run(grad[i])

Это занимает около 1,5 секунд, очень медленно. Теперь последующие звонки sess.run(grad[i]) (с тем же индексом i) действительно быстрые, около 100 мс, при запуске смены цикла for i на каждой итерации получается примерно 1,5 секунды на итерацию. Увидев такое поведение, я предполагаю, что при переносе содержимого в GPU возникают большие накладные расходы, возможно ли это? Если это так, как я могу избежать этого? Я уже перенесла images тензор к константе GPU вместо использования заполнителя и полагаясь на feed_dict в sess.run, но это никак не повлияло на производительность. Есть идеи, чтобы ускорить оценку символических градиентов? Я чувствую, что упускаю что-то простое здесь, поскольку 1 backprop, занимающий 1,5 секунды, действительно далек от любого реалистичного сценария (например, тренировка сети смогла обработать около 100 выборок в секунду, так что это не проблема архитектуры, я думаю...)

Спасибо!

1 ответ

Вот мои идеи:

  1. Попробуйте визуализировать график обучения, например, через тензорную доску и SummaryWriter. tf.gradients в цикле выглядит подозрительно - убедитесь, что вы не создаете данный тензор больше раз, чем необходимо.
  2. Если это не меняет семантику, попробуйте рассчитать все градиенты одновременно:

    res = sess.run (град)

Если предположить, grad это список тензоров. дела sess.run в цикле пересчитает любые общие части grad[i] а также grad[j] многократно.

Надеюсь, поможет!

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