Aufwärmen der Lernrate mit Cosine Decay in Keras/TensorFlow PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.

Aufwärmen der Lernrate mit Cosine Decay in Keras/TensorFlow

Die Lernrate ist ein wichtiger Hyperparameter in Deep-Learning-Netzwerken – und bestimmt direkt die (...) an denen Aktualisierungen von Gewichten durchgeführt werden, die geschätzt werden, um eine gegebene Verlustfunktion zu minimieren. Im SGD:

$$
Gewicht_{t+1} = Gewicht_t – lr * frac{derror}{dweight_t}
$$

Mit einer Lernrate von 0, das aktualisierte Gewicht ist gerade wieder auf sich selbst gestellt – Gewichtt. Die Lernrate ist praktisch ein Knopf, an dem wir drehen können, um das Lernen zu aktivieren oder zu deaktivieren, und sie hat einen großen Einfluss darauf, wie viel Lernen passiert, indem sie den Grad der Gewichtsaktualisierungen direkt steuert.

Verschiedene Optimierer verwenden Lernraten unterschiedlich – aber das zugrunde liegende Konzept bleibt gleich. Selbstverständlich sind Lernraten Gegenstand vieler Studien, Veröffentlichungen und Praxis-Benchmarks.

Im Allgemeinen sind sich so ziemlich alle einig, dass eine statische Lernrate nicht ausreicht, und bei den meisten Techniken, die die Lernrate während des Trainings anpassen, findet eine Art von Lernratenreduzierung statt – sei es monoton, kosinusförmig, dreieckig oder andere Arten von die Ermäßigung.

Eine Technik, die in den letzten Jahren Fuß gefasst hat Lernrate Aufwärmen, die praktisch mit jeder anderen Reduktionstechnik kombinierbar ist.

Lernrate Aufwärmen

Die Idee hinter dem Aufwärmen der Lernrate ist einfach. In den frühesten Stadien des Trainings – Gewichte sind weit von ihrem Idealzustand entfernt. Dies bedeutet große Aktualisierungen auf der ganzen Linie, die als „Überkorrekturen“ für jedes Gewicht angesehen werden können – wobei die drastische Aktualisierung eines anderen die Aktualisierung eines anderen Gewichts zunichte machen kann, wodurch die Anfangsphasen des Trainings instabiler werden.

Diese Änderungen bügeln aus, können aber vermieden werden, indem man zunächst eine kleine Lernrate hat, einen stabileren suboptimalen Zustand erreicht und dann eine größere Lernrate anwendet. Sie können das Netzwerk sozusagen in Updates einbinden, anstatt es mit ihnen zu treffen.

Das ist das Aufwärmen der Lernrate! Beginnen Sie mit einer niedrigen (oder 0) Lernrate und erhöhen Sie sich auf eine Startlernrate (womit Sie sowieso beginnen würden). Dieser Anstieg kann wirklich jeder Funktion folgen, ist aber üblicherweise linear.

Nach Erreichen der Anfangsrate können andere Zeitpläne wie Kosinusabfall, lineare Reduktion usw. angewendet werden, um die Rate schrittweise bis zum Ende des Trainings zu senken. Das Aufwärmen der Lernrate ist normalerweise Teil eines Zeitplans mit zwei Zeitplänen, bei dem das Aufwärmen von LR der erste ist, während ein anderer Zeitplan übernimmt, nachdem die Rate einen Startpunkt erreicht hat.

In diesem Leitfaden implementieren wir ein Aufwärmen der Lernrate in Keras/TensorFlow als keras.optimizers.schedules.LearningRateSchedule Unterklasse und keras.callbacks.Callback zurückrufen. Die Lernrate wird von erhöht 0 zu target_lr und wenden Sie den Kosinusabfall an, da dies ein sehr häufiger sekundärer Zeitplan ist. Wie gewohnt macht es Keras einfach, flexible Lösungen auf verschiedene Arten zu implementieren und mit Ihrem Netzwerk auszuliefern.

Hinweis: Die Implementierung ist generisch und inspiriert von Tonys Keras-Implementierung der Tricks, die in „Trickkiste zur Bildklassifizierung mit Convolutional Neural Networks“.

Lernrate mit Keras Callbacks

Der einfachste Weg, einen beliebigen Lernratenplan zu implementieren, besteht darin, eine Funktion zu erstellen, die die übernimmt lr Parameter (float32), durchläuft es eine Transformation und gibt es zurück. Diese Funktion wird dann an die weitergegeben LearningRateScheduler Callback, der die Funktion auf die Lernrate anwendet.

Nun wird die tf.keras.callbacks.LearningRateScheduler() übergibt die Epochennummer an die Funktion, die zur Berechnung der Lernrate verwendet wird, was ziemlich grob ist. LR Warmup sollte bei jedem durchgeführt werden Step (Batch), nicht Epoche, also müssen wir a ableiten global_step (über alle Epochen), um stattdessen die Lernrate zu berechnen und die zu unterteilen Callback Klasse, um einen benutzerdefinierten Rückruf zu erstellen, anstatt nur die Funktion zu übergeben, da wir bei jedem Aufruf Argumente übergeben müssen, was unmöglich ist, wenn nur die Funktion übergeben wird:

def func():
    return ...
    
keras.callbacks.LearningRateScheduler(func)

Dieser Ansatz ist günstig, wenn Sie kein hohes Maß an Anpassung wünschen und nicht in die Art und Weise eingreifen möchten, wie Keras die behandelt lr, und vor allem, wenn Sie Rückrufe wie verwenden möchten ReduceLROnPlateau() da es nur mit einem Float-basierten funktionieren kann lr. Lassen Sie uns ein Aufwärmen der Lernrate mit einem Keras-Callback implementieren, beginnend mit einer praktischen Funktion:

def lr_warmup_cosine_decay(global_step,
                           warmup_steps,
                           hold = 0,
                           total_steps=0,
                           start_lr=0.0,
                           target_lr=1e-3):
    
    learning_rate = 0.5 * target_lr * (1 + np.cos(np.pi * (global_step - warmup_steps - hold) / float(total_steps - warmup_steps - hold)))

    
    warmup_lr = target_lr * (global_step / warmup_steps)

    
    
    if hold > 0:
        learning_rate = np.where(global_step > warmup_steps + hold,
                                 learning_rate, target_lr)
    
    learning_rate = np.where(global_step < warmup_steps, warmup_lr, learning_rate)
    return learning_rate

Bei jedem Schritt berechnen wir die Lernrate und die Aufwärm-Lernrate (beide Elemente des Zeitplans) in Bezug auf die start_lr und target_lr. start_lr beginnt in der Regel um 0.0, Während die target_lr hängt von Ihrem Netzwerk und Optimierer ab – 1e-3 Dies ist möglicherweise kein guter Standard. Stellen Sie daher sicher, dass Sie beim Aufrufen der Methode Ihr Ziel festlegen, das LR startet.

Besitzt das global_step in der Ausbildung ist höher als die warmup_steps Wir haben festgelegt – wir verwenden den Kosinus-Abklingplan LR. Wenn nicht, bedeutet dies, dass wir uns noch aufwärmen, also wird das Aufwärm-LR verwendet. Wenn die hold Argument gesetzt ist, halten wir die target_lr für diese Anzahl von Schritten nach dem Aufwärmen und vor dem Kosinusabfall. np.where() bietet eine großartige Syntax dafür:

np.where(condition, value_if_true, value_if_false)

Sie können die Funktion visualisieren mit:

steps = np.arange(0, 1000, 1)
lrs = []

for step in steps:
  lrs.append(lr_warmup_cosine_decay(step, total_steps=len(steps), warmup_steps=100, hold=10))
plt.plot(lrs)

Nun möchten wir diese Funktion als Teil eines Rückrufs verwenden und den Optimierungsschritt als übergeben global_step anstelle eines Elements eines beliebigen Arrays – oder Sie können die Berechnung innerhalb der Klasse durchführen. Lassen Sie uns die subclass Callback Klasse:

from keras import backend as K

class WarmupCosineDecay(keras.callbacks.Callback):
    def __init__(self, total_steps=0, warmup_steps=0, start_lr=0.0, target_lr=1e-3, hold=0):

        super(WarmupCosineDecay, self).__init__()
        self.start_lr = start_lr
        self.hold = hold
        self.total_steps = total_steps
        self.global_step = 0
        self.target_lr = target_lr
        self.warmup_steps = warmup_steps
        self.lrs = []

    def on_batch_end(self, batch, logs=None):
        self.global_step = self.global_step + 1
        lr = model.optimizer.lr.numpy()
        self.lrs.append(lr)

    def on_batch_begin(self, batch, logs=None):
        lr = lr_warmup_cosine_decay(global_step=self.global_step,
                                    total_steps=self.total_steps,
                                    warmup_steps=self.warmup_steps,
                                    start_lr=self.start_lr,
                                    target_lr=self.target_lr,
                                    hold=self.hold)
        K.set_value(self.model.optimizer.lr, lr)

Sehen Sie sich unseren praxisnahen, praktischen Leitfaden zum Erlernen von Git an, mit Best Practices, branchenweit akzeptierten Standards und einem mitgelieferten Spickzettel. Hören Sie auf, Git-Befehle zu googeln und tatsächlich in Verbindung, um es!

Zuerst definieren wir den Konstruktor für die Klasse und verfolgen ihre Felder. Bei jedem beendeten Stapel erhöhen wir den globalen Schritt, notieren den aktuellen LR und fügen ihn der Liste der bisherigen LRs hinzu. Zu Beginn jeder Charge berechnen wir die LR anhand der lr_warmup_cosine_decay() Funktion und setzen Sie diese LR als aktuelle LR des Optimierers. Dies geschieht mit dem Backend set_value().

Wenn das erledigt ist, berechnen Sie einfach die Gesamtschritte (Länge/Batch_Größe*Epochen) und nehmen Sie einen Teil dieser Zahl für sich warmup_steps:


total_steps = len(train_set)*config['EPOCHS']



warmup_steps = int(0.05*total_steps)

callback = WarmupCosineDecay(total_steps=total_steps, 
                             warmup_steps=warmup_steps,
                             hold=int(warmup_steps/2), 
                             start_lr=0.0, 
                             target_lr=1e-3)

Erstellen Sie schließlich Ihr Modell und stellen Sie den Rückruf in der bereit fit() Anruf:

model = keras.applications.EfficientNetV2B0(weights=None, 
                                            classes=n_classes, 
                                            input_shape=[224, 224, 3])
  
model.compile(loss="sparse_categorical_crossentropy",
                  optimizer='adam',
                  jit_compile=True,
                  metrics=['accuracy'])

Am Ende des Trainings können Sie die geänderten LRs erhalten und visualisieren über:

lrs = callback.lrs 
plt.plot(lrs)

Aufwärmen der Lernrate mit Cosine Decay in Keras/TensorFlow PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.

Wenn Sie den Verlauf eines Modells darstellen, das mit und ohne LR-Aufwärmung trainiert wurde, sehen Sie einen deutlichen Unterschied in der Stabilität des Trainings:

Aufwärmen der Lernrate mit Cosine Decay in Keras/TensorFlow PlatoBlockchain Data Intelligence. Vertikale Suche. Ai.

Lernrate mit LearningRateSchedule-Unterklasse

Eine Alternative zum Erstellen eines Callbacks ist das Erstellen einer LearningRateSchedule Unterklasse, die das LR nicht manipuliert – es ersetzt es. Dieser Ansatz ermöglicht es Ihnen, etwas mehr in das Backend von Keras/TensorFlow einzudringen, kann aber bei Verwendung nicht mit anderen LR-bezogenen Callbacks kombiniert werden, wie z ReduceLROnPlateau(), die LRs als Gleitkommazahlen behandelt.

Darüber hinaus erfordert die Verwendung der Unterklasse, dass Sie sie serialisierbar machen (Überladung get_config()), da es Teil des Modells wird, wenn Sie die Modellgewichte speichern möchten. Eine weitere zu beachtende Sache ist, dass die Klasse erwartet, ausschließlich mit zu arbeiten tf.Tensors. Glücklicherweise besteht der einzige Unterschied in unserer Arbeitsweise darin, anzurufen tf.func() statt np.func() da die TensorFlow- und NumPy-APIs erstaunlich ähnlich und kompatibel sind.

Lassen Sie uns Bequemlichkeit umschreiben lr_warmup_cosine_decay() Funktion, um stattdessen TensorFlow-Operationen zu verwenden:

def lr_warmup_cosine_decay(global_step,
                           warmup_steps,
                           hold = 0,
                           total_steps=0,
                           start_lr=0.0,
                           target_lr=1e-3):
    
    
    learning_rate = 0.5 * target_lr * (1 + tf.cos(tf.constant(np.pi) * (global_step - warmup_steps - hold) / float(total_steps - warmup_steps - hold)))

    
    warmup_lr = target_lr * (global_step / warmup_steps)

    
    
    if hold > 0:
        learning_rate = tf.where(global_step > warmup_steps + hold,
                                 learning_rate, target_lr)
    
    learning_rate = tf.where(global_step < warmup_steps, warmup_lr, learning_rate)
    return learning_rate

Mit der Convinience-Funktion können wir die ableiten LearningRateSchedule Klasse. Auf jeder __call__() (Batch) berechnen wir den LR mit der Funktion und geben ihn zurück. Sie können die Berechnung natürlich auch innerhalb der untergeordneten Klasse packen.

Die Syntax ist sauberer als die Callback sublcass, vor allem, weil wir Zugriff auf die erhalten step Feld, anstatt es selbst zu verfolgen, macht es aber auch etwas schwieriger, mit Klasseneigenschaften zu arbeiten – insbesondere macht es es schwierig, die zu extrahieren lr von einem tf.Tensor() in einen anderen Typ, um ihn in einer Liste zu verfolgen. Dies kann technisch umgangen werden, indem man im eifrigen Modus läuft, stellt aber ein Ärgernis dar, um den LR zu Debugging-Zwecken im Auge zu behalten, und wird am besten vermieden:

class WarmUpCosineDecay(keras.optimizers.schedules.LearningRateSchedule):
    def __init__(self, start_lr, target_lr, warmup_steps, total_steps, hold):
        super().__init__()
        self.start_lr = start_lr
        self.target_lr = target_lr
        self.warmup_steps = warmup_steps
        self.total_steps = total_steps
        self.hold = hold

    def __call__(self, step):
        lr = lr_warmup_cosine_decay(global_step=step,
                                    total_steps=self.total_steps,
                                    warmup_steps=self.warmup_steps,
                                    start_lr=self.start_lr,
                                    target_lr=self.target_lr,
                                    hold=self.hold)

        return tf.where(
            step > self.total_steps, 0.0, lr, name="learning_rate"
        )

Die Parameter sind die gleichen und können auf die gleiche Weise wie zuvor berechnet werden:


total_steps = len(train_set)*config['EPOCHS']



warmup_steps = int(0.05*total_steps)

schedule = WarmUpCosineDecay(start_lr=0.0, target_lr=1e-3, warmup_steps=warmup_steps, total_steps=total_steps, hold=warmup_steps)

Und die Trainingspipeline unterscheidet sich nur darin, dass wir das LR des Optimierers auf setzen schedule:

model = keras.applications.EfficientNetV2B0(weights=None, 
                                            classes=n_classes, 
                                            input_shape=[224, 224, 3])
  
model.compile(loss="sparse_categorical_crossentropy",
                  optimizer=tf.keras.optimizers.Adam(learning_rate=schedule),
                  jit_compile=True,
                  metrics=['accuracy'])

history3 = model.fit(train_set,
                    epochs = config['EPOCHS'],
                    validation_data=valid_set)

Wenn Sie das Modell speichern möchten, wird die WarmupCosineDecay Zeitplan muss die überschreiben get_config() Verfahren:

    def get_config(self):
        config = {
          'start_lr': self.start_lr,
          'target_lr': self.target_lr,
          'warmup_steps': self.warmup_steps,
          'total_steps': self.total_steps,
          'hold': self.hold
        }
        return config

Schließlich müssen Sie beim Laden des Modells a passieren WarmupCosineDecay als benutzerdefiniertes Objekt:

model = keras.models.load_model('weights.h5', 
                                custom_objects={'WarmupCosineDecay', WarmupCosineDecay})

Zusammenfassung

In diesem Leitfaden haben wir einen Blick auf die Intuition hinter Learning Rate Warmup geworfen – eine gängige Technik zur Manipulation der Lernrate beim Training neuronaler Netze.

Wir haben eine Lernratenaufwärmung mit Kosinusabfall implementiert, die häufigste Art der LR-Reduktion gepaart mit Aufwärmphase. Sie können jede andere Funktion zur Reduzierung implementieren oder die Lernrate überhaupt nicht reduzieren – und es anderen Callbacks überlassen, wie z ReduceLROnPlateau(). Wir haben das Aufwärmen der Lernrate als Keras Callback sowie als Keras Optimizer Schedule implementiert und die Lernrate über die Epochen aufgetragen.

Zeitstempel:

Mehr von Stapelmissbrauch