Come impostare la velocità di apprendimento adattivo per GradientDescentOptimizer?


104

Utilizzo TensorFlow per addestrare una rete neurale. Ecco come sto inizializzando 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)

Il fatto è che non so come impostare una regola di aggiornamento per il tasso di apprendimento o un valore di decadimento per quello.

Come posso utilizzare un tasso di apprendimento adattivo qui?


3
È una buona abitudine inizializzare tutte le variabili dopo aver specificato l'ottimizzatore perché alcuni ottimizzatori come AdamOptimizer utilizzano le proprie variabili che devono essere inizializzate. Altrimenti potresti ricevere un errore simile al seguente:FailedPreconditionError (see above for traceback): Attempting to use uninitialized value beta2_power
JYun

Ricevo questo errore sopra menzionato, quando cerco di impostare un nuovo tasso di apprendimento in Tensorflow da tf.train.GradientDescentOptimizer(new_lr).minimize(loss). Sembra che l'impostazione di un nuovo tasso di apprendimento richieda l'inizializzazione del modello con le variabili già addestrate. Ma non riesco a capire come farlo.
Siladittya

Risposte:


193

Innanzitutto, tf.train.GradientDescentOptimizerè progettato per utilizzare un tasso di apprendimento costante per tutte le variabili in tutti i passaggi. TensorFlow fornisce anche ottimizzatori adattivi pronti all'uso, tra cui il tf.train.AdagradOptimizere il tf.train.AdamOptimizer, e questi possono essere usati come sostituti drop-in.

Tuttavia, se si desidera controllare la velocità di apprendimento con una discesa del gradiente altrimenti vanigliata, è possibile trarre vantaggio dal fatto che l' learning_rateargomento del tf.train.GradientDescentOptimizercostruttore può essere un Tensoroggetto. Ciò consente di calcolare un valore diverso per la velocità di apprendimento in ogni fase, ad esempio:

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

In alternativa, puoi creare uno scalare tf.Variableche trattiene il tasso di apprendimento e assegnarlo ogni volta che desideri modificare il tasso di apprendimento.


Bella risposta. La stessa tecnica può essere utilizzata per il ritaglio del gradiente? tf.clip_by_normnon accetta un tensore per la norma della clip, quindi che ne dici di fare [(tf.minimum(gv[0], ct), gv[1]) for gv in optimizer.compute_gradients(cost, vars)], dovect = tf.placeholder('float32', shape=[])
richizy

Dovrebbe funzionare, sì. (Anche se guardando tf.clip_by_norm, l'unica cosa che gli impedisce di accettare un tensore come input è il constant_op.constant(1.0 / clip_norm). Sostituire quell'espressione con math_ops.inv(clip_norm)lo farebbe funzionare con un segnaposto (o qualsiasi altro tensore) input.)
mrry

@mrry ho fatto come hai detto e in qualche modo la velocità di allenamento è molto più lenta. È previsto per favore?
tnq177

89

Tensorflow fornisce un op per applicare automaticamente un decadimento esponenziale a un tensore tasso di apprendimento: tf.train.exponential_decay. Per un esempio in uso, vedere questa riga nell'esempio del modello convoluzionale MNIST . Quindi usa il suggerimento di @ mrry sopra per fornire questa variabile come parametro learning_rate al tuo ottimizzatore preferito.

L'estratto chiave da esaminare è:

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

Notare il global_step=batchparametro per ridurre al minimo. Questo dice all'ottimizzatore di incrementare utilmente il parametro "batch" per te ogni volta che si allena.


3
Di solito, la variabile che chiami batchviene chiamata global_stepe ci sono diverse funzioni utili, una per crearla tf.train.create_global_step()(che crea semplicemente un numero intero tf.Variablee lo aggiunge alla tf.GraphKeys.GLOBAL_STEPcollezione) e tf.train.get_global_step().
Lenar Hoyt

86

L'algoritmo di discesa del gradiente utilizza la velocità di apprendimento costante che è possibile fornire durante l'inizializzazione . Puoi superare vari tassi di apprendimento in un modo mostrato da Mrry.

Ma al posto di esso puoi anche utilizzare ottimizzatori più avanzati che hanno una velocità di convergenza più rapida e si adattano alla situazione.

Ecco una breve spiegazione basata sulla mia comprensione:

  • lo slancio aiuta SGD a navigare lungo le direzioni rilevanti e ammorbidisce le oscillazioni nell'irrilevante. Aggiunge semplicemente una frazione della direzione del passaggio precedente a un passaggio corrente. Ciò ottiene l'amplificazione della velocità nella direzione corretta e ammorbidisce l'oscillazione nelle direzioni sbagliate. Questa frazione è generalmente compresa nell'intervallo (0, 1). Ha anche senso usare lo slancio adattivo. All'inizio dell'apprendimento un grande slancio ostacolerà solo i tuoi progressi, quindi ha senso usare qualcosa come 0,01 e una volta che tutti i gradienti alti sono scomparsi, puoi usare uno slancio più grande. C'è un problema con lo slancio: quando siamo molto vicini all'obiettivo, il nostro slancio nella maggior parte dei casi è molto alto e non sa che dovrebbe rallentare. Ciò può far sì che manchi o oscilli intorno ai minimi
  • Il gradiente accelerato di nesterov supera questo problema iniziando a rallentare presto. Nella quantità di moto calcoliamo prima il gradiente e poi facciamo un salto in quella direzione amplificato dalla quantità di moto che avevamo in precedenza. NAG fa la stessa cosa ma in un altro ordine: all'inizio facciamo un grande salto in base alle nostre informazioni memorizzate, quindi calcoliamo il gradiente e apportiamo una piccola correzione. Questo cambiamento apparentemente irrilevante dà significativi aumenti pratici.
  • AdaGrad o il gradiente adattivo consente al tasso di apprendimento di adattarsi in base ai parametri. Esegue aggiornamenti più grandi per parametri poco frequenti e aggiornamenti più piccoli per parametri frequenti. Per questo motivo è adatto per dati sparsi (NLP o riconoscimento di immagini). Un altro vantaggio è che sostanzialmente limita la necessità di regolare il tasso di apprendimento. Ogni parametro ha una propria velocità di apprendimento e, a causa delle peculiarità dell'algoritmo, la velocità di apprendimento è in diminuzione monotona. Questo causa il problema più grande: a un certo punto il tasso di apprendimento è così piccolo che il sistema smette di imparare
  • AdaDelta risolve il problema della diminuzione monotona del tasso di apprendimento in AdaGrad. In AdaGrad il tasso di apprendimento è stato calcolato approssimativamente come uno diviso per la somma delle radici quadrate. Ad ogni fase si aggiunge un'altra radice quadrata alla somma, che fa diminuire costantemente il denominatore. In AdaDelta invece di sommare tutte le radici quadrate passate utilizza la finestra scorrevole che consente di diminuire la somma. RMSprop è molto simile a AdaDelta
  • Adam o slancio adattivo è un algoritmo simile a AdaDelta. Ma oltre a memorizzare i tassi di apprendimento per ciascuno dei parametri, memorizza anche le modifiche dello slancio per ciascuno di essi separatamente

    A poche visualizzazioni : inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine


2
Per confrontare i diversi ottimizzatori in TensorFlow, dai un'occhiata al seguente notebook ipython: github.com/vsmolyakov/experiments_with_python/blob/master/chp03/… per
Vadim Smolyakov

Ottimizzatori più avanzati non devono essere presi "al posto", ma in aggiunta, vedere stats.stackexchange.com/questions/200063/…
Dima Lituiev

@DimaLituiev puoi usare due ottimizzatori contemporaneamente? In caso contrario, stai usando optimizer1 invece di optimizer2.
Salvador Dali

1
non è quello che sto dicendo, e non era la domanda qui. Suggerisci di utilizzare ottimizzatori avanzati invece del tasso di apprendimento adattivo. Sto dicendo che preferiresti utilizzare ottimizzatori avanzati oltre al tasso di apprendimento adattivo
Dima Lituiev

7

Dai documenti ufficiali di 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

Se vuoi impostare tassi di apprendimento specifici per intervalli di epoche come 0 < a < b < c < .... Quindi puoi definire il tuo tasso di apprendimento come un tensore condizionale, condizionato al passo globale, e alimentarlo normalmente all'ottimizzatore.

Puoi ottenere ciò con un mucchio di tf.condistruzioni annidate , ma è più facile costruire il tensore in modo ricorsivo:

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

Quindi per usarlo è necessario sapere quanti passaggi di formazione ci sono in una singola epoca, in modo da poter utilizzare il passaggio globale per passare al momento giusto e infine definire le epoche e le velocità di apprendimento desiderate. Quindi, se voglio i tassi di apprendimento [0.1, 0.01, 0.001, 0.0001]durante gli intervalli di epoca [0, 19], [20, 59], [60, 99], [100, \infty]rispettivamente di, farei:

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.