最优化是一个十分困难的问题,通常要精心设计一个目标函数及相关约束,同时还要确保所要优化的问题为凸函数,但现实中的问题大多为非凸函数,针对非凸优化问题,这里有一些基本的优化方法: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\]