200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 【从零开始学习深度学习】40. 算法优化之AdaGrad算法介绍及其Pytorch实现

【从零开始学习深度学习】40. 算法优化之AdaGrad算法介绍及其Pytorch实现

时间:2024-05-30 20:23:59

相关推荐

【从零开始学习深度学习】40. 算法优化之AdaGrad算法介绍及其Pytorch实现

之前介绍的梯度下降算法中,目标函数自变量的每一个元素在相同时间步都使用同一个学习率来自我迭代。例如,假设目标函数为 f f f,自变量为一个二维向量 [ x 1 , x 2 ] ⊤ [x_1, x_2]^\top [x1​,x2​]⊤,该向量中每一个元素在迭代时都使用相同的学习率。例如,在学习率为 η \eta η的梯度下降中,元素 x 1 x_1 x1​和 x 2 x_2 x2​都使用相同的学习率 η \eta η来自我迭代:

x 1 ← x 1 − η ∂ f ∂ x 1 , x 2 ← x 2 − η ∂ f ∂ x 2 . x_1 \leftarrow x_1 - \eta \frac{\partial{f}}{\partial{x_1}}, \quad x_2 \leftarrow x_2 - \eta \frac{\partial{f}}{\partial{x_2}}. x1​←x1​−η∂x1​∂f​,x2​←x2​−η∂x2​∂f​.

通过上一篇文章动量法中我们知道,当 x 1 x_1 x1​和 x 2 x_2 x2​的梯度值有较大差别时,需要选择足够小的学习率使得自变量在梯度值较大的维度上不发散。但这样会导致自变量在梯度值较小的维度上迭代过慢。动量法依赖指数加权移动平均使得自变量的更新方向更加一致,从而降低发散的可能。

本文我们介绍AdaGrad算法,它可以根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题

目录

1. AdaGrad算法介绍1.1 AdaGrad算法特点 2. 从零实现AdaGrad算法3. Pytorch简洁实现AdaGrad算法--使用optim.Adagrad总结

1. AdaGrad算法介绍

AdaGrad算法会使用一个小批量随机梯度 g t \boldsymbol{g}_t gt​按元素平方的累加变量 s t \boldsymbol{s}_t st​。在时间步0,AdaGrad将 s 0 \boldsymbol{s}_0 s0​中每个元素初始化为0。在时间步 t t t,首先将小批量随机梯度 g t \boldsymbol{g}_t gt​按元素平方后累加到变量 s t \boldsymbol{s}_t st​:

s t ← s t − 1 + g t ⊙ g t , \boldsymbol{s}_t \leftarrow \boldsymbol{s}_{t-1} + \boldsymbol{g}_t \odot \boldsymbol{g}_t, st​←st−1​+gt​⊙gt​,

其中 ⊙ \odot ⊙是按元素相乘。接着,我们将目标函数自变量中每个元素的学习率通过按元素运算重新调整一下:

x t ← x t − 1 − η s t + ϵ ⊙ g t , \boldsymbol{x}_t \leftarrow \boldsymbol{x}_{t-1} - \frac{\eta}{\sqrt{\boldsymbol{s}_t + \epsilon}} \odot \boldsymbol{g}_t, xt​←xt−1​−st​+ϵ ​η​⊙gt​,

其中 η \eta η是学习率, ϵ \epsilon ϵ是为了维持数值稳定性而添加的常数,如 1 0 − 6 10^{-6} 10−6。这里开方、除法和乘法的运算都是按元素运算的。这些按元素运算使得目标函数自变量中每个元素都分别拥有自己的学习率。

1.1 AdaGrad算法特点

需要强调的是,小批量随机梯度按元素平方的累加变量 s t \boldsymbol{s}_t st​出现在学习率的分母项中。因此,如果目标函数有关自变量中某个元素的偏导数一直都较大,那么该元素的学习率将下降较快;反之,如果目标函数有关自变量中某个元素的偏导数一直都较小,那么该元素的学习率将下降较慢。然而,由于 s t \boldsymbol{s}_t st​一直在累加按元素平方的梯度,自变量中每个元素的学习率在迭代过程中一直在降低(或不变)。所以,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解

下面我们仍然以目标函数 f ( x ) = 0.1 x 1 2 + 2 x 2 2 f(\boldsymbol{x})=0.1x_1^2+2x_2^2 f(x)=0.1x12​+2x22​为例观察AdaGrad算法对自变量的迭代轨迹。我们实现AdaGrad算法并使用和之前动量法相同的学习率0.4。可以看到,自变量的迭代轨迹较平滑。但由于 s t \boldsymbol{s}_t st​的累加效果使学习率不断衰减,自变量在迭代后期的移动幅度较小。

%matplotlib inlineimport mathimport torchimport sysimport d2lzh_pytorch as d2ldef adagrad_2d(x1, x2, s1, s2):g1, g2, eps = 0.2 * x1, 4 * x2, 1e-6 # 前两项为自变量梯度s1 += g1 ** 2s2 += g2 ** 2x1 -= eta / math.sqrt(s1 + eps) * g1x2 -= eta / math.sqrt(s2 + eps) * g2return x1, x2, s1, s2def f_2d(x1, x2):return 0.1 * x1 ** 2 + 2 * x2 ** 2eta = 0.4d2l.show_trace_2d(f_2d, d2l.train_2d(adagrad_2d))

输出:

epoch 20, x1 -2.382563, x2 -0.158591

下面将学习率增大到2。可以看到自变量更为迅速地逼近了最优解。

eta = 2d2l.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-6for 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算法时,自变量中每个元素的学习率在迭代过程中一直在降低(或不变)。

如果文章内容对你有帮助,感谢点赞+关注!

欢迎关注下方GZH:阿旭算法与机器学习,共同学习交流~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。