8 RMSProp算法
上一节的关键问题之一,是学习率按预定时间表$O(t^{-\frac12})$显著降低。虽然这通常适用于凸问题,但对于深度学习中遇到的非凸问题,可能并不理想。但是,作为一个预处理器,Adagrad算法按坐标顺序的适应性是非常可取的。
问题在于,Adagrad算法将梯度$g_t$的平方累加成状态矢量$s_t =s_{t−1}+g^2_t$。因此,由于缺乏规范化,没有约束力,$s_t$持续增长,几乎上是在算法收敛时呈线性递增。
- 解决此问题的一种方法是使用$\frac {s_t}{t}$对$g_t$的合理分布来说,它将收敛。遗憾的是,限制行为生效可能需要很长时间,因为该流程记住了值的完整轨迹。
- 另一种方法是按动量法中的方式使用泄漏平均值,即$\mathbf s_t \leftarrow \gamma \mathbf s_{t-1} + (1-\gamma) \mathbf g_t^2$,其中$\gamma$>0. 保持所有其它部分不变就产生了RMSProp算法。
8.1 算法
$$\mathbf s_t \leftarrow \gamma \mathbf s_{t-1} + (1-\gamma) \mathbf g_t^2$$
$$\mathbf x_t \leftarrow \mathbf x_{t-1} - \frac{\eta}{\sqrt{\mathbf s_t + \epsilon}} \odot \mathbf g_t$$
我们现在可以自由控制学习率η,而不考虑基于每个坐标应用的缩放。就泄漏平均值而言,我们可以采用与之前在动量法中适用的相同推理。扩展$\mathbf s_t $定义可获得:
$$\begin{aligned} \mathbf s_t &= (1-\gamma) \mathbf g_t^2 + \gamma \mathbf s_{t-1} \& = (1-\gamma) \mathbf g_t^2 + \gamma (1-\gamma) \mathbf g_{t-1}^2 + \gamma^2 \mathbf s_{t-2} \& = \sum_{i=0}^{t-1} \gamma^{t-i} (1-\gamma) \mathbf g_i^2 \end{aligned}$$- 我们使用$1+\gamma+\gamma^2+\cdots = \frac{1}{1-\gamma}$。因此,权重总和标准化为1且观测值的半衰期为$\gamma^ {-1}$。让我们图像化各种数值的γ在过去40个时间步长的权重。
1 | import math |
Text(0.5, 0, 'Time')
8.2 从零开始实现
- 对$f ( \mathbf x ) = 0.1x_1^2 + 2x_2^2$使用RMSProp算法。当我们使用学习率为0.4的Adagrad算法时,变量在算法的后期阶段移动非常缓慢,因为学习率衰减太快。RMSProp算法中不会发生这种情况,因为η是单独控制的。
1 | def rmsprop_2d(x1, x2, s1, s2): |
epoch 20, x1: -0.010599, x2: 0.000000
c:\Users\admin\miniconda3\envs\d2l\lib\site-packages\torch\functional.py:478: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at C:\actions-runner\_work\pytorch\pytorch\builder\windows\pytorch\aten\src\ATen\native\TensorShape.cpp:2895.)
return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined]
8.2.1 在深度网络中使用RMSProp算法
1 | def init_rmsprop_states(feature_dim): |
loss: 0.244, 0.009 sec/epoch
8.3 简洁实现
1 | trainer = torch.optim.RMSprop |
loss: 0.242, 0.009 sec/epoch