Wie stelle ich die adaptive Lernrate für GradientDescentOptimizer ein?

104

Ich benutze TensorFlow, um ein neuronales Netzwerk zu trainieren. So initialisiere ich 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)

Die Sache hier ist, dass ich nicht weiß, wie ich eine Aktualisierungsregel für die Lernrate oder einen Abklingwert dafür festlegen soll.

Wie kann ich hier eine adaptive Lernrate verwenden?

Anzeigename
quelle
3
Es ist eine gute Angewohnheit, alle Variablen zu initialisieren, nachdem Sie Ihren Optimierer angegeben haben, da einige Optimierer wie AdamOptimizer eigene Variablen verwenden, die ebenfalls initialisiert werden müssen. Andernfalls erhalten Sie möglicherweise eine Fehlermeldung, die folgendermaßen aussieht:FailedPreconditionError (see above for traceback): Attempting to use uninitialized value beta2_power
JYun
Ich erhalte diesen oben genannten Fehler, wenn ich versuche, eine neue Lernrate in Tensorflow von festzulegen tf.train.GradientDescentOptimizer(new_lr).minimize(loss). Es scheint, dass zum Festlegen einer neuen Lernrate das Modell mit den bereits trainierten Variablen initialisiert werden muss. Aber ich kann nicht herausfinden, wie das geht.
Siladittya

Antworten:

193

Zunächst tf.train.GradientDescentOptimizersoll eine konstante Lernrate für alle Variablen in allen Schritten verwendet werden. TensorFlow bietet auch sofort einsatzbereite adaptive Optimierer, einschließlich des tf.train.AdagradOptimizerund des tf.train.AdamOptimizer, und diese können als Ersatz verwendet werden.

Wenn Sie jedoch die Lernrate mit einem ansonsten Vanille-Gradientenabstieg steuern möchten, können Sie die Tatsache nutzen, dass das learning_rateArgument an den tf.train.GradientDescentOptimizerKonstruktor ein TensorObjekt sein kann. Auf diese Weise können Sie in jedem Schritt einen anderen Wert für die Lernrate berechnen, zum Beispiel:

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

Alternativ können Sie einen Skalar erstellen tf.Variable, der die Lernrate enthält, und ihn jedes Mal zuweisen, wenn Sie die Lernrate ändern möchten.

mrry
quelle
Gute Antwort. Kann dieselbe Technik für das Abschneiden von Gradienten verwendet werden? tf.clip_by_normakzeptiert keinen Tensor für die Clip-Norm, also wie wäre es [(tf.minimum(gv[0], ct), gv[1]) for gv in optimizer.compute_gradients(cost, vars)], woct = tf.placeholder('float32', shape=[])
richizy
Das sollte funktionieren, ja. (Obwohl es betrachtet wird tf.clip_by_norm, ist das einzige, was es daran hindert, einen Tensor als Eingabe zu akzeptieren, das constant_op.constant(1.0 / clip_norm). Wenn Sie diesen Ausdruck durch ersetzen, math_ops.inv(clip_norm)funktioniert er mit einem Platzhalter (oder einem anderen Tensor).)
mrry
@mrry Ich habe getan, wie du gesagt hast und einige, wie viel langsamer die Trainingsgeschwindigkeit ist. Wird es bitte erwartet?
tnq177
89

Tensorflow bietet eine Option zum automatischen Anwenden eines exponentiellen Abfalls auf einen Lernratentensor : tf.train.exponential_decay. Ein Beispiel für die Verwendung finden Sie in dieser Zeile im Beispiel für das MNIST-Faltungsmodell . Verwenden Sie dann den obigen Vorschlag von @ mrry, um diese Variable als Parameter learning_rate an den Optimierer Ihrer Wahl anzugeben.

Der wichtigste Auszug ist:

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

Beachten Sie den global_step=batchzu minimierenden Parameter. Dadurch wird der Optimierer angewiesen, den Parameter "Batch" bei jedem Training hilfreich zu erhöhen.

dga
quelle
3
Normalerweise wird die von Ihnen aufgerufene Variable batchaufgerufen global_stepund es gibt mehrere praktische Funktionen, eine zum Erstellen tf.train.create_global_step()(die einfach eine Ganzzahl erstellt tf.Variableund der tf.GraphKeys.GLOBAL_STEPSammlung hinzufügt ) und tf.train.get_global_step().
Lenar Hoyt
86

Der Gradientenabstiegsalgorithmus verwendet die konstante Lernrate, die Sie während der Initialisierung angeben können . Sie können verschiedene Lernraten auf eine von Mrry gezeigte Weise bestehen.

Stattdessen können Sie aber auch erweiterte Optimierer verwenden, die eine schnellere Konvergenzrate aufweisen und sich an die Situation anpassen.

Hier ist eine kurze Erklärung, die auf meinem Verständnis basiert:

  • Der Impuls hilft SGD, in die relevanten Richtungen zu navigieren, und mildert die Schwingungen im Irrelevanten. Es fügt einfach einen Bruchteil der Richtung des vorherigen Schritts zu einem aktuellen Schritt hinzu. Dies erreicht eine Geschwindigkeitsverstärkung in der richtigen Richtung und mildert die Schwingung in falsche Richtungen. Diese Fraktion liegt normalerweise im Bereich (0, 1). Es ist auch sinnvoll, adaptiven Impuls zu verwenden. Zu Beginn des Lernens wird ein großer Impuls Ihren Fortschritt nur behindern. Daher ist es sinnvoll, etwa 0,01 zu verwenden. Wenn alle hohen Gradienten verschwunden sind, können Sie einen größeren Moment verwenden. Es gibt ein Problem mit der Dynamik: Wenn wir dem Ziel sehr nahe sind, ist unsere Dynamik in den meisten Fällen sehr hoch und es ist nicht bekannt, dass sie sich verlangsamen sollte. Dies kann dazu führen, dass es um die Minima herum verfehlt oder schwingt
  • Der beschleunigte Gradient von nesterov überwindet dieses Problem, indem er früh langsamer wird. Im Impuls berechnen wir zuerst den Gradienten und machen dann einen Sprung in diese Richtung, verstärkt durch den Impuls, den wir zuvor hatten. NAG macht dasselbe, aber in einer anderen Reihenfolge: Zuerst machen wir einen großen Sprung basierend auf unseren gespeicherten Informationen, dann berechnen wir den Gradienten und nehmen eine kleine Korrektur vor. Diese scheinbar irrelevante Änderung führt zu erheblichen praktischen Beschleunigungen.
  • AdaGrad oder adaptiver Gradient ermöglicht die Anpassung der Lernrate basierend auf Parametern. Es führt größere Aktualisierungen für seltene Parameter und kleinere Aktualisierungen für häufige Parameter durch. Aus diesem Grund eignet es sich gut für spärliche Daten (NLP oder Bilderkennung). Ein weiterer Vorteil besteht darin, dass die Notwendigkeit, die Lernrate anzupassen, grundsätzlich entfällt. Jeder Parameter hat seine eigene Lernrate und aufgrund der Besonderheiten des Algorithmus nimmt die Lernrate monoton ab. Dies verursacht das größte Problem: Irgendwann ist die Lernrate so gering, dass das System aufhört zu lernen
  • AdaDelta löst das Problem der monoton sinkenden Lernrate in AdaGrad. In AdaGrad wurde die Lernrate ungefähr als eins geteilt durch die Summe der Quadratwurzeln berechnet. In jeder Phase fügen Sie der Summe eine weitere Quadratwurzel hinzu, wodurch der Nenner ständig abnimmt. In AdaDelta wird anstelle der Summierung aller vergangenen Quadratwurzeln ein Schiebefenster verwendet, mit dem die Summe verringert werden kann. RMSprop ist AdaDelta sehr ähnlich
  • Adam oder adaptiver Impuls ist ein Algorithmus ähnlich wie AdaDelta. Zusätzlich zum Speichern der Lernraten für jeden der Parameter werden auch Impulsänderungen für jeden von ihnen separat gespeichert

    Ein paar Visualisierungen : Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Salvador Dali
quelle
2
Zum Vergleich verschiedener Optimierer in TensorFlow schauen Sie sich das folgende ipython-Notizbuch an: github.com/vsmolyakov/experiments_with_python/blob/master/chp03/… für
Vadim Smolyakov
Weiterführende Optimierer sind nicht "stattdessen" zu verwenden, sondern siehe auch stats.stackexchange.com/questions/200063/…
Dima Lituiev
@DimaLituiev können Sie zwei Optimierer gleichzeitig verwenden? Wenn nein, verwenden Sie Optimierer1 anstelle von Optimierer2.
Salvador Dali
1
das sage ich nicht, und das war hier nicht die Frage. Sie schlagen vor, erweiterte Optimierer anstelle der adaptiven Lernrate zu verwenden. Ich sage, Sie möchten lieber erweiterte Optimierer zusätzlich zur adaptiven Lernrate verwenden
Dima Lituiev
7

Aus offiziellen Tensorflow- Dokumenten

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))
Prakash Vanapalli
quelle
0

Wenn Sie bestimmte Lernraten für Intervalle von Epochen wie einstellen möchten 0 < a < b < c < .... Anschließend können Sie Ihre Lernrate als bedingten Tensor definieren, der vom globalen Schritt abhängig ist, und diesen wie gewohnt dem Optimierer zuführen.

Sie könnten dies mit einer Reihe verschachtelter tf.condAnweisungen erreichen, aber es ist einfacher, den Tensor rekursiv zu erstellen:

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

Um es dann verwenden zu können, müssen Sie wissen, wie viele Trainingsschritte es in einer einzelnen Epoche gibt, damit wir den globalen Schritt verwenden können, um zum richtigen Zeitpunkt zu wechseln und schließlich die gewünschten Epochen und Lernraten zu definieren. Wenn ich also die Lernraten [0.1, 0.01, 0.001, 0.0001]während der Epochenintervalle von [0, 19], [20, 59], [60, 99], [100, \infty]jeweils möchte, würde ich tun:

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