最优化是一个十分困难的问题,通常要精心设计一个目标函数及相关约束,同时还要确保所要优化的问题为凸函数,但现实中的问题大多为非凸函数,针对非凸优化问题,这里有一些基本的优化方法:SGD、Momentum、AdaGrad、RMSProp及Adam等
随机梯度下降(Stochastic Gradient Descent, SGD)
// 随机梯度下降
给定数据集$X=\\{x^{(1)},x^{(2)},...,x^{(n)}\\}$, 数据集标记$Y=\\{y^{(1)}, y^{(2)},...,y^{(n)}\\}$
学习器$f(x;w)$, 学习率(步长)$\alpha$
For 迭代足够多次
{
随机选择数据: $\\{x^{(j)}, y^{(j)}\\}$
计算损失梯度: $\nabla\mathbf{w}=\frac{\partial{L(y^{(j)},f(x^{(j)};w))}}{\partial{w}}$
修改权重: $\mathbf{w_i}=\mathbf{w_i}-\alpha\nabla\mathbf{w}$
}
以上是从数据集中随机选择一条数据进行梯度下降,故在训练过程中会出现很强的随机现象,为了避免这种随机性,可以选择多条数据进行梯度计算,之后再取平均值。
对于学习率,在上面的算法中,学习率一直保持不变,这在训练后期会造成算法在最优解附近振荡的现象,为了消除或缓解这种情况,我们可以在靠近最优解周围时尽可能地减小学习率
综合以上可得以下梯度下降算法
// 学习率衰减最小批量梯度下降
给定数据集$X=\\{x^{(1)},x^{(2)},...,x^{(n)}\\}$, 数据集标记$Y=\\{y^{(1)}, y^{(2)},...,y^{(n)}\\}$
随机采样$m$条数据,训练周期$k$,学习率衰减最低值$b$,学习器$f(x;w)$
初始学习率(步长)$\alpha_0$
For $i <= k$
{
随机采样$m$条数据: $\\{(x^{(i)},y^{(i)}),...,(x^{(m)},y^{(m)})\\}$
计算采样数据平均损失值梯度: $\nabla \mathbf{w} = \frac{1}{m}\sum^m_{j=1}\frac{\partial{L(y^{(j)},f(x^{(j)};w)})}{\partial{\mathbf{w}}}$
计算衰减学习率: $a_i=(i-\frac{i}{k})a_0+\frac{i}{k}b$
修改网络权重: $\mathbf{w}_i=\mathbf{w}_i-\alpha\nabla\mathbf{w}$
}
动量学习法(Momentum)
上面的算法虽然解决了在最优解附近振荡以及随机性的问题,但却不能保证算法找到的解为全局最优解,算法随后有可能找到的是局部最优解,即为鞍点。
为了跳出鞍点,可以借助物理上的概念——动量,冲出鞍点,故有以下动量随机梯度下降法
// 动量学习法
给定数据集$X=\\{x^{(1)},x^{(2)},...,x^{(n)}\\}$, 数据集标记$Y=\\{y^{(1)}, y^{(2)},...,y^{(n)}\\}$
初始速度$v$,随机采样数据大小$m$,训练周期$k$
学习器$f(x;w)$,初始学习率$\alpha$,初始动量参数$\beta$
For $i <= k$
{
随机采样$m$条数据: $\\{(x^{(i)},y^{(i)}),...,(x^{(m)},y^{(m)})\\}$
计算采样数据平均损失值梯度: $\nabla \mathbf{w} = \frac{1}{m}\sum^m_{j=1}\frac{\partial{L(y^{(j)},f(x^{(j)};w)})}{\partial{\mathbf{w}}}$
更新速度: $v=\beta v-\alpha\nabla\mathbf{w}$
更新参数: $\mathbf{w}=\mathbf{w}+v$
}
在实践中,常用的$\beta$取值可为0.5,0.9或0.99,根据具体问题进行调试,但对于$\beta$的调整,并没有$\alpha$的调整重要,因此不太需要作为超参数进行选择,一般取值适当即可。动量学习法在训练后期会出现轻微振荡。
NAG(Nesterov accelerated gradient)
为了解决动量学习法会出现轻微振荡的问题,NAG用$\mathbf{w}-\beta v_{t-1}$近似作为参数下一步会变成的值,故计算梯度时是在未来的位置上,在稀疏数据上表现很好。更新速度表示如下:
$$ v_t = \beta v_{t-1}+\alpha\nabla_\mathbf{w} J(\mathbf{w}-\beta v_{t-1}) $$其中$J(\cdot)$为损失函数。NAG在梯度方向将要改变时,可提前预知,从而减弱这个过程,减少无用迭代。
AdaGrad、Adelta和RMSProp
以上的算法都使用一个全局学习率,所有的参数都是统一步伐整齐向前,但网络中的参数可能不会同时有一致的下降梯度和方向,以下算法针对每个参数单独配置学习率
AdaGrad
该算法其实就是将每一维各自的历史梯度的平方叠加起来,然后在更新的时候除以该历史梯度即可(使用平方的原因是去除梯度的符号,只对梯度的量进行累加)
$$cache_i = cache_i+(\nabla\mathbf{w}_i)^2$$更新参数:
$$\mathbf{w}_i=\mathbf{w}_i-\frac{\alpha}{\sqrt{cache_i}+\delta}\nabla\mathbf{w}_i$$其中$\delta=10^{-7}$, 防止除零导致数值溢出
AdaGrad使得参数在累积的梯度量较小时(<1),放大学习率,使得网络的训练更加快速,在梯度的累积量较大时(>1),缩小学习率,延缓网络训练
但AdaGrad随着epoch的增长,学习率降低得很快,即该算法很容易过分降低学习率
Adelta
该方法对Adgard方法中随迭代次数的增多,学习率会变得非常小的情况进行了改进,主要是将$cache$更换为过去梯度平方的衰减平均值。参数更新公式如下:
$$ \begin{aligned} \mathbf{w}_t &= \mathbf{w}_{t-1} - \frac{\alpha}{\sqrt{E[g^2]_t}+\delta}g_t \\ E[g^2]_t &= \frac{1}{t}\sum_{i=1}^t g_i^2 \\ g_t &= \nabla\mathbf{w}_t \end{aligned} $$这个分母相当于梯度的均方根(数理统计中,均方根为数据平方的平均值再开方)。故可简写为下式:
$$ \mathbf{w}_t = \mathbf{w}_{t-1}-\frac{\alpha}{RMS[g]_t}g_t $$求平均值部分可以更换为增量式,并引入超参数$\gamma$(一般设定为0.9)来衡量过去与现在梯度的重要性:
$$ E[g^2]_t = \gamma E[g^2]_{t-1}+(1-\gamma)g_t^2 $$还可将学习率更换为$RMS[\Delta\mathbf{w}]$,这样就不需要预设学习率。
$$ \begin{aligned} \Delta\mathbf{w}_t &= -\frac{RMS[\Delta\mathbf{w}]_{t-1}}{RMS[g]_t}g_t \\ \mathbf{w}_t &= \mathbf{w}_{t-1}+\Delta\mathbf{w}_t \\ \end{aligned} $$RMSProp
为了解决AdaGrad学习率衰减过快的问题,RMSProp算法引入了衰减因子,在进行梯度累积时会对“过去”和“现在”做一个权衡,通过$\beta$来调节衰减量,常用的取值有0.9或0.5
$$cache_i=\beta cache_i+(1-\beta)(\nabla \mathbf{w}_i)^2$$在参数更新阶段,和AdaGrad相同
$$\mathbf{w}_i=\mathbf{w}_i-\frac{\alpha}{\sqrt{cache_i}+\delta}\nabla\mathbf{w}_i$$Adam
该算法是Momentum+RMSProp的微调版本,默认情况下,推荐使用这种优化方法
在开始时梯度会非常小,$r$和$v$经常会接近于0,因此我们还需要对$r$和$v$进行调整
$$ \begin{aligned} vb=\frac{v}{1-\beta^t_1} \\ rb=\frac{r}{1-\beta^t_2} \end{aligned} $$其中$t$表示训练次数,因此该算法仅在训练的前几轮中根据衰减因子来放大各自值,很快$vb$,$rb$会衰减为$v$,$r$
// Adam
给定数据集$X=\\{x^{(1)},x^{(2)},...,x^{(n)}\\}$, 数据集标记$Y=\\{y^{(1)}, y^{(2)},...,y^{(n)}\\}$
初始速度$v$,随机采样数据大小$m$,训练周期$k$
学习器$f(x;w)$,初始学习率$\alpha$,初始动量参数$\beta_1$
学习率衰减参数$\beta_2$, $\delta=10^{-7}$
For $i <= k$
随机采样$m$条数据: $\\{(x^{(i)},y^{(i)}),...,(x^{(m)},y^{(m)})\\}$
计算当前采样数据梯度: $g = \frac{1}{m}\sum^m_{j=1}\frac{\partial{L(y^{(j)},f(x^{(j)};w)})}{\partial{\mathbf{w}}}$
更新当前速度: $v=\beta_1 v+(1-\beta_1)g$
更新当前学习率: $r=\beta_2 r+(1-\beta_2)g^2$
更新训练次数: $t=t+1$
$$ \begin{aligned} vb=\frac{v}{1-\beta^t_1} \\ rb=\frac{r}{1-\beta^t_2} \end{aligned} $$更新新参数:
$$w=w-\frac{\alpha}{\sqrt{rb}+\delta}vb$$