Как применить градиентное отсечение в TensorFlow?


учитывая пример кода.

Я хотел бы знать, как применить градиентное обрезание в этой сети на RNN, где есть возможность взрыва градиентов.

tf.clip_by_value(t, clip_value_min, clip_value_max, name=None)

Это пример, который может быть использован, но где я его представлю ? В def of RNN

    lstm_cell = rnn_cell.BasicLSTMCell(n_hidden, forget_bias=1.0)
    # Split data because rnn cell needs a list of inputs for the RNN inner loop
    _X = tf.split(0, n_steps, _X) # n_steps
tf.clip_by_value(_X, -1, 1, name=None)

но это не имеет смысла, так как тензор _X-это вход, а не град, что обрезается?

должен ли я определить свой собственный Оптимизатор для этого или есть более простой вариант?

6 59

6 ответов:

градиент отсечения должно произойти после вычисления градиентов, но перед их применением для обновления параметров модели. В вашем примере, обе эти вещи обрабатываются AdamOptimizer.minimize() метод.

чтобы обрезать ваши градиенты, вам нужно будет явно вычислить, обрезать и применить их, как описано в этот раздел в документации API TensorFlow. В частности, вам нужно будет заменить вызов на minimize() метод с чем-то вроде следующее:

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
gvs = optimizer.compute_gradients(cost)
capped_gvs = [(tf.clip_by_value(grad, -1., 1.), var) for grad, var in gvs]
train_op = optimizer.apply_gradients(capped_gvs)

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

optimizer = tf.train.AdamOptimizer(1e-3)
gradients, variables = zip(*optimizer.compute_gradients(loss))
gradients, _ = tf.clip_by_global_norm(gradients, 5.0)
optimize = optimizer.apply_gradients(zip(gradients, variables))

отсечение каждой градиентной матрицы индивидуально изменяет их относительный масштаб, но также возможно:

optimizer = tf.train.AdamOptimizer(1e-3)
gradients, variables = zip(*optimizer.compute_gradients(loss))
gradients = [
    None if gradient is None else tf.clip_by_norm(gradient, 5.0)
    for gradient in gradients]
optimize = optimizer.apply_gradients(zip(gradients, variables))

Это на самом деле правильно описано в документации.:

вызов метода minimize () обеспечивает как вычисление градиентов, так и применение их к переменным. Если вы хотите обработать градиенты перед их применением вы можете использовать оптимизатор в три этапа:

  • вычислить градиенты с помощью compute_gradients ().
  • процесс градиенты, как вы хотите.
  • применить обработаны градиенты с apply_gradients().

и в Примере они предоставляют они используют эти 3 шага:

# Create an optimizer.
opt = GradientDescentOptimizer(learning_rate=0.1)

# Compute the gradients for a list of variables.
grads_and_vars = opt.compute_gradients(loss, <list of variables>)

# grads_and_vars is a list of tuples (gradient, variable).  Do whatever you
# need to the 'gradient' part, for example cap them, etc.
capped_grads_and_vars = [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars]

# Ask the optimizer to apply the capped gradients.
opt.apply_gradients(capped_grads_and_vars)

здесь MyCapper - это любая функция, которая покрывает ваш градиент. Список полезных функций (кроме tf.clip_by_value()) составляет здесь.

для тех, кто хотел бы понять идею градиентного отсечения (по норме):

всякий раз, когда норма градиента больше определенного порога, мы обрезаем норму градиента так, чтобы она оставалась в пределах порога. Этот порог иногда устанавливается в 5.

пусть градиент будет g и max_norm_threshold быть j.

теперь, если ||g|/>j , мы делать:

g = (j*g )||/g|/

это реализация, выполненная в tf.clip_by_norm

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

clipped_value=tf.clip_by_value(grad, -range, +range), var) for grad, var in grads_and_vars

где Грады _and_vars-это пары градиентов (которые вы вычисляете через tf.compute_gradients) и их переменные, они будут применяться к.

после отсечения мы просто применяем его значение с помощью оптимизатора. optimizer.apply_gradients(clipped_value)

IMO лучшим решением является обертывание вашего оптимизатора с помощью декоратора оценки TF tf.contrib.estimator.clip_gradients_by_norm:

original_optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
optimizer = tf.contrib.estimator.clip_gradients_by_norm(original_optimizer, clip_norm=5.0)
train_op = optimizer.minimize(loss)

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

документация: https://www.tensorflow.org/api_docs/python/tf/contrib/estimator/clip_gradients_by_norm