[python] 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가 입력이고 무엇을 잘라야 할 졸업생이 아니기 때문에 의미가 없습니다.

이를 위해 고유 한 Optimizer를 정의해야합니까? 아니면 더 간단한 옵션이 있습니까?



답변

그래디언트 클리핑은 그래디언트를 계산 한 후 모델의 매개 변수를 업데이트하기 위해 적용하기 전에 발생해야합니다. 귀하의 예에서 두 가지 모두 AdamOptimizer.minimize()메서드에 의해 처리됩니다 .

그라디언트를 자르려면 TensorFlow의 API 문서의이 섹션에 설명 된대로 그라디언트를 명시 적으로 계산, 자르고 적용해야 합니다 . 특히 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))

TensorFlow 2에서 테이프는 기울기를 계산하고 옵티마이 저는 Keras에서 제공되며 세션으로 전달하지 않고 자동으로 실행되기 때문에 업데이트 작업을 저장할 필요가 없습니다.

optimizer = tf.keras.optimizers.Adam(1e-3)
# ...
with tf.GradientTape() as tape:
  loss = ...
variables = ...
gradients = tape.gradient(loss, variables)
gradients, _ = tf.clip_by_global_norm(gradients, 5.0)
optimizer.apply_gradients(zip(gradients, variables))


답변

이것은 실제로 문서에 제대로 설명되어 있습니다. :

최소화 ()를 호출하면 그래디언트를 계산하고 변수에 적용 할 수 있습니다. 그라디언트를 적용하기 전에 처리하려면 대신 최적화 프로그램을 세 단계로 사용할 수 있습니다.

  • 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


답변

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


답변

Gradient Clipping은 기본적으로 그라디언트가 폭발하거나 사라지는 경우에 도움이됩니다. 손실이 너무 높아서 네트워크를 통해 지수 그라디언트가 흐르게되어 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)


답변