如何为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)。似乎,设置新的学习率需要使用已经训练好的变量来初始化模型。但是无法弄清楚该怎么做。
Siladittya

Answers:


193

首先,tf.train.GradientDescentOptimizer旨在对所有步骤中的所有变量使用恒定的学习率。TensorFlow还提供了开箱即用的自适应优化器,包括tf.train.AdagradOptimizertf.train.AdamOptimizer,这些可以用作即插即用的替代品。

但是,如果您想通过其他方式降低梯度来控制学习率,则可以利用构造函数learning_rate参数可以是对象的事实。这使您可以在每个步骤中为学习率计算一个不同的值,例如:tf.train.GradientDescentOptimizerTensor

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 2015年

应该可以,是的。(尽管看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

梯度下降算法使用您可以在初始化期间提供的恒定学习率。您可以通过Mrry展示的方式通过各种学习率。

但是,除了它,您还可以使用更高级的优化器,这些优化器具有更快的收敛速度并可以适应这种情况。

根据我的理解,这是一个简短的解释:

  • 动量 可帮助 SGD沿相关方向导航并软化无关的振荡。它只是将上一步的方向的一部分添加到当前步骤中。这样可以以正确的方向放大速度,并软化错误方向的振动。该分数通常在(0,1)范围内。使用自适应动量也很有意义。在开始学习时,很大的动力只会阻碍您的进步,因此使用0.01之类的东西就显得有些麻木了,一旦所有的高梯度消失了,您就可以使用更大的动量。动量存在一个问题:当我们非常接近目标时,在大多数情况下我们的动量很高,并且不知道它会放慢速度。这可能会导致它丢失或在最小值附近振荡
  • Nesterov加速梯度可以通过尽早降低速度来解决此问题。在动量中,我们首先计算坡度,然后在该方向上进行跳跃,并被我们之前拥有的任何动量放大。NAG的功能相同,但顺序相反:首先,我们根据存储的信息进行较大的跳跃,然后计算梯度并进行较小的校正。这种看似无关紧要的变化大大提高了实用速度。
  • AdaGrad或自适应梯度允许学习率根据参数进行自适应。它对不频繁的参数执行较大的更新,对频繁的参数执行较小的更新。因此,它非常适合稀疏数据(NLP或图像识别)。另一个优点是,它基本上不需要调整学习速度。每个参数都有其自己的学习速率,由于算法的特殊性,学习速率单调降低。这导致了最大的问题:在某些时候,学习率太小,系统停止学习
  • AdaDelta解决了AdaGrad中单调降低学习率的问题。在AdaGrad中,学习率大约是用除以平方根之和得出的。在每个阶段,您都要在总和上加上另一个平方根,这会使分母不断减小。在AdaDelta中,它使用滑动窗口而不是将所有过去的平方根求和,而是使总和减少。RMSprop与AdaDelta非常相似
  • 亚当或自适应动量是类似于AdaDelta的算法。但是,除了存储每个参数的学习率之外,它还分别存储每个参数的动量变化

    一个几可视化在此处输入图片说明 在此处输入图片说明


2
对于TensorFlow不同的优化比较看看下面IPython的笔记本:github.com/vsmolyakov/experiments_with_python/blob/master/chp03/...
瓦迪姆Smolyakov

更先进的优化不采取“而不是”但除此之外,见stats.stackexchange.com/questions/200063/...
迪马Lituiev

@DimaLituiev您可以同时使用两个优化器吗?如果否,那么您正在使用optimizer1而不是optimizer2。
萨尔瓦多·达利

1
那不是我在说的,这不是这里的问题。您建议使用高级优化器而不是自适应学习率。我要说的是,除了自适应学习率之外,您宁愿使用高级优化器
Dima Lituiev

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.