Влияние положения tf.GradientTape () на время обучения модели

Я пытаюсь обновлять вес каждую эпоху, но обрабатываю данные партиями. Проблема в том, что для нормализации потерь мне нужно записать переменные TensorFlow вне цикла обучения (чтобы их можно было отслеживать и нормализовать). Но когда я это делаю, время на тренировки Огромное.

Я думаю, он накапливает переменные из всех партий в график и вычисляет градиенты в конце.

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

# Very Slow

loss_value = 0
batches = 0

with tf.GradientTape() as tape:
    for inputs, min_seq in zip(dataset, minutes_sequence):
        temp_loss_value = my_loss_function(inputs, min_seq)
        batches +=1
        loss_value = loss_value + temp_loss_value

# The following line takes huge time.
grads = tape.gradient(loss_value, model.trainable_variables)

# Very Fast

loss_value = 0
batches = 0

for inputs, min_seq in zip(dataset, minutes_sequence):
    with tf.GradientTape() as tape:
        temp_loss_value = my_loss_function(inputs, min_seq)
        batches +=1
        loss_value = loss_value + temp_loss_value

# If I do the following line, the graph will break because this are out of tape's scope.
    loss_value = loss_value / batches

# the following line takes huge time
grads = tape.gradient(loss_value, model.trainable_variables)

Когда я объявляю tf.GradientTape () внутри цикла for, он выполняется очень быстро, а снаружи - медленно.

P.S. - Это для нестандартной потери, а архитектура содержит только один скрытый слой размером 10.

Я хочу знать, в чем разница между положением tf.GradientTape () и тем, как его следует использовать для обновления весов для каждой эпохи в пакетном наборе данных.


person gauravtolani    schedule 26.08.2019    source источник


Ответы (1)


Переменная ленты используется в первую очередь для просмотра обучаемых тензорных переменных (записи предыдущих и изменяющихся значений переменных), чтобы мы могли вычислить градиент для эпохи обучения в соответствии с функцией потерь. Это реализация конструкции диспетчера контекста Python, используемой здесь для записи состояния переменных. Отличный ресурс по менеджерам контекста Python находится здесь. Итак, если внутри цикла он будет записывать переменные (веса) для этого прямого прохода, чтобы мы могли вычислить градиент для всех этих переменных за один выстрел (вместо передачи градиента на основе стека, как в наивной реализации без библиотеки, такой как тензорный поток) . Если он находится вне цикла, он будет записывать состояния для всех эпох, и в соответствии с исходным кодом Tensorflow он также сбрасывается при использовании TF2.0, в отличие от TF1.x, где разработчик модели должен был позаботиться о сбросе. В вашем примере у вас нет набора писателей, но если какой-либо писатель установлен, он тоже это сделает. Таким образом, для приведенного выше кода он будет продолжать записывать (метод Graph.add_to_collection используется внутри) все веса, и по мере увеличения эпох вы должны увидеть замедление. Скорость замедления будет пропорциональна размеру сети (обучаемые переменные) и текущему номеру эпохи.

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

Я только что нашел еще один хороший ресурс на gradienttape.

person Sunny    schedule 20.09.2019
comment
в значительной степени проясняет мои сомнения. Спасибо большое. - person gauravtolani; 21.09.2019