TensorFlowでグラデーションクリッピングを適用する方法は?


96

サンプルコードを考えてみましょう。

グラデーションが爆発する可能性がある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は入力であり、何がクリップされる卒業生ではないので、これは意味がありませんか?

これに対して独自のオプティマイザを定義する必要がありますか、それともより簡単なオプションがありますか?

回答:


143

グラデーションクリッピングは、グラデーションを計算した後、モデルのパラメーターを更新するためにグラデーションを適用する前に行う必要があります。あなたの例では、それらの両方が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)

4
Styrke、投稿ありがとう。オプティマイザの反復を実際に実行するための次のステップは何ですか?通常、オプティマイザは次のようにインスタンス化され、オプティマイザoptimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost) の反復は次のように行われますoptimizer.run()optimizer.run()、この場合、使用は機能しないようです。
applecider

6
okがそれを得たoptimizer.apply_gradients(capped_gvs)ニーズが何かに割り当てられることをx = optimizer.apply_gradients(capped_gvs)、あなたのセッションで、あなたのように訓練することができますx.run(...)
アップルサイダー

3
素晴らしい編集提案のために@ remi-cuingnetに声をかけてください。(残念ながら速攻レビュアーによって拒否されました)
Styrke

これは私にUserWarning: Converting sparse IndexedSlices to a dense Tensor with 148331760 elements. This may consume a large amount of memory.それを与えますどういうわけか私の疎な勾配は密に変換されます この問題を克服する方法はありますか?
Pekka

8
実際にクリップ勾配(tensorflowドキュメント、コンピュータ科学者、及びロジックに従って)に正しい方法はであるtf.clip_by_global_norm@danijarによって示唆されるように、
gdelab

116

人気があるように思われるものにもかかわらず、グローバルな基準でグラデーション全体をクリップしたいと思うでしょう:

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

10
の良い例clip_by_global_norm()!これは、として記載されてthe correct way to perform gradient clippingtensorflowドキュメントで:tensorflow.org/versions/r1.2/api_docs/python/tf/...
MZHm

9
@Escachatorこれは経験的であり、モデルとおそらくタスクに依存します。私がすることは、勾配のノルムを視覚化してtf.global_norm(gradients)それが通常の範囲であることを確認し、その少し上をクリップして外れ値がトレーニングを台無しにしないようにすることです。
danijar 2017

1
それでもopt.minimize()後から電話をかけopt.run()ますか、それとも他の回答のコメントで提案されているような別の電話をかけますか?
reese0106

3
@ reese0106いいえ、optimizer.minimize(loss)グラデーションを計算して適用するための省略形にすぎません。あなたは私の答えの例をで実行できますsess.run(optimize)
danijar 2018

1
だから私がtf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)実験関数内で使用しているなら、あなたoptimizeは私のtrain_op正しいものを置き換えますか?現在、私はtrain_op = optimizer.minimize(loss, global_step=global_step))それに応じて調整するようにしています...
reese0106

10

これは実際にはドキュメントで適切に説明されています。

miniize()を呼び出すと、勾配の計算と変数への適用の両方が処理されます。グラデーションを適用する前に処理したい場合は、代わりに3つのステップでオプティマイザーを使用できます。

  • 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()こちらです。


それでもopt.minimize()後から電話をかけopt.run()ますか、それとも他の回答のコメントで提案されているような別の電話をかけますか?
reese0106

@ reese0106いいえ、たとえばのopt.apply_gradients(...)ようtrain_stepに変数にを割り当てる必要があります(の場合と同様に)opt.minimize()。メインループで、通常のように呼び出してトレーニングしますsess.run([train_step, ...], feed_dict)
dsalaj

勾配は、モデルのすべてのパラメーターに対する損失の導関数のベクトルとして定義されることに注意してください。TensorFlowは、それを各変数とその勾配のタプルを含むPythonリストとして表します。これは、勾配ノルムをクリップすることを意味します。各テンソルを個別にクリップすることはできませんtf.clip_by_global_norm(list_of_tensors)。リストを一度に検討する必要があります(例:を使用)。
ダニジャー

8

グラディエントクリッピング(標準)の考え方を理解したい人のために:

勾配ノルムが特定のしきい値よりも大きい場合は常に、勾配ノルムをクリップしてしきい値内に留まらせます。このしきい値は時々設定され5ます。

勾配をgとし、max_norm_thresholdをjとします。

|| g || > j、私たちはします:

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

これはで行われた実装です tf.clip_by_norm


しきい値を手動で選択する必要がある場合、これを行う一般的な方法はありますか?
ningyuwhut

これは、いくつかの論文で示唆されている一種の黒魔術です。それ以外の場合は、多くの実験を行い、どれがよりうまく機能するかを見つける必要があります。
kmario23

4

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


2

グラデーションクリッピングは、基本的に、グラデーションが爆発または消失した場合に役立ちます。損失が高すぎると、指数勾配がネットワークを流れ、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)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.