Riscaldamento della velocità di apprendimento con decadimento del coseno in Keras/TensorFlow PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Riscaldamento della frequenza di apprendimento con decadimento del coseno in Keras/TensorFlow

Il tasso di apprendimento è un iperparametro importante nelle reti di deep learning e determina direttamente il grado a cui vengono eseguiti gli aggiornamenti dei pesi, che si stima riducano al minimo una determinata funzione di perdita. In SGD:

$$
peso_{t+1} = peso_t – lr * frac{derror}{dpeso_t}
$$

Con un tasso di apprendimento di 0, il peso aggiornato è tornato a se stesso – pesot. Il tasso di apprendimento è effettivamente una manopola che possiamo ruotare per abilitare o disabilitare l'apprendimento e ha una grande influenza sulla quantità di apprendimento in corso, controllando direttamente il grado di aggiornamento del peso.

Diversi ottimizzatori utilizzano i tassi di apprendimento in modo diverso, ma il concetto alla base rimane lo stesso. Inutile dire che i tassi di apprendimento sono stati oggetto di molti studi, articoli e benchmark dei professionisti.

In generale, praticamente tutti sono d'accordo sul fatto che un tasso di apprendimento statico non lo taglierà e nella maggior parte delle tecniche che regolano il tasso di apprendimento durante l'allenamento si verifica qualche tipo di riduzione del tasso di apprendimento, che si tratti di un riduzione.

Una tecnica che negli ultimi anni ha preso piede è riscaldamento della velocità di apprendimento, che può essere abbinato praticamente a qualsiasi altra tecnica di riduzione.

Riscaldamento della velocità di apprendimento

L'idea alla base del riscaldamento della frequenza di apprendimento è semplice. Nelle prime fasi dell'allenamento, i pesi sono lontani dai loro stati ideali. Ciò significa grandi aggiornamenti su tutta la linea, che possono essere visti come "correzioni eccessive" per ciascun peso, in cui l'aggiornamento drastico di un altro può annullare l'aggiornamento di qualche altro peso, rendendo le fasi iniziali dell'allenamento più instabili.

Questi cambiamenti si appianano, ma possono essere evitati avendo un basso tasso di apprendimento all'inizio, raggiungendo uno stato non ottimale più stabile e quindi applicando un tasso di apprendimento maggiore. Puoi in qualche modo facilitare la rete negli aggiornamenti, piuttosto che colpirla con loro.

Questo è il riscaldamento del tasso di apprendimento! Iniziando con un tasso di apprendimento basso (o 0) e aumentando fino a un tasso di apprendimento iniziale (quello con cui inizieresti comunque). Questo aumento può seguire qualsiasi funzione in realtà, ma è comunemente lineare.

Dopo aver raggiunto la velocità iniziale, è possibile applicare altri programmi come il decadimento del coseno, la riduzione lineare, ecc. per abbassare progressivamente la velocità fino alla fine dell'allenamento. Il riscaldamento della frequenza di apprendimento fa solitamente parte di un programma a due orari, in cui il riscaldamento LR è il primo, mentre un altro programma prende il posto dopo che la frequenza ha raggiunto un punto di partenza.

In questa guida, implementeremo un riscaldamento della frequenza di apprendimento in Keras/TensorFlow come a keras.optimizers.schedules.LearningRateSchedule sottoclasse e keras.callbacks.Callback richiama. Il tasso di apprendimento sarà aumentato da 0 a target_lr e applicare il decadimento del coseno, poiché questo è un programma secondario molto comune. Come al solito, Keras semplifica l'implementazione di soluzioni flessibili in vari modi e la spedizione con la tua rete.

Nota: L'implementazione è generica e ispirata a Implementazione Keras di Tony dei trucchi delineati in “Borsa di trucchi per la classificazione delle immagini con le reti neurali convoluzionali".

Tasso di apprendimento con i callback Keras

Il modo più semplice per implementare qualsiasi pianificazione del tasso di apprendimento è creare una funzione che prenda il lr parametro (float32), lo passa attraverso una trasformazione e lo restituisce. Questa funzione viene quindi trasferita al LearningRateScheduler callback, che applica la funzione alla velocità di apprendimento.

In questo momento, tf.keras.callbacks.LearningRateScheduler() passa il numero di epoch alla funzione che usa per calcolare il tasso di apprendimento, che è piuttosto grossolano. Il riscaldamento LR dovrebbe essere eseguito su ciascuno passo (batch), non epoch, quindi dovremo derivare a global_step (in tutte le epoche) per calcolare invece il tasso di apprendimento e sottoclassare il Callback class per creare un callback personalizzato anziché semplicemente passare la funzione, poiché dovremo passare argomenti su ogni chiamata, cosa impossibile quando si passa semplicemente la funzione:

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

Questo approccio è favorevole quando non si desidera un alto livello di personalizzazione e non si vuole interferire con il modo in cui Keras tratta i lre soprattutto se vuoi usare callback come ReduceLROnPlateau() poiché può funzionare solo con un float-based lr. Implementiamo un riscaldamento della frequenza di apprendimento utilizzando un callback Keras, iniziando con una funzione di convenienza:

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

Ad ogni passo, calcoliamo il tasso di apprendimento e il tasso di apprendimento del riscaldamento (entrambi elementi del programma), rispetto al start_lr ed target_lr. start_lr di solito inizia a 0.0, Mentre l' target_lr dipende dalla tua rete e dall'ottimizzatore – 1e-3 potrebbe non essere una buona impostazione predefinita, quindi assicurati di impostare il tuo target che avvia LR quando chiami il metodo.

Se l' global_step nella formazione è superiore al warmup_steps abbiamo impostato – usiamo il programma di decadimento del coseno LR. In caso contrario, significa che ci stiamo ancora riscaldando, quindi viene utilizzato il riscaldamento LR. Se la hold argomento è impostato, terremo il target_lr per quel numero di passi dopo il riscaldamento e prima del decadimento del coseno. np.where() fornisce un'ottima sintassi per questo:

np.where(condition, value_if_true, value_if_false)

Puoi visualizzare la funzione con:

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)

Ora, vorremo usare questa funzione come parte di un callback e passare il passaggio dell'ottimizzatore come global_step piuttosto che un elemento di un array arbitrario, oppure puoi eseguire il calcolo all'interno della classe. Sottoclassiamo il Callback classe:

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)

Dai un'occhiata alla nostra guida pratica e pratica per l'apprendimento di Git, con le migliori pratiche, gli standard accettati dal settore e il cheat sheet incluso. Smetti di cercare su Google i comandi Git e in realtà imparare esso!

Innanzitutto, definiamo il costruttore per la classe e teniamo traccia dei suoi campi. In ogni batch terminato, aumenteremo il passaggio globale, prenderemo nota dell'LR corrente e lo aggiungeremo all'elenco di LR finora. All'inizio di ogni lotto, calcoleremo il LR usando il lr_warmup_cosine_decay() funzione e imposta quel LR come LR corrente dell'ottimizzatore. Questo viene fatto con il back-end set_value().

Fatto ciò, calcola semplicemente i passaggi totali (lunghezza/batch_size* epoche) e prendi una parte di quel numero per il tuo 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)

Infine, costruisci il tuo modello e fornisci il callback nel file fit() chiamata:

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

Al termine della formazione è possibile ottenere e visualizzare le LR modificate tramite:

lrs = callback.lrs 
plt.plot(lrs)

Riscaldamento della velocità di apprendimento con decadimento del coseno in Keras/TensorFlow PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Se si traccia la storia di un modello allenato con e senza riscaldamento LR, si noterà una netta differenza nella stabilità dell'allenamento:

Riscaldamento della velocità di apprendimento con decadimento del coseno in Keras/TensorFlow PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Tasso di apprendimento con la sottoclasse LearningRateSchedule

Un'alternativa alla creazione di una richiamata consiste nel creare a LearningRateSchedule sottoclasse, che non manipola la LR, ma la sostituisce. Questo approccio ti consente di spingere un po' di più nel back-end di Keras/TensorFlow, ma quando viene utilizzato, non può essere combinato con altri callback relativi a LR, come ReduceLROnPlateau(), che tratta gli LR come numeri in virgola mobile.

Inoltre, l'utilizzo della sottoclasse richiederà di renderla serializzabile (overload get_config()) quando diventa parte del modello, se si desidera salvare i pesi del modello. Un'altra cosa da notare è che la classe si aspetterà di lavorare esclusivamente con tf.TensorS. Per fortuna, l'unica differenza nel modo in cui lavoriamo sarà chiamare tf.func() invece di np.func() poiché le API TensorFlow e NumPy sono sorprendentemente simili e compatibili.

Riscriviamo la convenienza lr_warmup_cosine_decay() funzione per utilizzare invece le operazioni TensorFlow:

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

Con la funzione di convenienza, possiamo sottoclassare il LearningRateSchedule classe. Su ciascun __call__() (batch), calcoleremo il LR usando la funzione e lo restituiremo. Naturalmente puoi anche impacchettare il calcolo all'interno della classe sottoclasse.

La sintassi è più pulita di Callback sublcass, principalmente perché otteniamo l'accesso a step campo, piuttosto che tenerne traccia da soli, ma rende anche un po' più difficile lavorare con le proprietà della classe, in particolare, rende difficile estrarre il lr da parte di un tf.Tensor() in qualsiasi altro tipo per tenerne traccia in un elenco. Questo può essere tecnicamente aggirato eseguendo in modalità desiderosa, ma presenta un fastidio per tenere traccia di LR a scopo di debug ed è meglio evitarlo:

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

I parametri sono gli stessi e possono essere calcolati più o meno allo stesso modo di prima:


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)

E la pipeline di formazione differisce solo per il fatto che impostiamo LR dell'ottimizzatore su 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)

Se si desidera salvare il modello, il file WarmupCosineDecay il programma dovrà sovrascrivere il get_config() Metodo:

    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

Infine, quando carichi il modello, dovrai passare a WarmupCosineDecay come oggetto personalizzato:

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

Conclusione

In questa guida, abbiamo dato un'occhiata all'intuizione alla base del riscaldamento della frequenza di apprendimento, una tecnica comune per manipolare la velocità di apprendimento durante l'allenamento delle reti neurali.

Abbiamo implementato un riscaldamento della velocità di apprendimento con il decadimento del coseno, il tipo più comune di riduzione LR abbinato al riscaldamento. Puoi implementare qualsiasi altra funzione per la riduzione o non ridurre affatto il tasso di apprendimento, lasciandolo ad altri callback come ReduceLROnPlateau(). Abbiamo implementato il riscaldamento della frequenza di apprendimento come callback Keras, nonché una pianificazione Keras Optimizer e tracciato la velocità di apprendimento attraverso le epoche.

Timestamp:

Di più da Impilamento