Як встановити адаптивний рівень навчання для GradientDescentOptimizer?


104

Я використовую TensorFlow для тренування нейронної мережі. Ось як я ініціалізую 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)

Вся справа в тому, що я не знаю, як встановити правило оновлення для швидкості навчання або значення занепаду для цього.

Як тут можна використовувати адаптивний курс навчання?


3
Корисна звичка ініціалізувати всі змінні після того, як ви вкажете свій оптимізатор, оскільки деякі оптимізатори, такі як AdamOptimizer, використовують власні змінні, які також потрібно ініціалізувати. В іншому випадку ви можете отримати повідомлення про помилку , що виглядає наступним чином :FailedPreconditionError (see above for traceback): Attempting to use uninitialized value beta2_power
JYun

Я отримую цю вищезгадану помилку, коли я намагаюся встановити новий рівень навчання в Tensorflow від tf.train.GradientDescentOptimizer(new_lr).minimize(loss). Здається, встановлення нового рівня навчання вимагає ініціалізації моделі з уже навченими змінними. Але не можу зрозуміти, як це зробити.
Силадіття

Відповіді:


193

Перш за все, tf.train.GradientDescentOptimizerпризначений для використання постійної швидкості навчання для всіх змінних на всіх етапах. TensorFlow також пропонує нестандартні адаптивні оптимізатори, включаючи і tf.train.AdagradOptimizerта tf.train.AdamOptimizer, і вони можуть бути використані в якості замінного меню.

Однак якщо ви хочете контролювати швидкість навчання з пониженням ванільного градієнта, ви можете скористатися тим, що learning_rateаргументом для tf.train.GradientDescentOptimizerконструктора може бути Tensorоб'єкт. Це дозволяє обчислити різне значення для рівня навчання на кожному кроці, наприклад:

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

Крім того, ви можете створити скаляр, tf.Variableякий утримує ступінь навчання, і призначити його щоразу, коли ви хочете змінити рівень навчання.


Чудова відповідь. Чи можна використовувати ту саму техніку для градієнтного відсікання? tf.clip_by_normне приймає тензор для норми кліпу, то як щодо справи [(tf.minimum(gv[0], ct), gv[1]) for gv in optimizer.compute_gradients(cost, vars)], деct = tf.placeholder('float32', shape=[])
richizy

Це повинно працювати, так. (Хоча дивлячись на це tf.clip_by_norm, єдине, що заважає йому прийняти тензор як вхід, - це constant_op.constant(1.0 / clip_norm). Заміна цього виразу math_ops.inv(clip_norm)змусить його працювати із заповненням (або будь-яким іншим тензором).)
mrry

@mrry Я зробив, як ви сказали, і деякі, як швидкість тренувань значно повільніша. Чи очікується, будь ласка?
tnq177

89

Tensorflow забезпечує опи автоматично застосовувати експонентний розпад з тензором швидкості навчання: tf.train.exponential_decay. Для прикладу його використання див. Цей рядок на прикладі згорткової моделі MNIST . Потім скористайтеся пропозицією @ mrry, поданою вище, щоб надати цю змінну як параметр learning_rate вашому оптимізатору за вибором.

Основний уривок, на який слід звернути увагу:

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

Зверніть увагу на global_step=batchпараметр для мінімізації. Це підказує оптимізатору корисно збільшувати параметр "batch" для кожного разу, коли він тренується.


3
Зазвичай batchназивається змінна, яку ви викликаєте , global_stepі є кілька функцій зручності, одна для їх створення tf.train.create_global_step()(яка просто створює ціле число tf.Variableі додає їх до tf.GraphKeys.GLOBAL_STEPколекції) і tf.train.get_global_step().
Ленар Хойт

86

Алгоритм спуску градієнта використовує постійну швидкість навчання, яку ви можете надати під час ініціалізації . Ви можете передавати різні показники навчання способом, показаним Брі.

Але замість цього ви можете також використовувати більш просунуті оптимізатори, які мають швидший коефіцієнт конвергенції та адаптуються до ситуації.

Ось коротке пояснення на основі мого розуміння:

  • імпульс допомагає SGD орієнтуватися по відповідних напрямках і пом’якшує коливання в неактуальному. Він просто додає частину напрямку попереднього кроку до поточного кроку. Це досягає посилення швидкості в правильному напрямку і пом’якшує коливання в неправильних напрямках. Ця частка зазвичай знаходиться в межах (0, 1). Також має сенс використовувати пристосувальний імпульс. На початку навчання великий імпульс буде лише перешкоджати вашому прогресу, тому максимум сенсу використовувати щось на зразок 0,01, і як тільки всі високі градієнти зникнуть, ви можете використовувати більший імпульс. Є одна проблема з імпульсом: коли ми дуже близько до мети, наш імпульс у більшості випадків дуже високий, і він не знає, що він повинен сповільнюватися. Це може змусити його пропустити або коливатися навколо мінімумів
  • Нестеров прискорений градієнт долає цю проблему, починаючи рано сповільнюватися. У імпульсі ми спочатку обчислюємо градієнт, а потім робимо стрибок у тому напрямку, посилений будь-яким імпульсом, який ми мали раніше. NAG робить те ж саме, але в іншому порядку: спочатку ми робимо великий стрибок на основі нашої збереженої інформації, а потім обчислюємо градієнт і робимо невелику корекцію. Ця, здавалося б, неактуальна зміна дає значні практичні прискорення.
  • AdaGrad або адаптивний градієнт дозволяє швидкості навчання адаптуватися на основі параметрів. Він виконує більші оновлення для рідкісних параметрів і менші оновлення для частого. Через це він добре підходить для розріджених даних (NLP або розпізнавання зображень). Ще одна перевага полягає в тому, що це в основному ілюструє необхідність налаштування рівня навчання. Кожен параметр має свою ступінь навчання і завдяки особливостям алгоритму рівень навчання монотонно знижується. Це спричиняє найбільшу проблему: у якийсь момент рівень навчання настільки малий, що система припиняє навчання
  • AdaDelta вирішує проблему монотонно зниження рівня навчання в AdaGrad. В AdaGrad швидкість навчання обчислювали приблизно як одиницю, поділену на суму квадратних коренів. На кожному етапі ви додаєте ще один квадратний корінь до суми, через що знаменник постійно зменшується. В AdaDelta замість підсумовування всіх минулих квадратних коренів він використовує розсувне вікно, що дозволяє зменшити суму. RMSprop дуже схожий на AdaDelta
  • Адам або імпульс адаптації - це алгоритм, подібний до AdaDelta. Але крім збереження темпів навчання для кожного з параметрів, він також зберігає зміни імпульсу для кожного з них окремо

    Через кілька візуалізацій : введіть тут опис зображення введіть тут опис зображення


2
Для порівняння різних оптимізаторів у TensorFlow подивіться на наступний ноутбук ipython : github.com/vsmolyakov/experiment_with_python/blob/master/chp03/… для
Вадим Смоляков

Більш просунуті оптимізатори не слід приймати «замість», але крім того, див. Stats.stackexchange.com/questions/200063/…
Діма Літуєв,

@DimaLituiev Ви можете використовувати два оптимізатори одночасно? Якщо ні, то ви використовуєте optimizer1 замість optimizer2.
Сальвадор Далі

1
це не те, що я говорю, і тут не було питання. Ви пропонуєте використовувати розширені оптимізатори замість адаптивного курсу навчання. Я кажу, що ви краще скористаєтеся оптимізаторами на додачу до адаптивного курсу навчання
Діма Літуєв,

7

З 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

Якщо ви хочете встановити конкретні темпи навчання для інтервалів епох, як 0 < a < b < c < .... Тоді ви можете визначити свій рівень навчання як умовний тензор, що залежить від глобального кроку, і подати це як звичайне для оптимізатора.

Ви можете досягти цього за допомогою купки вкладених tf.condвисловлювань, але простіше побудувати тензор рекурсивно:

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

Потім для його використання потрібно знати, скільки навчальних етапів відбувається за одну епоху, щоб ми могли використовувати глобальний крок для перемикання в потрібний час і, нарешті, визначити потрібні епохи та темпи навчання. Отже, якщо я хочу, щоб рівень навчання [0.1, 0.01, 0.001, 0.0001]протягом епох інтервалів, [0, 19], [20, 59], [60, 99], [100, \infty]відповідно, я би зробив:

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.