深度学习-优化算法
概念
经验风险是训练数据集的平均损失,而风险则是整个数据群的预期损失。

风险也就是深度学习追求的泛化误差,因为不可能获得所有数据所以没有办法解决,所以这里只考虑经验风险误差,也就是训练误差。
局部最小值
李宏毅有讲过 李宏毅机器学习#优化失败,通过 Hessian 矩阵判断是局部最大(负定)/小值(正定)或者是不定(鞍点)
[!tip]
凸函数是 Hessian 函数的特征值永远不为负值(正定)的函数
凸性(convexity)
凸集(convex set)
$$ \lambda a + (1-\lambda) b \in \mathcal{X} \text{ 当 } a, b \in \mathcal{X}. $$
集合元素满足以上关系,几何意义是,集合上任意两点的连线在这个集合中。
性质:
- 交集是凸的
[!Tip]
通常,深度学习中的问题是在凸集上定义的。
凸函数(convex function)
$\lambda f(x) + (1-\lambda) f(x’) \geq f(\lambda x + (1-\lambda) x’).$
函数上任意两点的线段不会经过(穿过)函数的第三个点

詹森不等式(Jensen’s inequality)
$\sum_i \alpha_i f(x_i) \geq f\left(\sum_i \alpha_i x_i\right) \text{ and } E_X[f(X)] \geq f\left(E_X[X]\right),$
- 满足 $\sum_i \alpha_i = 1$
- 即:凸函数的期望不小于期望的凸函数
下水平集(below sets)
$\mathcal{S}_b := {x | x \in \mathcal{X} \text{ and } f(x) \leq b}$
- 凸函数的下水平集是凸的
二阶导数
- 微积分时使用二阶导数定义函数的凹凸性
- 凸函数意味着它二次可微分并且二阶导数是(半)正定(全为正的)
约束优化(constrained optimization)
$$ \text{ subject to } & c_i(\mathbf{x}) \leq 0 \text{ for all } i \in {1, \ldots, N}. \end{aligned}\end{split}$$
- 就是把自变量 X 进行限制的优化(在约束条件下找极值)
拉格朗日函数
$$L(\mathbf{x}, \alpha_1, \ldots, \alpha_n) = f(\mathbf{x}) + \sum_{i=1}^n \alpha_i c_i(\mathbf{x}) \text{ where } \alpha_i \geq 0.$$
- $\alpha_i$ 为拉格朗日乘数(Lagrange multipliers)
- 𝐿 的鞍点是原始约束优化问题的最优解
梯度下降(gradient descent)
$$f(x + \epsilon) = f(x) + \epsilon f’(x) + \mathcal{O}(\epsilon^2).$$ $$f(\mathbf{x} + \boldsymbol{\epsilon}) = f(\mathbf{x}) + \mathbf{\boldsymbol{\epsilon}}^\top \nabla f(\mathbf{x}) + \mathcal{O}(|\boldsymbol{\epsilon}|^2).$$ 有: $$f(x - \eta f’(x)) = f(x) - \eta f’^2(x) + \mathcal{O}(\eta^2 f’^2(x)).$$ 当梯度没有消失时($f’(x) \neq 0$),就能不断迭代下降 $$f(x - \eta f’(x)) \lessapprox f(x).$$
这里面的 $\eta$ 被成为学习率
- 牛顿法:略(实践基本不用)
随机梯度下降(stochastic gradient descent)
loss: $$f(\mathbf{x}) = \frac{1}{n} \sum_{i = 1}^n f_i(\mathbf{x}).$$ loss 的梯度: $$\nabla f(\mathbf{x}) = \frac{1}{n} \sum_{i = 1}^n \nabla f_i(\mathbf{x}).$$ 如果使用梯度下降则要计算 n 次,并求平均值。 如果使用 SGD 随机取一个 $\nabla f_i(\mathbf{x})$ 只要计算一次。
因为它是无偏估计: $$\mathbb{E}i \nabla f_i(\mathbf{x}) = \frac{1}{n} \sum{i = 1}^n \nabla f_i(\mathbf{x}) = \nabla f(\mathbf{x}).$$
动态学习率
但是随机梯度下降由于噪声的存在不容易到达目标,可以使用动态学习率去优化,即 $\eta \to \eta(t)$。
简单方法
$$
\begin{split}\begin{aligned}
\eta(t) & = \eta_i \text{ if } t_i \leq t \leq t_{i+1} && \text{分段常数} \\
\eta(t) & = \eta_0 \cdot e^{-\lambda t} && \text{指数衰减} \\
\eta(t) & = \eta_0 \cdot (\beta t + 1)^{-\alpha} && \text{多项式衰减}
\end{aligned}\end{split}
$$
[!Tip] 在第一个_分段常数_(piecewise constant)场景中,我们会降低学习率,例如,每当优化进度停顿时。这是训练深度网络的常见策略。或者,我们可以通过_指数衰减_(exponential decay)来更积极地减低它。不幸的是,这往往会导致算法收敛之前过早停止。一个受欢迎的选择是𝛼=0.5的_多项式衰减_(polynomial decay)。在凸优化的情况下,有许多证据表明这种速率表现良好。
凸目标
- 结论:对于凸问题,我们可以证明,对于广泛的学习率选择,随机梯度下降将收敛到最优解。
小批量随机梯度下降(minibatch gradient descent)
在实际中 SGD 收敛的速度稍慢,小批量随机梯度下降能够平衡收敛速度和计算效率。结合了计算设备向量化的优势,并行计算效率更高。
即把选择一个样本的梯度换成选择一批样本的梯度然后再除批次大小 $$
\mathbf{g}t = \partial{\mathbf{w}} f(\mathbf{x}_{t}, \mathbf{w}).
\quad
\to
\quad
\mathbf{g}t = \partial{\mathbf{w}} \frac{1}{|\mathcal{B}t|} \sum{i \in \mathcal{B}t} f(\mathbf{x}{i}, \mathbf{w}).
$$
- 标准差减少了 $b^{-\frac{1}{2}}$
- 实践中,loss 求平均则是无需在优化时除以批次大小
- 如果 loss 是求和则 sgd 中需要除以批次大小
动量法
整理 mSGD 的原理形式: $$
\mathbf{g}{t, t-1} = \partial{\mathbf{w}} \frac{1}{|\mathcal{B}t|} \sum{i \in \mathcal{B}t} f(\mathbf{x}{i}, \mathbf{w}_{t-1}) = \frac{1}{|\mathcal{B}t|} \sum{i \in \mathcal{B}t} \mathbf{h}{i, t-1}.
$$
- $\mathbf{h}{i, t-1} = \partial{\mathbf{w}} f(\mathbf{x}i, \mathbf{w}{t-1})$
使用动量 $\mathbf{v}$ ( 它累加了过去的梯度): $$
\mathbf{v}t = \beta \mathbf{v}{t-1} + \mathbf{g}_{t, t-1}
$$
$$
\begin{aligned}
\mathbf{v}t = \beta^2 \mathbf{v}{t-2} + \beta \mathbf{g}{t-1, t-2} + \mathbf{g}{t, t-1}
= \ldots, = \sum_{\tau = 0}^{t-1} \beta^{\tau} \mathbf{g}_{t-\tau, t-\tau-1}.
\end{aligned}
$$
- 动量法则是考虑了梯度本身的大小情况,影响参数的更新
- 目的是进一步使方差减少
- 加快收敛速度
- 新的参数更新方向是过去的梯度和新梯度的矢量和
- $\mathbf{x}t \leftarrow \mathbf{x}{t-1} - \eta_t \mathbf{v}_t.$
- ??:有效梯度数 $\frac{1}{1-\beta}$
- 可以解决输入 X 在各个维度的梯度陡峭程度不均衡的问题
- 有的地方陡峭,那么需要更小的学习率,有的地方平坦需要更大的学习率
- $\beta \in (0, 1)$ 为 0 时则是不使用动量
- 但是要增加参数
[!caution] 问题
- 动量和学习率的关系暂时未知
AdaGrad
- 实践中用了很多优化替代,最终使用梯度下降,原理不深究,比较复杂。
$$
\begin{split}\begin{aligned}
\mathbf{g}t & = \partial{\mathbf{w}} l(y_t, f(\mathbf{x}_t, \mathbf{w})), \\
\mathbf{s}t & = \mathbf{s}{t-1} + \mathbf{g}_t^2, \\
\mathbf{w}t & = \mathbf{w}{t-1} - \frac{\eta}{\sqrt{\mathbf{s}_t + \epsilon}} \cdot \mathbf{g}_t.
\end{aligned}\end{split}
$$
- $\epsilon$ 是一个为维持数值稳定性而添加的常数(很小),保证不会除0。
- 最终权重的计算为梯度除以过去梯度的标准差/二阶矩?
- 因为 loss 求平均,所以这里没有除批量大小
- 这样把各个坐标上比较大的值都平滑了
- 在AdaGrad算法中,我们允许每个坐标有单独的学习率。
- 但是状态向量是一直递增的
RMSProp
$$
\begin{split}\begin{aligned}
\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.
\end{aligned}\end{split}
$$
- 在 AdaGrad 的基础上,增加了一个超参数控制状态的变化程度
- 有效梯度数:$1/(1-\gamma)$ 和动量那边类似,超过多少次后的不管了
Adadelta
$$
\begin{split}\begin{aligned}
\mathbf{s}t & = \rho \mathbf{s}{t-1} + (1 - \rho) \mathbf{g}_t^2.
\\
\mathbf{x}t & = \mathbf{x}{t-1} - \mathbf{g}_t’. \\
\mathbf{g}t’ & = \frac{\sqrt{\Delta\mathbf{x}{t-1} + \epsilon}}{\sqrt{{\mathbf{s}_t + \epsilon}}} \odot \mathbf{g}_t, \\
\Delta \mathbf{x}t & = \rho \Delta\mathbf{x}{t-1} + (1 - \rho) {\mathbf{g}_t’}^2,
\end{aligned}\end{split}
$$
- 无学习率,但需要两个状态变量
- 增加了一个 $\Delta \mathbf{x}_t$ 放到原本学习率的位置上,注意与状态 s 的异同
- 相当于在 s 的基础上再增加了一层
- $\Delta \mathbf{x}_t$ 是取 s 计算完的梯度进行更新的
Adam
$$
\begin{split}\begin{aligned}
\mathbf{v}t & \leftarrow \beta_1 \mathbf{v}{t-1} + (1 - \beta_1) \mathbf{g}_t, \\
\mathbf{s}t & \leftarrow \beta_2 \mathbf{s}{t-1} + (1 - \beta_2) \mathbf{g}_t^2.
\end{aligned}\end{split}
$$
- 常将它们设置为$\beta_1 = 0.9$和$\beta_2 = 0.999$
- 梯度使用动量和二次矩估计值状态一起决定
- 需要两个状态变量和超参数
$$
\begin{split}\begin{aligned}
\hat{\mathbf{v}}_t &= \frac{\mathbf{v}_t}{1 - \beta_1^t} \text{ and } \hat{\mathbf{s}}_t = \frac{\mathbf{s}_t}{1 - \beta_2^t}. \\
\mathbf{g}_t’ &= \frac{\eta \hat{\mathbf{v}}_t}{\sqrt{\hat{\mathbf{s}}_t} + \epsilon}.
\end{aligned}\end{split}
$$
- 带上标的为标准化变量,由 $\sum_{i=0}^t \beta^i = \frac{1 - \beta^t}{1 - \beta}$ 得到
Yogi 更新
[!attention] 问题
- 当 $\mathbf{s}_t$ 的二次矩估计值爆炸时,它可能无法收敛
- 对于具有显著差异的梯度,我们可能会遇到收敛性问题
$$
\mathbf{s}t \leftarrow \mathbf{s}{t-1} + (1 - \beta_2) \left(\mathbf{g}t^2 - \mathbf{s}{t-1}\right).
$$
- 进一步优化,解决梯度的平方具有值很大的变量或更新很稀疏时 $$
\mathbf{s}t \leftarrow \mathbf{s}{t-1} + (1 - \beta_2) \mathbf{g}_t^2 \odot \mathop{\mathrm{sgn}}(\mathbf{g}t^2 - \mathbf{s}{t-1}).
$$
学习率调度器(learning rate scheduler)
$$
\eta = \eta_0 (t + 1)^{-\frac{1}{2}}
$$
-
用于管理学习率变化
-
通过访问 trainer.param_groups 可以修改学习率,因为 lr 是定义优化器的时候确定的,后么自然也能修改
-
实践中使用
from torch.optim import lr_scheduler- 需要提供初始学习率和目标学习率,以及预热步数等
单因子调度器
$$
\eta_{t+1} \leftarrow \mathop{\mathrm{max}}(\eta_{\mathrm{min}}, \eta_t \cdot \alpha)
$$
- $\eta_{\mathrm{min}}$ 是设置好的学习率下界
多因子调度器
- 分段衰减:
lr_scheduler.MultiStepLR(trainer, milestones=[15, 30], gamma=0.5)- 含义是在 epoch 到 15 和 30 时都会减半
余弦调度器
$$
\eta_t = \eta_T + \frac{\eta_0 - \eta_T}{2} \left(1 + \cos(\pi t/T)\right)
$$
- t 大于 T 时,不再变化它
- 余弦调度器在某些计算机视觉问题中很受欢迎
预热
- 初始学习率很小然后开始增加到最大值,后面冷却
- 实现是设定预热步数,然后初始学习率乘上 epoch 和 预热步数的比值,这样会逐渐增加到初始学习率
- 优化之前的预热期可以防止发散(避免初始学习率过大) $$