Jak ustawić adaptacyjną szybkość uczenia się dla GradientDescentOptimizer?

104

Używam TensorFlow do trenowania sieci neuronowej. Oto jak inicjalizuję 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)

Chodzi o to, że nie wiem, jak ustawić regułę aktualizacji dla współczynnika uczenia lub wartości zaniku dla tego.

Jak mogę tutaj zastosować adaptacyjny współczynnik uczenia się?

wyświetlana nazwa
źródło
3
Dobrym zwyczajem jest inicjowanie wszystkich zmiennych po określeniu optymalizatora, ponieważ niektóre optymalizatory, takie jak AdamOptimizer, używają własnych zmiennych, które również wymagają zainicjowania. W przeciwnym razie może pojawić się następujący błąd:FailedPreconditionError (see above for traceback): Attempting to use uninitialized value beta2_power
JYun,
Otrzymuję ten wyżej wymieniony błąd, gdy próbuję ustawić nowy współczynnik uczenia w Tensorflow wg tf.train.GradientDescentOptimizer(new_lr).minimize(loss). Wydaje się, że ustawienie nowego tempa uczenia się wymaga zainicjowania modelu z już wyuczonymi zmiennymi. Ale nie wiem, jak to zrobić.
Siladittya

Odpowiedzi:

193

Przede wszystkim tf.train.GradientDescentOptimizerma na celu stosowanie stałej szybkości uczenia się dla wszystkich zmiennych na wszystkich etapach. TensorFlow zapewnia również gotowe do użycia adaptacyjne optymalizatory, w tym tf.train.AdagradOptimizeri oraz tf.train.AdamOptimizer, które mogą być używane jako zamienniki typu drop-in.

Jeśli jednak chcesz sterować szybkością uczenia się za pomocą zwykłego gradientu zstępującego, możesz skorzystać z faktu, że learning_rateargument dla tf.train.GradientDescentOptimizerkonstruktora może być Tensorobiektem. Umożliwia to obliczenie innej wartości współczynnika uczenia się na każdym kroku, na przykład:

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

Alternatywnie możesz utworzyć skalar, tf.Variablektóry utrzymuje współczynnik uczenia się i przypisywać go za każdym razem, gdy chcesz zmienić współczynnik uczenia.

mrry
źródło
Świetna odpowiedź. Czy można zastosować tę samą technikę do obcinania gradientu? tf.clip_by_normnie akceptuje tensora dla normy klipu, więc co powiesz na to [(tf.minimum(gv[0], ct), gv[1]) for gv in optimizer.compute_gradients(cost, vars)], gdziect = tf.placeholder('float32', shape=[])
richizy
To powinno działać, tak. (Chociaż patrząc na to tf.clip_by_norm, jedyną rzeczą, która uniemożliwia mu zaakceptowanie tensora jako danych wejściowych, jest constant_op.constant(1.0 / clip_norm). Zastąpienie tego wyrażenia math_ops.inv(clip_norm)sprawiłoby, że zadziałałoby ono z elementem zastępczym (lub jakimkolwiek innym tensorem).)
pan
@mrry Zrobiłem tak, jak powiedziałeś i trochę, jak prędkość treningu jest znacznie wolniejsza. Czy jest to oczekiwane?
tnq177
89

Tensorflow zapewnia op automatycznie zastosować rozkład wykładniczy do tensora stopy learning: tf.train.exponential_decay. Aby zapoznać się z przykładem użycia, zobacz tę linię w przykładzie modelu splotowego MNIST . Następnie użyj sugestii @ mrry powyżej, aby podać tę zmienną jako parametr learning_rate do wybranego optymalizatora.

Kluczowy fragment, na który należy zwrócić uwagę, to:

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

Zwróć uwagę na global_step=batchparametr, aby zminimalizować. To mówi optymalizatorowi, aby pomocnie zwiększał parametr „partii” za każdym razem, gdy trenuje.

dga
źródło
3
Zwykle wywoływana batchjest zmienna, która jest wywoływana global_stepi istnieje kilka wygodnych funkcji, jedna służąca do jej tworzenia tf.train.create_global_step()(która po prostu tworzy liczbę całkowitą tf.Variablei dodaje ją do tf.GraphKeys.GLOBAL_STEPkolekcji) i tf.train.get_global_step().
Lenar Hoyt
86

Algorytm zstępowania gradientu wykorzystuje stałą szybkość uczenia się, którą można zapewnić podczas inicjalizacji . Możesz przejść różne wskaźniki uczenia się w sposób pokazany przez Mrry.

Ale zamiast tego można zastosować bardziej zaawansowane optymalizatory, które mają szybszy współczynnik konwergencji i dostosowują się do sytuacji.

Oto krótkie wyjaśnienie oparte na moim zrozumieniu:

  • momentum pomaga SGD poruszać się po odpowiednich kierunkach i łagodzi oscylacje w nieistotnych. Po prostu dodaje ułamek kierunku poprzedniego kroku do bieżącego kroku. Osiąga to wzmocnienie prędkości w prawidłowym kierunku i łagodzi oscylacje w niewłaściwych kierunkach. Ułamek ten zwykle mieści się w zakresie (0, 1). Sensowne jest również użycie pędu adaptacyjnego. Na początku nauki duży pęd będzie tylko przeszkadzał w postępach, dlatego warto użyć czegoś takiego jak 0,01, a gdy wszystkie wysokie gradienty znikną, możesz użyć większego pędu. Z rozmachem jest jeden problem: kiedy jesteśmy bardzo blisko celu, w większości przypadków nasz pęd jest bardzo duży i nie wie, że powinien zwolnić. Może to powodować chybienie lub oscylowanie wokół minimów
  • Gradient przyspieszony nesterowa rozwiązuje ten problem, zaczynając zwalniać wcześnie. W pędzie najpierw obliczamy gradient, a następnie wykonujemy skok w tym kierunku wzmocniony przez pęd, jaki mieliśmy wcześniej. NAG robi to samo, ale w innej kolejności: najpierw wykonujemy duży skok w oparciu o nasze zapisane informacje, a następnie obliczamy gradient i dokonujemy niewielkiej korekty. Ta pozornie nieistotna zmiana daje znaczące praktyczne przyspieszenie.
  • AdaGrad lub gradient adaptacyjny umożliwia dostosowanie tempa uczenia się na podstawie parametrów. Wykonuje większe aktualizacje dla rzadkich parametrów i mniejsze aktualizacje dla częstych. Z tego powodu dobrze nadaje się do rzadkich danych (NLP lub rozpoznawanie obrazu). Kolejną zaletą jest to, że zasadniczo eliminuje potrzebę dostrojenia szybkości uczenia się. Każdy parametr ma swój własny współczynnik uczenia, a ze względu na specyfikę algorytmu szybkość uczenia się monotonicznie maleje. To powoduje największy problem: w pewnym momencie wskaźnik uczenia się jest tak mały, że system przestaje się uczyć
  • AdaDelta rozwiązuje problem monotonicznie malejącego tempa uczenia się w AdaGrad. W AdaGrad współczynnik uczenia się obliczono w przybliżeniu jako podzielony przez sumę pierwiastków kwadratowych. Na każdym etapie dodajesz do sumy kolejny pierwiastek kwadratowy, co powoduje, że mianownik stale się zmniejsza. W AdaDelta zamiast sumować wszystkie przeszłe pierwiastki kwadratowe używa przesuwanego okna, które pozwala na zmniejszenie sumy. RMSprop jest bardzo podobny do AdaDelta
  • Adam lub pęd adaptacyjny to algorytm podobny do AdaDelta. Ale oprócz przechowywania współczynników uczenia się dla każdego z parametrów, zapisuje również zmiany pędu dla każdego z nich oddzielnie

    A kilka wizualizacje : wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

Salvador Dali
źródło
2
Aby porównać różne optymalizatory w TensorFlow, spójrz na następujący notatnik ipython : github.com/vsmolyakov/experiments_with_python/blob/master/chp03/ ... for
Vadim Smolyakov
Bardziej zaawansowanych optymalizatorów nie należy brać „zamiast tego”, ale dodatkowo patrz stats.stackexchange.com/questions/200063/…
Dima Lituiev
@DimaLituiev czy możesz używać dwóch optymalizatorów jednocześnie? Jeśli nie, to używasz Optimizer1 zamiast Optimizer2.
Salvador Dali,
1
nie to mówię i nie o to tutaj chodziło. Sugerujesz użycie zaawansowanych optymalizatorów zamiast adaptacyjnego tempa uczenia się. Mówię, że wolałbyś używać zaawansowanych optymalizatorów oprócz adaptacyjnego tempa uczenia się
Dima Lituiev
7

Z oficjalnych dokumentów 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))
Prakash Vanapalli
źródło
0

Jeśli chcesz ustawić określone współczynniki uczenia się dla interwałów takich jak 0 < a < b < c < ... . Następnie możesz zdefiniować współczynnik uczenia się jako warunkowy tensor, zależny od kroku globalnego i przekazać to optymalizatorowi w normalny sposób.

Możesz to osiągnąć za pomocą kilku zagnieżdżonych tf.condinstrukcji, ale łatwiej jest zbudować tensor rekurencyjnie:

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

Następnie, aby go użyć, musisz wiedzieć, ile kroków szkoleniowych jest w jednej epoce, abyśmy mogli użyć kroku globalnego, aby przełączyć się we właściwym czasie, a na koniec zdefiniować żądane epoki i wskaźniki uczenia się. Więc jeśli chcę, aby współczynniki uczenia się [0.1, 0.01, 0.001, 0.0001]w przedziałach epoki [0, 19], [20, 59], [60, 99], [100, \infty]odpowiednio, zrobiłbym:

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
źródło