Как установить адаптивную скорость обучения для GradientDescentOptimizer?
Я использую 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)
Дело в том, что я не знаю, как установить правило обновления для скорости обучения или значения распада для этого.
Как я могу использовать скорость адаптивного обучения здесь?
Ответы
Ответ 1
Прежде всего, 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
, который содержит скорость обучения, и назначать его каждый раз, когда вы хотите изменить скорость обучения.
Ответ 2
Tensorflow обеспечивает автоматическое применение экспоненциального распада к тензору скорости обучения: tf.train.exponential_decay
. Пример его использования см. В этой строке в примере сверточной модели MNIST. Затем используйте предложение @mrry выше, чтобы предоставить эту переменную в качестве параметра learn_rate вашему оптимизатору выбора.
Ключевой отрывок для просмотра:
# Optimizer: set up a variable that 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
Алгоритм спуска градиента использует постоянную скорость обучения, которую вы можете предоставить в во время инициализации. Вы можете передавать различные учебные курсы таким образом, который показал Мрри.
Вместо этого вы также можете использовать более продвинутые оптимизаторы, которые имеют более высокую скорость конвергенции и адаптируются к ситуации.
Вот краткое объяснение, основанное на моем понимании:
- импульс помогает SGD перемещаться по соответствующим направлениям и смягчает колебания в нерелевантности. Он просто добавляет часть направления предыдущего шага к текущему шагу. Это обеспечивает усиление скорости в правильном направлении и смягчает колебания в неправильных направлениях. Эта доля обычно находится в диапазоне (0, 1). Также имеет смысл использовать адаптивный импульс. В начале обучения большой импульс будет только мешать вашему прогрессу, поэтому имеет смысл использовать что-то вроде 0,01, и как только все градиенты исчезнут, вы можете использовать больший импульс. Есть одна проблема с импульсом: когда мы очень близки к цели, наш импульс в большинстве случаев очень высок, и он не знает, что он должен замедляться. Это может привести к пропуску или колебанию вокруг минимумов.
- Нестеров ускоренный градиент преодолевает эту проблему, начиная рано замедляться. В импульсе мы сначала вычисляем градиент, а затем делаем скачок в этом направлении, усиленный каким-либо импульсом, который мы имели ранее. NAG делает то же самое, но в другом порядке: сначала мы делаем большой прыжок на основе нашей хранимой информации, а затем вычисляем градиент и делаем небольшую коррекцию. Это, казалось бы, неуместное изменение дает значительные практические ускорения.
- AdaGrad или адаптивный градиент позволяет адаптировать курс обучения на основе параметров. Он выполняет большие обновления для нечастых параметров и небольших обновлений для частых. Из-за этого он хорошо подходит для разреженных данных (NLP или распознавание изображений). Другим преимуществом является то, что он в основном лимитирует необходимость настройки скорости обучения. Каждый параметр имеет собственную скорость обучения, и из-за особенностей алгоритма скорость обучения монотонно уменьшается. Это вызывает самую большую проблему: в некоторый момент времени скорость обучения настолько мала, что система перестает учиться
- AdaDeltastrong > решает проблему монотонно уменьшающейся скорости обучения в AdaGrad. В AdaGrad коэффициент обучения был рассчитан приблизительно как один, деленный на сумму квадратных корней. На каждом этапе вы добавляете еще один квадратный корень в сумму, что приводит к тому, что знаменатель постоянно уменьшается. В AdaDelta вместо суммирования всех прошлых квадратных корней он использует скользящее окно, которое позволяет уменьшить сумму. RMSprop очень похож на AdaDeltali >
-
Adam или адаптивный импульс - это алгоритм, подобный AdaDelta. Но помимо хранения скоростей обучения для каждого из параметров он также сохраняет изменения импульса для каждого из них отдельно.
A несколько визуализаций:
![введите описание изображения здесь]()
Ответ 4
Из официальных документов tendorflow
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))
Ответ 5
Если вы хотите установить конкретные скорости обучения для интервалов эпох, например, 0 < a < b < c <...
Затем вы можете определить свою скорость обучения как условный тензор, зависящий от глобального шага, и передать его как обычно оптимизатору.
tf.cond
можно достичь с помощью нескольких вложенных операторов 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)