web-dev-qa-db-ja.com

GradientDescentOptimizerの適応学習率を設定するにはどうすればいいですか?

私はTensorFlowを使ってニューラルネットワークを訓練しています。これがGradientDescentOptimizerを初期化する方法です。

init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

mse        = tf.reduce_mean(tf.square(out - out_))
train_step = tf.train.GradientDescentOptimizer(0.3).minimize(mse)

ここで重要なのは、学習率の更新ルールやその減衰値を設定する方法がわからないということです。

ここでは適応学習率をどのように使用できますか?

91
displayname

まず第一に、tf.train.GradientDescentOptimizerはすべてのステップですべての変数に対して一定の学習率を使うように設計されています。 TensorFlowは、 tf.train.AdagradOptimizer および tf.train.AdamOptimizer を含む、すぐに使用可能なアダプティブオプティマイザも提供します。これらは、ドロップイン置換として使用できます。

ただし、そうでなければVanilla勾配降下法を使用して学習率を制御する場合は、 learning_rateコンストラクター へのtf.train.GradientDescentOptimizer引数をTensorオブジェクトにすることができます。これにより、各ステップの学習率に対して異なる値を計算できます。次に例を示します。

learning_rate = tf.placeholder(tf.float32, shape=[])
# ...
train_step = tf.train.GradientDescentOptimizer(
    learning_rate=learning_rate).minimize(mse)

sess = tf.Session()

# Feed different values for learning rate to each training step.
sess.run(train_step, feed_dict={learning_rate: 0.1})
sess.run(train_step, feed_dict={learning_rate: 0.1})
sess.run(train_step, feed_dict={learning_rate: 0.01})
sess.run(train_step, feed_dict={learning_rate: 0.01})

あるいは、学習率を保持するスカラーtf.Variableを作成し、学習率を変更するたびにそれを割り当てることもできます。

184
mrry

Tensorflowは自動的に指数関数的減衰を学習率テンソルに適用する操作を提供します: tf.train.exponential_decay 。使用されている例については、 MNISTたたみ込みモデルの例のこの行 を参照してください。次に、上記の@ mrryの提案を使用して、選択したオプティマイザのlearning_rateパラメータとしてこの変数を指定します。

注目すべき抜粋は次のとおりです。

# Optimizer: set up a variable that's incremented once per batch and
# controls the learning rate decay.
batch = tf.Variable(0)

learning_rate = tf.train.exponential_decay(
  0.01,                # Base learning rate.
  batch * BATCH_SIZE,  # Current index into the dataset.
  train_size,          # Decay step.
  0.95,                # Decay rate.
  staircase=True)
# Use simple momentum for the optimization.
optimizer = tf.train.MomentumOptimizer(learning_rate,
                                     0.9).minimize(loss,
                                                   global_step=batch)

最小化するglobal_step=batchパラメータに注意してください。これはオプティマイザーにトレーニングの度に 'batch'パラメーターを便利に増やすように伝えます。

87
dga

勾配降下アルゴリズムでは、 初期化中 で指定できる一定の学習率が使用されます。あなたはMrryによって示された方法で様々な学習率を渡すことができます。

しかし代わりに より高度なオプティマイザ を使うこともできます。これらはより速い収束速度を持ち、状況に適応します。

これが私の理解に基づく簡単な説明です。

  • 運動量助ける 関連する方向に沿ってナビゲートし、無関係の振動を和らげるSGD。前のステップの方向のごく一部を現在のステップに追加するだけです。これは正しい方向への速度の増幅を達成し、間違った方向への振動を和らげる。この割合は通常(0、1)の範囲です。適応運動量を使用することも理にかなっています。大きな運動量を学び始めても、あなたの進歩を妨げるだけなので、0.01のようなものを使うことは意味がありません。そしてすべての高い勾配が消えたら、あなたはより大きな運動量を使うことができます。運動量には1つ問題があります。目標に非常に近いと、ほとんどの場合、運動量が非常に大きくなり、速度が低下することがわかりません。これにより、最小値を失うか振動する可能性があります。
  • nesterov加速勾配は、早めに速度を落とし始めることでこの問題を克服します。運動量では、最初に勾配を計算してから、その方向にジャンプして、以前に行った運動量によって増幅します。 NAGも同じことを行いますが、別の順序で行います。まず、格納されている情報に基づいて大きなジャンプを行い、次に勾配を計算して小さな修正を加えます。この一見無関係な変更により、実用的なスピードが大幅に向上します。
  • AdaGradまたは適応勾配により、学習率をパラメータに基づいて適応させることができます。頻度の低いパラメータに対してはより大きな更新を、頻繁なパラメータに対してはより小さな更新を実行します。このため、まばらなデータ(NLPまたは画像認識)に最適です。もう一つの利点は、それが基本的に学習率を調整する必要性を無効にするということです。各パラメータには独自の学習率があり、アルゴリズムの特性により学習率は単調に減少しています。これが最大の問題を引き起こします。ある時点で学習率が非常に小さいためにシステムが学習を停止します。
  • AdaDeltaは、AdaGradの学習率が単調に減少する問題を解決します。 AdaGradでは、学習率は平方根の合計で割ったものとしておよそ計算されました。各段階で、合計に別の平方根を追加します。これにより、分母は常に減少します。 AdaDeltaでは、過去のすべての平方根を合計する代わりに、スライディングウィンドウを使用して合計を減らすことができます。 RMSpropはAdaDeltaと非常によく似ています
  • Adamまたは適応運動量はAdaDeltaに似たアルゴリズムです。しかし、パラメータごとに学習率を保存することに加えて、パラメータごとに運動量の変化も別々に保存します。

    A 視覚化が少ないenter image description hereenter image description here

80
Salvador Dali

tensorflow 公式ドキュメントより

global_step = tf.Variable(0, trainable=False)
starter_learning_rate = 0.1
learning_rate = tf.train.exponential_decay(starter_learning_rate, global_step,
                                       100000, 0.96, staircase=True)

# Passing global_step to minimize() will increment it at each step.
learning_step = (
tf.train.GradientDescentOptimizer(learning_rate)
.minimize(...my loss..., global_step=global_step))
6

0 < a < b < c < ...のようにエポックの間隔に特定の学習率を設定したい場合。次に、学習率を大域ステップを条件とする条件付きテンソルとして定義し、これを最適化プログラムに通常どおりに入力します。

これはtf.condステートメントをネストしてまとめることで実現できますが、テンソルを再帰的に構築する方が簡単です。

def make_learning_rate_tensor(reduction_steps, learning_rates, global_step):
    assert len(reduction_steps) + 1 == len(learning_rates)
    if len(reduction_steps) == 1:
        return tf.cond(
            global_step < reduction_steps[0],
            lambda: learning_rates[0],
            lambda: learning_rates[1]
        )
    else:
        return tf.cond(
            global_step < reduction_steps[0],
            lambda: learning_rates[0],
            lambda: make_learning_rate_tensor(
                reduction_steps[1:],
                learning_rates[1:],
                global_step,)
            )

それを使用するには、1つのEpochにいくつのトレーニングステップがあるかを知る必要があります。そうすれば、グローバルなステップを使用して適切なタイミングで切り替え、最後に必要なエポックと学習率を定義できます。それで、[0.1, 0.01, 0.001, 0.0001]のエポック間隔の間にそれぞれ[0, 19], [20, 59], [60, 99], [100, \infty]の学習率が欲しいなら、私はそうするでしょう:

global_step = tf.train.get_or_create_global_step()
learning_rates = [0.1, 0.01, 0.001, 0.0001]
steps_per_Epoch = 225
epochs_to_switch_at = [20, 60, 100]
epochs_to_switch_at = [x*steps_per_Epoch for x in epochs_to_switch_at ]
learning_rate = make_learning_rate_tensor(epochs_to_switch_at , learning_rates, global_step)
0
Ben