如何为 GradientDescentOptimizer 设置自适应学习率?
How to set adaptive learning rate for 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)
这里的问题是我不知道如何为学习率或衰减值设置更新规则。
这里如何使用自适应学习率?
首先,tf.train.GradientDescentOptimizer
旨在对所有步骤中的所有变量使用恒定的学习率。 TensorFlow 还提供开箱即用的自适应优化器,包括 tf.train.AdagradOptimizer
and the tf.train.AdamOptimizer
,这些可以用作直接替代品。
然而,如果你想用普通的梯度下降来控制学习率,你可以利用 tf.train.GradientDescentOptimizer
constructor 的 learning_rate
参数可以是 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
,并在每次您想要更改学习率时分配它。
Tensorflow 提供了一个自动将指数衰减应用于学习率张量的操作:tf.train.exponential_decay
. For an example of it in use, see this line in the MNIST convolutional model example。然后使用上面@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' 参数。
来自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))
梯度下降算法使用您可以在 during the initialization 中提供的恒定学习率。你可以通过Mrry展示的方式传递各种学习率。
但是你也可以使用more advanced optimizers代替它,它收敛速度更快,适应情况。
这里根据我的理解做一个简单的解释:
- momentum helps SGD 沿着相关方向导航并缓和不相关的振荡。它只是将前一步方向的一小部分添加到当前步骤。这实现了在正确方向上的速度放大并减弱了在错误方向上的振荡。该分数通常在 (0, 1) 范围内。使用自适应动量也很有意义。在开始学习时,大动量只会阻碍你的进步,所以使用 0.01 之类的值是有意义的,一旦所有高梯度消失,你就可以使用更大的动量。动量有一个问题:当我们非常接近目标时,我们的动量在大多数情况下非常高,它不知道应该减速。这可能会导致它错过或围绕最小值振荡
- nesterov 加速梯度 通过提早开始减速克服了这个问题。在动量中,我们首先计算梯度,然后在那个方向上跳跃,通过我们之前的动量放大。 NAG 做同样的事情,但顺序不同:首先我们根据存储的信息进行大跳跃,然后计算梯度并进行小幅修正。这个看似无关紧要的更改提供了显着的实际加速。
- AdaGrad 或自适应梯度允许学习率根据参数进行调整。它对不频繁的参数执行较大的更新,对频繁的参数执行较小的更新。正因为如此,它非常适合稀疏数据(NLP 或图像识别)。另一个优点是它基本上消除了调整学习率的需要。每个参数都有自己的学习率,并且由于算法的特殊性,学习率单调递减。这导致了最大的问题:在某个时间点学习率太小以至于系统停止学习
- AdaDelta解决了AdaGrad学习率单调递减的问题。在 AdaGrad 中,学习率的计算方法大致为 1 除以平方根之和。在每个阶段,您都将另一个平方根添加到总和中,这会导致分母不断减小。在 AdaDelta 中,它不是对所有过去的平方根求和,而是使用滑动 window 来减少总和。 RMSprop 与 AdaDelta
非常相似
Adam或者adaptive momentum是一种类似于AdaDelta的算法。但是除了存储每个参数的学习率之外,它还分别存储每个参数的动量变化
如果你想像 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,)
)
那么使用它需要知道单个epoch有多少训练步,这样我们就可以在合适的时候使用全局步进行切换,最后定义你想要的epoch和学习率。因此,如果我想要分别在 [0, 19], [20, 59], [60, 99], [100, \infty]
的时期间隔内学习率 [0.1, 0.01, 0.001, 0.0001]
,我会这样做:
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)
我正在使用 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)
这里的问题是我不知道如何为学习率或衰减值设置更新规则。
这里如何使用自适应学习率?
首先,tf.train.GradientDescentOptimizer
旨在对所有步骤中的所有变量使用恒定的学习率。 TensorFlow 还提供开箱即用的自适应优化器,包括 tf.train.AdagradOptimizer
and the tf.train.AdamOptimizer
,这些可以用作直接替代品。
然而,如果你想用普通的梯度下降来控制学习率,你可以利用 tf.train.GradientDescentOptimizer
constructor 的 learning_rate
参数可以是 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
,并在每次您想要更改学习率时分配它。
Tensorflow 提供了一个自动将指数衰减应用于学习率张量的操作:tf.train.exponential_decay
. For an example of it in use, see this line in the MNIST convolutional model example。然后使用上面@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' 参数。
来自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))
梯度下降算法使用您可以在 during the initialization 中提供的恒定学习率。你可以通过Mrry展示的方式传递各种学习率。
但是你也可以使用more advanced optimizers代替它,它收敛速度更快,适应情况。
这里根据我的理解做一个简单的解释:
- momentum helps SGD 沿着相关方向导航并缓和不相关的振荡。它只是将前一步方向的一小部分添加到当前步骤。这实现了在正确方向上的速度放大并减弱了在错误方向上的振荡。该分数通常在 (0, 1) 范围内。使用自适应动量也很有意义。在开始学习时,大动量只会阻碍你的进步,所以使用 0.01 之类的值是有意义的,一旦所有高梯度消失,你就可以使用更大的动量。动量有一个问题:当我们非常接近目标时,我们的动量在大多数情况下非常高,它不知道应该减速。这可能会导致它错过或围绕最小值振荡
- nesterov 加速梯度 通过提早开始减速克服了这个问题。在动量中,我们首先计算梯度,然后在那个方向上跳跃,通过我们之前的动量放大。 NAG 做同样的事情,但顺序不同:首先我们根据存储的信息进行大跳跃,然后计算梯度并进行小幅修正。这个看似无关紧要的更改提供了显着的实际加速。
- AdaGrad 或自适应梯度允许学习率根据参数进行调整。它对不频繁的参数执行较大的更新,对频繁的参数执行较小的更新。正因为如此,它非常适合稀疏数据(NLP 或图像识别)。另一个优点是它基本上消除了调整学习率的需要。每个参数都有自己的学习率,并且由于算法的特殊性,学习率单调递减。这导致了最大的问题:在某个时间点学习率太小以至于系统停止学习
- AdaDelta解决了AdaGrad学习率单调递减的问题。在 AdaGrad 中,学习率的计算方法大致为 1 除以平方根之和。在每个阶段,您都将另一个平方根添加到总和中,这会导致分母不断减小。在 AdaDelta 中,它不是对所有过去的平方根求和,而是使用滑动 window 来减少总和。 RMSprop 与 AdaDelta 非常相似
Adam或者adaptive momentum是一种类似于AdaDelta的算法。但是除了存储每个参数的学习率之外,它还分别存储每个参数的动量变化
如果你想像 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,)
)
那么使用它需要知道单个epoch有多少训练步,这样我们就可以在合适的时候使用全局步进行切换,最后定义你想要的epoch和学习率。因此,如果我想要分别在 [0, 19], [20, 59], [60, 99], [100, \infty]
的时期间隔内学习率 [0.1, 0.01, 0.001, 0.0001]
,我会这样做:
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)