Подтвердить что ты не робот

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

С учетом примерного кода.

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

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

Это пример, который можно использовать, но где я его представляю? В определении 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 является входом, а не градиентом, что нужно обрезать?

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

4b9b3361

Ответ 1

Градиентная обрезка должна произойти после вычисления градиентов, но перед применением их для обновления параметров модели. В вашем примере обе эти вещи обрабатываются методом 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)

Ответ 2

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

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))

Ответ 3

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

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

  • Вычислить градиенты с помощью 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()) находится здесь.

Ответ 4

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

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

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

Теперь, если || г || > Дж, мы делаем:

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

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

Ответ 5

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

Ответ 6

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

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

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

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