Эффективное вычисление теневого потока на пиксельный градиент
Я переопределяю статью " Обучение сопоставлению изображений путем простого просмотра видео с использованием тензорного потока", и у меня возникают серьезные проблемы с производительностью при получении градиентов из сети. Чтобы быстро повторить то, что они делают в статье, у них есть обученная сеть, они делают 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 ответ
Вот мои идеи:
- Попробуйте визуализировать график обучения, например, через тензорную доску и SummaryWriter.
tf.gradients
в цикле выглядит подозрительно - убедитесь, что вы не создаете данный тензор больше раз, чем необходимо. Если это не меняет семантику, попробуйте рассчитать все градиенты одновременно:
res = sess.run (град)
Если предположить, grad
это список тензоров. дела sess.run
в цикле пересчитает любые общие части grad[i]
а также grad[j]
многократно.
Надеюсь, поможет!