Optimization in Deep Learning.

本文目录:

  1. 深度学习中的优化问题
  2. 基于梯度的优化算法
  3. 常用的梯度下降算法
  4. 其他优化算法

1. 深度学习中的优化问题

深度学习中的优化(optimization)问题通常是指在已有的数据集上实现最小的训练误差(training error)。记深度网络的待优化参数为$\theta$,包含$N$个训练样本$x$的数据集为$X$,损失度量为$l(x;\theta)$;则损失函数定义为:

\[L(\theta)= \frac{1}{N}\sum_{x \in X}^{}l(x;\theta)\]

优化问题建模为寻找使得损失函数为全局最小(global minima)的参数$\theta^*$:

\[\theta^*=\mathcal{\arg \min}_{\theta} L(\theta)\]

在实践中,优化深度网络存在以下困难:

  1. 网络结构多样性:深度网络是高度非线性的模型,网络结构的多样性阻碍了构造通用的优化方法;网络通常含有比较多的参数,难以优化。
  2. 非凸优化:深度网络的损失函数是高维空间的非凸函数,其损失曲面存在大量局部极小(local minima)鞍点(saddle point),这些点也满足梯度为$0$。 目前常用的优化方法大多数是基于梯度的,因此在寻找损失函数的全局最小值点的过程中,有可能会落入局部极小值点或鞍点上。

注:鞍点是指梯度为$0$但是Hessian矩阵不是半正定的点。

目前深度学习中的优化问题尚没有通用的解决方法,有许多工作尝试给出优化过程和损失函数的直觉解释:

2. 基于梯度的优化算法

深度学习中的优化问题通常用梯度下降(Gradient Descent, GD)算法求解,它是一种一阶近似方法。将神经网络的参数为$θ$初始化为$θ_0$,对损失函数$l(θ)$在$θ_0$处进行一阶Taylor展开:

\[l(θ)=l(θ_0)+\nabla_{\theta} l(θ_0)(θ-θ_0)+o(θ-θ_0)^2\]

注意到若使损失函数$l(θ)$减小,需要满足:

\[\nabla_{\theta} l(θ_0)(θ-θ_0)<0\]

当梯度$\nabla_{\theta} l(θ_0)$大于零时,应该减小$\theta$;当梯度$\nabla_{\theta} l(θ_0)$小于零时,应该增大$\theta$。综上所述,应该沿梯度$\nabla_{\theta}$的负方向更新参数。

在执行梯度下降时需要指定每次计算梯度时所使用数据的批量(batch) $\mathcal{B}$ 和学习率(learning rate) $\gamma$。若记第$t$次参数更新时的梯度为$g_t=\frac{1}{|\mathcal{B}|}\sum_{x \in \mathcal{B}}^{}\nabla_{\theta} l(θ_{t-1})$,则参数更新公式:

\[θ_t=θ_{t-1}-\gamma g_t\]

(1) 超参数的选择

① 超参数 batch size

损失函数$L(\theta)$是在整个训练集上定义的,因此计算更新梯度时需要考虑所有训练数据。这种方法称为全量梯度下降,此时batch size为整个训练集大小:$|\mathcal{B}|=N$。

通常训练数据的规模比较大,如果梯度下降在整个训练集上进行,需要比较多的计算资源;此外大规模训练集中的数据通常非常冗余。因此在实践中,把训练集分成若干批次(batch)的互补的子集,每次在一个子集上计算梯度并更新参数。这种方法称为小批量梯度下降(mini batch gradient descent),此时$|\mathcal{B}|<N$。

特别地,把每个数据看作一个批次,对应batch size=1时,称为随机梯度下降(stochastic gradient descent, SGD),此时$|\mathcal{B}|=1$。

每一批量数据的梯度都是总体数据梯度的近似,由于mini batch的数据分布和总体的分布有所差异,并且batch size越小这种差异越大;因此batch size越小,则梯度近似误差的方差越大,引入的噪声就越大,可能导致训练不稳定。

② 超参数 learning rate

学习率$\gamma$决定了梯度下降时的更新步长。学习率太大,可能会使梯度更新不收敛甚至发散(diverge);学习率太小,导致收敛速度慢。

③ 选择超参数

学习率$\gamma$和批量大小$|\mathcal{B}|$的选择可以参考以下工作:

(2) 从不同角度理解梯度下降

① 动力学角度

把神经网络建模为一个动力系统(dynamical system),则梯度下降算法描述了参数$\theta$随时间(即梯度更新轮数)的演化情况。该动力系统的规则是参数$\theta$的变化率为损失函数的梯度$g=\nabla_{\theta}l(θ)$的负值:

\[\dot θ =-g\]

该动力系统是一个保守动力系统,因此它最终可以收敛到一个不动点($\dot \theta = 0$),并可以进一步证明该稳定的不动点是一个极小值点。求解上述常微分方程ODE可以采用欧拉解法(该方法是指将方程$dy/dx=f(x,y)$转化为$y_{n+1}-y_n≈f(x_n,y_n)h$)。因此有:

\[θ_t-θ_{t-1}=-\gamma g\]

上式即为梯度下降算法的更新公式。对于小批量梯度下降,其每一批量上损失函数的梯度是总损失函数的梯度的近似估计,假设梯度估计的误差服从方差为$\sigma^2$的正态分布,则相当于在动力系统中引入高斯噪声:

\[\dot θ =-g+\sigma \xi\]

该系统用随机微分方程SDE描述,称为朗之万方程。该方程的解可以用平衡状态下的概率分布描述:

\[P(\theta) \sim \exp(-\frac{l(\theta)}{\sigma^2})\]

从上式中可以看出,当$\sigma^2$越大时,$P(\theta)$越接近均匀分布,此时参数$\theta$可能的取值范围也越大,允许探索更大比例的参数空间。当$\sigma^2$越小时,$P(\theta)$的极大值点(对应$l(\theta)$的极小值点)附近的区域越突出,则参数$\theta$落入极值点附近。在实践中,batch size越小,则参数$\sigma^2$越大。

② 逼近角度

深度学习问题的优化函数$f(x)$通常是复杂的非线性函数,优化的目的是求其全局最小值。根据逼近理论,在函数$f(x)$上的任意一点$x_n$,可以用一条近似的曲线逼近原函数。如果近似的曲线容易求得最小值,则可以用该最小值近似替代原函数的最小值。

注意到所求极值为最小值,因此在$x_n$处采用一个开口向上的抛物线$g(x)$近似替代原函数曲线$f(x)$:

\[g(x) = f(x_n) + f'(x_n)(x-x_n) + \frac{1}{2h}(x-x_n)^2\]

该抛物线$g(x)$具有如下特点:

  1. $g(x)$与原曲线$f(x)$在$x_n$处具有一阶近似,即具有相同的数值和一阶导数。
  2. $g(x)$具有容易求得的极小值点$x_n - hf’(x_n)$。

使用$g(x)$的极小值点近似替代原函数$f(x)$的极小值点,即为梯度下降算法的基本形式:

\[x_{n+1} = x_n - hf'(x_n)\]

③ 概率角度

从概率视角建模优化问题,记模型当前参数为$\theta$,优化目标为$l(\theta)$,将下一步的更新量$\Delta \theta$看作随机变量。则使得$l(\theta+\Delta \theta)$的数值越小的$\Delta \theta$出现的概率越大,用下面的分布表示:

\[p(\Delta \theta | \theta) =\frac{e^{-[l(\theta+\Delta \theta)-l(\theta)] / \alpha}}{Z(\theta)}, Z(\theta)=\int_{}^{} e^{-[l(\theta+\Delta \theta)-l(\theta)] / \alpha}d(\Delta \theta)\]

式中$Z(\theta)$是归一化因子。参数$\alpha>0$调整分布的形状;当$\alpha \to ∞$时,$p(\Delta \theta | \theta)$趋近于均匀分布,参数可以向任意方向变化;当$\alpha \to 0$时,只有使得$l(\theta+\Delta \theta)$最小的$\Delta \theta$对应的概率$p(\Delta \theta | \theta)$不为$0$,因此$\Delta \theta$将选择损失下降最快的方向。

参数的实际更新量可以选择上式的期望:

\[\Delta \theta^* = \Bbb{E}_{\Delta \theta\text{~}p(\Delta \theta | \theta)}[\Delta \theta] = \int_{}^{} p(\Delta \theta | \theta) \Delta \theta d (\Delta \theta)\]

通常$p(\Delta \theta | \theta)$很难直接求得。假设$l(\theta)$是一阶可导的,由Taylor展开得:

\[l(\theta+\Delta \theta) - l(\theta) ≈ \Delta \theta^Tg\]

其中梯度$g=\nabla_\theta l(\theta)$。若约束参数更新的步长不超过$\epsilon$,即$||\Delta \theta|| \leq \epsilon$,则概率$p(\Delta \theta | \theta)$表示为:

\[p(\Delta \theta | \theta) =\frac{e^{-\Delta \theta^Tg / \alpha}}{Z(g)}, Z(g)=\int_{||\Delta \theta|| \leq \epsilon}^{} e^{-\Delta \theta^Tg / \alpha}d(\Delta \theta)\]

概率的期望表示为:

\[\Delta \theta^* = \int_{||\Delta \theta|| \leq \epsilon}^{} \frac{e^{-\Delta \theta^Tg / \alpha}}{Z(g)} \Delta \theta d (\Delta \theta) = -\nabla_g \ln Z(g)\]

假设更新量$\Delta \theta$与梯度$g$的夹角为$\eta$,则$Z(g)$表示为:

\[Z(g)=\int_{||\Delta \theta|| \leq \epsilon}^{} e^{-||\Delta \theta|| \times ||g|| \times \cos \eta / \alpha}d(\Delta \theta)\]

上式表示一个高维球体内的积分,由于积分空间具有各向同性,因此该积分只和梯度的模长$||g||$有关,因此将积分$Z(g)$记为$Z(||g||)$,则有:

\[\Delta \theta^* = -\nabla_g \ln Z(||g||) = -\frac{Z'(||g||)}{Z(||g||)} \nabla_g ||g|| = -\frac{Z'(||g||)}{Z(||g||)} \frac{g}{||g||}\]

上式表示参数更新的最佳方向与梯度方向相反,即为梯度下降算法。

3. 常用的梯度下降算法

标准的批量梯度下降方法存在一些缺陷:

在实际应用梯度下降算法时,可以根据截止到当前步$t$的历史梯度信息\(\{g_{1},...,g_{t}\}\)计算修正的参数更新量$h_t$(比如累积动量、累积二阶矩校正学习率等),从而弥补上述缺陷。因此梯度下降算法的一般形式可以表示为:

\[\begin{align} g_t&=\frac{1}{\|\mathcal{B}\|}\sum_{x \in \mathcal{B}}^{}\nabla_{\theta} l(θ_{t-1}) \\ h_t &= f(g_{1},...,g_{t}) \\ θ_t&=θ_{t-1}-\gamma h_t \end{align}\]

下面介绍一些常见的基于梯度的优化算法,部分算法的代码实现可参考Pytorch文档。在选择合适的优化器时可参考Descending through a Crowded Valley - Benchmarking Deep Learning Optimizers

优化算法 参数定义(缺省值/初始值) 更新形式
SGD \(g_t\text{: 梯度} \\ \gamma\text{: 学习率}\) \(\begin{align} g_t&=\nabla_{\theta} l(θ_{t-1}) \\ θ_t&=θ_{t-1}-\gamma g_t \end{align}\)
RProp:根据梯度符号更新参数 \(\eta_t\text{: 弹性步长} \\ \eta_+\text{: 步长增加值}(1.2) \\ \eta_{\_}\text{: 步长减小值}(0.5) \\ \Gamma_{max} \text{: 最大步长} \\ \Gamma_{min} \text{: 最小步长}\) \(\begin{align} \eta_t &= \begin{cases} \min(\eta_{t-1}\eta_+,\Gamma_{max}) & g_{t-1}g_t>0 \\ \max(\eta_{t-1}\eta_{\_},\Gamma_{min}) & g_{t-1}g_t<0 \\ \eta_{t-1}& g_{t-1}g_t=0 \end{cases} \\θ_{t} &= θ_{t-1} -\eta_t \text{sign}(g_t) \end{align}\)
momentum:引入动量(梯度累计值) \(m_t\text{: 动量}(0) \\ \gamma\text{: 学习率} \\ \mu \text{: 衰减率}(0.9)\) \(\begin{align} m_t &= \mu m_{t-1} + g_t \\ θ_t&=θ_{t-1}-\gamma m_t \end{align}\)
NAG:引入Nesterov动量 \(m_t\text{: 动量}(0) \\ \gamma\text{: 学习率} \\ \mu \text{: 衰减率}(0.9)\) \(\begin{align} m_t &= \mu m_{t-1} + \nabla_{\theta} l(θ_{t-1}-\mu m_{t-1}) \\ θ_t&=θ_{t-1}-\gamma m_t \\-&-------------\\ m_t & = \mu m_{t-1} + g_t \\ θ_t & =θ_{t-1}-\gamma(\mu m_t + g_t) \end{align}\)
AdaGrad:使用平方梯度累计调整学习率 \(v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ \epsilon \text{: 小值}(1e-10)\) \(\begin{align} v_t &= v_{t-1} + g_t^2 \\ θ_{t} &= θ_{t-1} -\gamma \frac{g_t}{\sqrt{v_t}+\epsilon} \end{align}\)
RMSProp:使用指数滑动平均调整学习率 \(v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ \rho \text{: 衰减率}(0.99) \\ \epsilon \text{: 小值}(1e-8)\) \(\begin{align} v_t &= \rho v_{t-1} + (1-\rho)g_t^2 \\θ_{t} &= θ_{t-1} -\gamma \frac{g_t}{\sqrt{v_t}+\epsilon} \end{align}\)
Adadelta:校正RMSProp的参数更新单位 \(v_t\text{: 平方梯度}(0) \\ X_t\text{: 平方参数更新量}(0) \\ \rho \text{: 衰减率}(0.9) \\ \epsilon \text{: 小值}(1e-6)\) \(\begin{align} v_t &= \rho v_{t-1} + (1-\rho)g_t^2 \\ X_{t-1} &= \rho X_{t-2} + (1-\rho)\Delta θ_{t-1}^2 \\ Δθ_t &= -\frac{\sqrt{X_{t-1}+\epsilon}}{\sqrt{v_t+\epsilon}} g_t \\θ_{t} &= θ_{t-1} +Δθ_t \end{align}\)
Adam:结合动量与RMSProp \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.999) \\ \epsilon \text{: 小值}(1e-8)\) \(\begin{align} m_t &= β_1m_{t-1} + (1-β_1)g_t \\ v_t &= β_2v_{t-1} + (1-β_2)g_t^2 \\\hat{m}_t &= \frac{m_t}{1-β_1^t} \\ \hat{v}_t &= \frac{v_t}{1-β_2^t} \\ θ_t&=θ_{t-1}-\gamma \frac{\hat{m}_t}{\sqrt{\hat{v}_t}+ε} \end{align}\)
AdamW:解耦权重衰减正则化 \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.999) \\ \lambda \text{: 权重衰减率}(0.01) \\ \epsilon \text{: 小值}(1e-8)\) \(\begin{align} m_t &= β_1m_{t-1} + (1-β_1)g_t \\ v_t &= β_2v_{t-1} + (1-β_2)g_t^2 \\\hat{m}_t &= \frac{m_t}{1-β_1^t} \\ \hat{v}_t &= \frac{v_t}{1-β_2^t} \\ θ_t&=θ_{t-1}-\gamma (\frac{\hat{m}_t}{\sqrt{\hat{v}_t}+ε}+\lambda θ_{t-1}) \end{align}\)
Adamax:使用L-∞范数调整学习率 \(m_t\text{: 动量}(0) \\ v_t\text{: L-∞范数梯度}(0) \\ \gamma\text{: 学习率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.999) \\ \epsilon \text{: 小值}(1e-8)\) \(\begin{align} m_t &= β_1m_{t-1} + (1-β_1)g_t \\ v_t &= \max(\beta_2 v_{t-1}, |g_t|+\epsilon) \\\hat{m}_t &= \frac{m_t}{1-β_1^t} \\ θ_t&=θ_{t-1}-\gamma \frac{\hat{m}_t}{v_t} \end{align}\)
Nadam:将Nesterov动量引入Adam \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.999) \\ \psi \text{: 衰减率}(0.004) \\ \epsilon \text{: 小值}(1e-8)\) \(\begin{align} \mu_t &= \beta_1(1-\frac{1}{2}0.96^{t\psi}) \\ \mu_{t+1} &= \beta_1(1-\frac{1}{2}0.96^{(t+1)\psi}) \\ m_t &= β_1m_{t-1} + (1-β_1)g_t \\ v_t &= β_2v_{t-1} + (1-β_2)g_t^2 \\\hat{m}_t &= \frac{\mu_{t+1} m_{t}}{1-\prod_{i=1}^{t}\mu_i}+\frac{(1-\mu_t) g_t}{1-\prod_{i=1}^{t}\mu_i} \\ \hat{v}_t &= \frac{v_t}{1-β_2^t} \\ θ_t&=θ_{t-1}-\gamma \frac{\hat{m}_t}{\sqrt{\hat{v}_t}+ε} \end{align}\)
AMSGrad:改善Adam的收敛性 \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.999) \\ \epsilon \text{: 小值}(1e-8)\) \(\begin{align} m_t &= β_1m_{t-1} + (1-β_1)g_t \\ v_t &= β_2v_{t-1} + (1-β_2)g_t^2 \\\hat{m}_t &= \frac{m_t}{1-β_1^t} \\ \hat{v}_t &= \frac{v_t}{1-β_2^t} \\ \hat{v}_t^{max} &= \max(\hat{v}_{t-1}^{max},\hat{v}_t) \\ θ_t&=θ_{t-1}-\gamma \frac{\hat{m}_t}{\sqrt{\hat{v}_t^{max}}+ε} \end{align}\)
Radam:减小Adam中自适应学习率的早期方差 \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.999) \\ \epsilon \text{: 小值}(1e-8)\) \(\begin{align} \rho_∞ &= \frac{2}{1-\beta_2} - 1 \\ m_t &= β_1m_{t-1} + (1-β_1)g_t \\ v_t &= β_2v_{t-1} + (1-β_2)g_t^2 \\ \hat{m}_t &= \frac{m_t}{1-β_1^t} \\ \rho_t &= \rho_∞ - \frac{2t\beta_2^t}{1-\beta_2^t} \\ \text{if } \rho_t &> 4: \\ \hat{v}_t &= \frac{v_t}{1-β_2^t} \\ r_t &= \sqrt{\frac{(\rho_t-4)(\rho_t-2)\rho_∞}{(\rho_∞-4)(\rho_∞-2)\rho_t}} \\ θ_t&=θ_{t-1}-\gamma r_t \frac{\hat{m}_t}{\sqrt{\hat{v}_t}+ε} \\ \text{else} & :\\ θ_t&=θ_{t-1}-\gamma \hat{m}_t \end{align}\)
Adafactor:减少Adam的显存占用 \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ c \text{: 衰减系数}(0.8) \\ d \text{: 截断系数}(1) \\ \epsilon_1 \text{: 小值}(1e-30) \\ \epsilon_2 \text{: 小值}(1e-3)\) \(\begin{align} \hat{\beta}_{2,t} &= 1-\frac{1}{t^c} \\ v_{i;t}^{(r)} &= \hat{\beta}_{2,t}v_{i;t-1}^{(r)} + (1-\hat{\beta}_{2,t})\sum_{j}^{} (g_{i,j;t}^2+\epsilon_1) \\ v_{j;t}^{(c)} &= \hat{\beta}_{2,t}v_{j;t-1}^{(c)} + (1-\hat{\beta}_{2,t})\sum_{i}^{} (g_{i,j;t}^2+\epsilon_1) \\ \hat{v}_{i,j;t} &= \frac{v_{i;t}^{(r)} v_{j;t}^{(c)} }{\sum_{j}^{} v_{j;t}^{(c)} } \\ u_t &= \frac{g_t}{\sqrt{\hat{v}_t}} \\ \hat{u}_t &= u_t \frac{\max(\epsilon_2,|\theta_{t-1}|)}{\max(1,|u_t| /d)} \\ θ_t&=θ_{t-1}-\gamma \hat{u}_t \end{align}\)
SM3:减少AdaGrad的显存占用 \(v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ N \text{: 总参数量}\) \(\begin{align} v_{t}^{(i)} &= v_{t-1}^{(i)}+\mathop{\max}_{j \in S_i}{g_t^{(j)}}^2 \\ \nu_t^{(i)} &= \mathop{\min}_{j: S_j\ni i} v_{t}^{(j)} \\ \theta_t^{(i)} &= \theta_{t-1}^{(i)} - \gamma \frac{g_t^{(i)}}{\sqrt{\nu_t^{(i)}}}, \text{for all }i \in [N] \end{align}\)
AdaX:引入二阶矩的指数长期记忆 \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 学习率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.0001) \\ \epsilon \text{: 小值}(1e-8)\) \(\begin{align} m_t &= β_1m_{t-1} + (1-β_1)g_t \\ v_t &= (1+\beta_2)v_{t-1}+\beta_2 g_t^2 \\ \hat{v}_t &= \frac{v_t}{(1+\beta_2)^t-1} \\ θ_t&=θ_{t-1}-\gamma \frac{m_t}{\sqrt{\hat{v}_t}+ε} \end{align}\)
Funnelled SGDM:指数梯度更新自适应学习率 \(m_t\text{: 动量}(0) \\ p_t\text{: 坐标增益向量} \\ s_t\text{: 步长尺度} \\ \eta\text{: 学习率} \\ \beta \text{: 衰减率}\) \(\begin{align} p_{t} &= p_{t-1} \odot \exp(\gamma_p m_{t-1} \odot g_t) \\ s_{t} &= s_{t-1} \cdot \exp(\gamma_s u_{t-1} \cdot g_t) \\ m_{t} &= \beta m_{t-1}+(1-\beta)g_t \\ u_{t} &= \mu u_{t-1}+\eta(p_{t}\odot g_t) \\ \theta_{t} &= \theta_{t-1}-s_{t} u_{t} \end{align}\)
LARS:层级自适应学习率+momentum \(m_t\text{: 动量}(0) \\ \gamma\text{: 全局学习率} \\ \mu \text{: 衰减率}(0.9) \\ L \text{: 网络层数}\) \(\begin{align} m_t &= \mu m_{t-1} + g_t \\ θ_t^{(i)}&=θ_{t-1}^{(i)}-\gamma \frac{| θ_{t-1}^{(i)} |}{| m_t^{(i)} |} m_t^{(i)}, \text{for all }i \in [L] \end{align}\)
LAMB:层级自适应学习率+Adam \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 全局学习率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.999) \\ \epsilon \text{: 小值}(1e-8) \\ L \text{: 网络层数}\) \(\begin{align} m_t &= β_1m_{t-1} + (1-β_1)g_t \\ v_t &= β_2v_{t-1} + (1-β_2)g_t^2 \\\hat{m}_t &= \frac{m_t}{1-β_1^t} \\ \hat{v}_t &= \frac{v_t}{1-β_2^t} \\ θ_t^{(i)}&=θ_{t-1}^{(i)}-\gamma \frac{| θ_{t-1}^{(i)} |}{|\frac{\hat{m}_t^{(i)}}{\sqrt{\hat{v}_t^{(i)}}+ε}|} \frac{\hat{m}_t^{(i)}}{\sqrt{\hat{v}_t^{(i)}}+ε} , \text{for all }i \in [L] \end{align}\)
NovoGrad:使用层级自适应二阶矩进行梯度归一化 \(m_t\text{: 动量}(0) \\ v_t\text{: 平方梯度}(0) \\ \gamma\text{: 全局学习率} \\ \lambda\text{: 权重衰减率} \\ \beta_1 \text{: 衰减率}(0.9) \\ \beta_2 \text{: 衰减率}(0.25) \\ \epsilon \text{: 小值}(1e-8) \\ L \text{: 网络层数}\) \(\begin{align} v_1^{(i)}&=|g_1^{(i)}|^2, m_1^{(i)}=\frac{g_1^{(i)}}{\sqrt{v_1^{(i)}}}+\lambda w_1^l \\ v_t^{(i)} &= \beta_2 \cdot v_{t-1}^{(i)} + (1-\beta_2) \cdot |g_t^{(i)}|^2 \\ m_t^{(i)} &= \beta_1 \cdot m_{t-1}^{(i)} + (\frac{g_t^{(i)}}{\sqrt{v_t^{(i)}}+\epsilon}+\lambda \theta_t^{(i)}) \\ θ_t^{(i)}&=θ_{t-1}^{(i)}-\gamma m_t^{(i)} , \text{for all }i \in [L] \end{align}\)
Amos:自适应设置学习率和权重衰减项 \(h_t\text{: 参数更新量} \\ \alpha_t\text{: 自适应学习率} \\ \rho_t \text{: 自适应权重衰减率}\) \(\begin{align} \theta_{t+1} &= \theta_t - (\alpha_th_t+\rho_t\theta_t) \\ \alpha_t &\approx \frac{\alpha_0 ||\epsilon_0||}{||h_t||} \frac{1}{2 \alpha_0 p_0 t+1} \\ \rho_t &\approx \frac{\alpha_0^2}{2q} \frac{1}{2 \alpha_0 p_0 t+1} \end{align}\)
Lion:自动搜索优化器 \(m_t\text{: 动量}(0) \\ \gamma\text{: 学习率} \\ \lambda \text{: 权重衰减率}(1.0) \\ \beta_1 \text{: 衰减率}(0.9)\\ \beta_2 \text{: 衰减率}(0.99)\) \(\begin{align} u_t &= \text{sign}( \beta_1m_{t-1}+(1-\beta_1)g_t ) + \lambda\theta_{t} \\ θ_t&=θ_{t-1}-\gamma u_t \\ m_t &= \beta_2m_{t-1}+(1-\beta_2)g_t \end{align}\)

4. 其他优化算法

Averaging Weights Leads to Wider Optima and Better Generalization:随机权重平均 SWA

随机权重平均是指在梯度下降过程中累积历史权重的平均值,通常与周期或恒定学习率一起使用。 若学习率变化周期为$c$(对于恒定学习率$c=1$),当训练轮数$i$每完成一个周期时($\text{mod}(i,c)=0$),通过已累积的模型数量$n_{\text{model}} = i/c$累积平均权重$w_{\text{SWA}}$:

\[w_{\text{SWA}} = \frac{n_{\text{model}} \cdot w_{\text{SWA}}+w_i}{n_{\text{model}}+1}\]

如果网络存在BatchNorm,则应在训练结束后使用平均权重$w_{\text{SWA}}$对数据额外进行一次前向传播,从而计算每一层神经元的相关统计量。

使用Pytorch实现SWA

dataloader, optimizer, model, loss_fn = ...
swa_model = torch.optim.swa_utils.AveragedModel(model)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=300)
swa_start = 160  # 从160轮开始累积权重
swa_scheduler = torch.optim.swa_utils.SWALR(
    optimizer, anneal_strategy="linear", anneal_epochs=5, swa_lr=0.05)
# SWALR在每轮的前5次更新内将学习率线性退火到0.05并保持恒定

for epoch in range(300):
    for input, target in dataloader:
        optimizer.zero_grad()
        loss_fn(model(input), target).backward()
        optimizer.step()
    if epoch > swa_start:
        swa_model.update_parameters(model)
        swa_scheduler.step()
    else:
        scheduler.step()
    
torch.optim.swa_utils.update_bn(dataloader, swa_model)  # 更新bn参数
preds = swa_model(test_input)  # 测试数据

在实践中,也可以累积权重的指数滑动平均值(exponential moving average, EMA, 也称Polyak averaging):

\[w_{\text{EMA}} = \beta w_{\text{EMA}} +(1-\beta) w_i\]
ema_avg = lambda averaged_model_parameter, model_parameter, num_averaged:\
        0.1 * averaged_model_parameter + 0.9 * model_parameter
ema_model = torch.optim.swa_utils.AveragedModel(model, avg_fn=ema_avg)

Gradientless Descent: High-Dimensional Zeroth-Order Optimization:不计算梯度的零阶优化方法

零阶优化泛指不需要梯度信息的优化方法。可以通过采样和差分这两种方法来估计参数更新的方向,从而省略梯度的计算。

基于差分的零阶优化是指通过采样求得梯度的近似表示:

\[\tilde{\nabla}_xf(x) = \Bbb{E}_{u\text{~}p(u)}[\frac{f(x+\epsilon u)-f(x)}{\epsilon} u]\]

其中$\epsilon$是小正数;$p(u)$是具有零均值和单位协方差矩阵的分布,通常用标准正态分布。通过上述估计梯度可以更新参数。

基于采样的零阶优化是一种参数搜索方法。其基本思路是给定采样分布$\mathcal{D}$和参数初始值$x_0$,在第$t$轮循环中设置一个标量半径$r_t$,从以$x_t$为中心的分布$r_t\mathcal{D}$中采样$y_t$。如果$f(y_t)<f(x_t)$,则更新$x_{t+1}=y_t$;否则$x_{t+1}=x_t$。

尽管零阶优化中的采样分布是固定的(通常选择均匀分布),可以在算法的每次迭代中选择采样半径$r_t$。如简单地通过二分搜索设置一系列半径:

Gradients without Backpropagation:使用前向梯度代替反向传播梯度

本文提出了一种基于方向导数的梯度计算方法,通关单次前向传播同时计算损失函数值和前向梯度(forward gradient)。前向梯度 $g:\Bbb{R}^{n} \to \Bbb{R}^{n}$定义为:

\[g(\theta) = (\nabla f(\theta)\cdot v) v\]

其中$\theta \in \Bbb{R}^{n}$是计算梯度的参数点,$v \in \Bbb{R}^{n}$是从多元标准正态分布中采样的干扰向量$v\text{~}\mathcal{N}(0,I)$,$\nabla f(\theta)\cdot v \in \Bbb{R}$表示在$\theta$点指向$v$的方向导数,可以在单次前向传播中计算得到。

前向梯度$g(\theta)$是真实梯度$\nabla f(\theta)$的无偏估计。使用前向梯度代替反向传播计算的梯度,可以实现仅依赖单次前向传播的前向梯度下降(forward gradient descent, FGD)算法,从而省去反向传播过程。

Lookahead: 快权重更新k次,慢权重更新1次

lookahead迭代地更新两组权重:慢权重 $\phi$ 和快权重 $\theta$。快权重 $\theta$是通过任意一种标准优化算法$A$进行更新的;慢权重 $\phi$是通过在参数空间$\theta-\phi$中进行线性插值得到的;快权重每经过$k$次更新后,慢权重更新$1$次。

\[\begin{aligned} h_t &= f(g_{1},...,g_{t}) \\ θ_t&=θ_{t-1}-\gamma h_t \\ \text{if } t \text{ m}&\text{od }k =0: \\ \phi_{t} &= \phi_{t-1} +\alpha(\theta_{t}-\phi_{t-1}) \\ \theta_t &= \phi_t \end{aligned}\]

lookahead算法相比于直接使用优化器更新$k$次,运算操作数变为$O(\frac{k+1}{k})$倍。当快权重沿低曲率方向进行更新时,慢权重通过参数插值平滑振荡,实现快速收敛。当快权重在极小值附近探索时,慢权重更新将推向一个测试精度更高的区域。

Data Echoing: 通过buffer加速模型训练

在深度学习模型流水线中,通常上游任务(数据预处理)是在CPU上进行的,而下游任务(深度学习任务)是在GPU上进行的;模型对一批数据进行预处理的时间要长于使用数据进行学习的时间;

data echoing将预处理的数据放入一个buffer中,使用数据更新参数时从这个buffer直接或再进行一些处理来获得一个批量的数据;不断从buffer中采样直到upstream处理好了一批新的数据,更新buffer

⚪ 参考文献