1. AdaGrad算法介绍
1.1 AdaGrad算法特点
需要强调的是,小批量随机梯度按元素平方的累加变量st出现在学习率的分母项中。因此,如果目标函数有关自变量中某个元素的偏导数一直都较大,那么该元素的学习率将下降较快;反之,如果目标函数有关自变量中某个元素的偏导数一直都较小,那么该元素的学习率将下降较慢。然而,由于st一直在累加按元素平方的梯度,自变量中每个元素的学习率在迭代过程中一直在降低(或不变)。所以,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。
%matplotlib inline import math import torch import sys import d2lzh_pytorch as d2l def adagrad_2d(x1, x2, s1, s2): g1, g2, eps = 0.2 * x1, 4 * x2, 1e-6 # 前两项为自变量梯度 s1 += g1 ** 2 s2 += g2 ** 2 x1 -= eta / math.sqrt(s1 + eps) * g1 x2 -= eta / math.sqrt(s2 + eps) * g2 return x1, x2, s1, s2 def f_2d(x1, x2): return 0.1 * x1 ** 2 + 2 * x2 ** 2 eta = 0.4 d2l.show_trace_2d(f_2d, d2l.train_2d(adagrad_2d))
输出:
epoch 20, x1 -2.382563, x2 -0.158591
下面将学习率增大到2。可以看到自变量更为迅速地逼近了最优解。
eta = 2 d2l.show_trace_2d(f_2d, d2l.train_2d(adagrad_2d))
输出:
epoch 20, x1 -0.002295, x2 -0.000000
2. 从零实现AdaGrad算法
同动量法一样,AdaGrad算法需要对每个自变量维护同它一样形状的状态变量。我们根据AdaGrad算法中的公式实现该算法。
features, labels = d2l.get_data_ch7() def init_adagrad_states(): s_w = torch.zeros((features.shape[1], 1), dtype=torch.float32) s_b = torch.zeros(1, dtype=torch.float32) return (s_w, s_b) def adagrad(params, states, hyperparams): eps = 1e-6 for p, s in zip(params, states): s.data += (p.grad.data**2) p.data -= hyperparams['lr'] * p.grad.data / torch.sqrt(s + eps)
与之前小批量随机梯度下降相比,这里使用更大的学习率来训练模型。
d2l.train_ch7(adagrad, init_adagrad_states(), {'lr': 0.1}, features, labels)
输出:
loss: 0.243675, 0.049749 sec per epoch
3. Pytorch简洁实现AdaGrad算法–使用optim.Adagrad
通过名称为Adagrad
的优化器方法,我们便可使用PyTorch提供的AdaGrad算法来训练模型。
d2l.train_pytorch_ch7(torch.optim.Adagrad, {'lr': 0.1}, features, labels)
输出:
loss: 0.243147, 0.040675 sec per epoch
总结
- AdaGrad算法在迭代过程中不断调整学习率,并让目标函数自变量中每个元素都分别拥有自己的学习率。
- 使用AdaGrad算法时,自变量中每个元素的学习率在迭代过程中一直在降低(或不变)。