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


104

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)

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

ここで適応学習率を使用するにはどうすればよいですか?


3
AdamOptimizerのような一部のオプティマイザは、初期化する必要のある独自の変数を使用するため、オプティマイザを指定した後にすべての変数を初期化するのは良い習慣です。:そうしないと、このようになりますというエラーが発生することがありますFailedPreconditionError (see above for traceback): Attempting to use uninitialized value beta2_power
JYun

によってTensorflowで新しい学習率を設定しようとすると、上記のエラーが発生しtf.train.GradientDescentOptimizer(new_lr).minimize(loss)ます。新しい学習率を設定するには、すでにトレーニングされた変数でモデルを初期化する必要があるようです。しかし、それを行う方法を理解することはできません。
Siladittya 2018年

回答:


193

まずtf.train.GradientDescentOptimizer、すべてのステップのすべての変数に一定の学習率を使用するように設計されています。TensorFlow tf.train.AdagradOptimizertf.train.AdamOptimizer、やを含む、すぐに使用できる適応オプティマイザも提供します。これらは、ドロップイン置換品として使用できます。

ただし、通常の勾配降下法を使用して学習率を制御する場合はlearning_ratetf.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学習率を保持するスカラーを作成し、学習率を変更するたびに割り当てることができます。


すばらしい答えです。同じ手法をグラデーションクリッピングに使用できますか?tf.clip_by_normはクリップノルムのテンソルを受け入れないので[(tf.minimum(gv[0], ct), gv[1]) for gv in optimizer.compute_gradients(cost, vars)]、どこで実行するのがよいでしょうかct = tf.placeholder('float32', shape=[])
richizy

はい、うまくいくはずです。(ただし、を見てtf.clip_by_norm、テンソルを入力として受け入れないようにする唯一の方法はconstant_op.constant(1.0 / clip_norm)です。その式をで置き換えるmath_ops.inv(clip_norm)と、プレースホルダー(または他のテンソル)入力で動作します。)
mrry

@mrryあなたが言ったように私はやった、そしていくつかの訓練速度ははるかに遅い よろしいですか?
tnq177 2018

89

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最小化するパラメーターに注意してください。これにより、最適化プログラムは、トレーニングするたびに「バッチ」パラメーターを増分するのに役立ちます。


3
通常、呼び出す変数が呼び出さbatchglobal_step、いくつかの便利な関数があります。1つはそれを作成するための関数tf.train.create_global_step()(これは単に整数tf.Variableを作成してtf.GraphKeys.GLOBAL_STEPコレクションに追加する)とtf.train.get_global_step()です。
Lenar Hoyt 2017

86

勾配降下アルゴリズムは、初期化中に提供できる一定の学習率を使用します。Mrryが示す方法で、さまざまな学習率を渡すことができます。

ただし、その代わりに、収束速度が速く、状況に適応する高度なオプティマイザを使用することもできます。

これは私の理解に基づいた簡単な説明です:

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

    いくつかの可視化ここに画像の説明を入力してください ここに画像の説明を入力してください


2
:TensorFlowの異なるオプティマイザの比較のためにノートipython以下を見ていgithub.com/vsmolyakov/experiments_with_python/blob/master/chp03/...ため
ヴァディムSmolyakov

より高度な最適化プログラムは、「代わりに」運ばれたが、加えて、参照すべきではないstats.stackexchange.com/questions/200063/...
ディマLituiev

@DimaLituiev 2つのオプティマイザを同時に使用できますか?いいえの場合、optimizer2の代わりにoptimizer1を使用しています。
サルバドールダリ

1
それは私が言っていることではなく、ここでは問題ではありませんでした。適応学習率の代わりに高度なオプティマイザーを使用することをお勧めします。適応学習率に加えて高度なオプティマイザを使用する方がいいと言っています
Dima Lituiev

7

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

0

のようなエポックの間隔に特定の学習率を設定する場合 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,)
            )

次に、それを使用するには、単一のエポックにトレーニングステップがいくつあるかを知る必要があります。これにより、グローバルステップを使用して適切なタイミングで切り替え、最終的に必要なエポックと学習率を定義できます。したがって[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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.