1. 现状:
大多数的梯度下降算法都需要选择学习率的超参数。设置学习率通常要不断调整,而较好的学习率一般是手动设置的。 学习率设置的过高会使得系统发散,但选择的过小又会使学习过程变慢。对于很多问题而言,选择一个好的学习率更像是艺术而不是科学。
2. 解决问题:
引入新的“动态学习率”来减轻原先需要反复选择学习率的重复任务。这种方法在每个维度上计算时只需要一阶导数信息,并且在每次在梯度下降的迭代计算时只增加额外少量计算量。另外,这种方法用到了一些超参数,但是我们发现这些超参数的选择对结果影响不大。这种方法的优点如下:
- 不需要人工设置学习率。
- 对超参数不敏感。
- 每维有单独的动态学习率。
- 能减小梯度下降算法的计算量。
- 对于大梯度、噪声和不同结构有较好的鲁棒性。
3. 相关工作ADAGRAD
优点
它有一个非常好的特性,就像一个二阶方法一样,它随着时间的推移在各个维度上的速度会趋于一致。这使得它非常适合训练深度网络,因为深度网络的不同层的梯度的尺度通常是不同数量级。因此,对于最优学习率应该考虑到这一点。此外,分母中的梯度和与退火算法有相同的效果,都会随着时间的推移减少学习率。
缺点
由于ADAGRAD没有考虑梯度的幅值,所以这种方法会对参数的初值和相对应的梯度敏感。如果初始梯度很大,在剩余的学习率将会变得很小。当然,可以通过增大全局学习率来解决这个问题,所以这使得ADAGRAD的学习率的选择变得很难。因为随着分母上梯度的平方不断积累,学习率会随着训练持续减小,最终会减小到零而导致训练停止。我们的ADADELTA方法有助于克服这种对超参数的选择的敏感性,同时能够避免学习率的持续下降。
4. ADADELTA 方法
该方法是基于ADAGRAD, 而且用于解决ADAGRAD的两个缺点,1) 随着训练学习率逐渐减小。2)需要人工选择全局学习率。 区别是在ADAGRAD方法中,分母从开始训练就对每一次迭代进行累加。每一个表达式都是正的,随着不断的累加,其和也不断的变大,使得每个维度上的学习率不断减小。多次迭代后,学习率会变得非常小。
不直接累加所有的梯度的平方,而是用一个宽度为w的窗口限制累加的历史梯度(即用w代替t,其中t指的是ADAGRAD中当前第t次迭代)。在窗口限制累加情况下,ADAGRAD中的分母就不会被累加到无穷大,这就变成了用最近几个的梯度来做局部预估。这就保证了若干次迭代之后学习能继续进行。
因为直接存储w个梯度的平方率有些低,因此把求和换成梯度平方的均值,我们的方法与直接计算相比计算量指数下降。
假设在t时刻的平均值为 ,然后我们计算:
其中ρ是下降常数,是同样宽为w的窗口下的梯度平方的期望值,和我们在动量方法中用的很像。在参数更新的时候我们需要计算出它的平方根,所以这就变成了求直到时间t前的梯度平方的均方根(RMS,root mean square):
至此,我们可以得出更新规则为:
算法:
算法 1 计算ADADELTA在t+1时刻的值 |
---|
需要:下降率ρ ,常数ϵ |
需要:初始参数x1 |
|
for t=1:T |
|
|
|
|
|
end for |
Code:
%matplotlib inline
import gluonbook as gb
from mxnet import nd
features, labels = gb.get_data_ch7()
def init_adadelta_states():
s_w, s_b = nd.zeros((features.shape[1], 1)), nd.zeros(1)
delta_w, delta_b = nd.zeros((features.shape[1], 1)), nd.zeros(1)
return ((s_w, delta_w), (s_b, delta_b))
def adadelta(params, states, hyperparams):
rho, eps = hyperparams['rho'], 1e-5
for p, (s, delta) in zip(params, states):
s[:] = rho * s + (1 - rho) * p.grad.square()
g = ((delta + eps).sqrt() / (s + eps).sqrt()) * p.grad
p[:] -= g
delta[:] = rho * delta + (1 - rho) * g * g
引用: