序言
在深度学习中,模型优化是提升模型性能与训练效率的关键环节。深度模型通过优化算法不断调整其内部参数,以最小化损失函数,从而实现对复杂数据的有效拟合与预测。本篇章将简要概述深度模型中的几种基本优化算法,包括梯度下降法及其变种,这些算法在推动深度学习领域的发展中起到了至关重要的作用。
概述
梯度下降法(Gradient Descent, GD)
作为最基础的优化算法,梯度下降法通过计算损失函数关于模型参数的梯度,并沿着梯度的反方向更新参数,从而逐步逼近损失函数的最小值。然而,标准梯度下降法需要计算整个数据集的梯度,计算量大且不适合大数据集。
随机梯度下降法(Stochastic Gradient Descent, SGD)
为了克服标准梯度下降法的缺点,SGD每次随机选取一个样本计算梯度并更新参数,显著提高了计算效率。但SGD的梯度估计存在噪声,可能导致收敛过程震荡。
小批量梯度下降法(Mini-batch Gradient Descent)
作为GD与SGD的折中方案,小批量梯度下降法每次选取一小批样本计算梯度并更新参数,既保持了计算效率,又相对稳定了梯度估计。
动量法(Momentum)
在SGD基础上引入动量项,利用历史梯度信息加速收敛并减少震荡。
自适应学习率算法(如Adam)
结合了动量法和 RMSprop \text{RMSprop} RMSprop算法的优点,通过维护梯度的一阶矩和二阶矩估计来动态调整学习率,具有较快的收敛速度和较强的适应性。
基本算法
- 之前我们已经介绍了梯度下降(基于梯度的优化方法),即沿着整个训练集梯度下降的方向。这可以使用随机梯度下降很大程度地加速,沿着随机挑选的 minibatch \text{minibatch} minibatch数据的梯度下降方向,请参阅随机梯度下降算法篇和批算法和 minibatch \text{minibatch} minibatch算法。
随机梯度下降
-
随机梯度下降( SGD \text{SGD} SGD)及其变种很可能是一般机器学习中用得最多的优化算法,特别是在深度学习中。如批算法和 minibatch \text{minibatch} minibatch算法中讨论,通过计算独立同分布地从数据生成分布中抽取的 m m m个 minibatch \text{minibatch} minibatch样本的梯度均值,我们可以得到梯度的无偏估计。
-
算法1:展示了如何使用这个下降梯度的估计。
算法1描述:随机梯度下降( SGD \text{SGD} SGD)在第 k k k个训练迭代的更新
伪代码:
R e q u i r e \bold{Require} Require: 学习速率 ϵ k \epsilon_k ϵk
R e q u i r e \bold{Require} Require: 初始参数 θ \boldsymbol{\theta} θ
w h i l e \quad\bold{while} while 没有达到停止准则 d o \bold{do} do
\qquad 从训练集中采包含 m m m个样本 { x ( i ) , … , x ( m ) } \{\boldsymbol{x}^{(i)},\dots,\boldsymbol{x}^{(m)}\} {x(i),…,x(m)}的 minibatch \text{minibatch} minibatch,对应目标为 y ( i ) \boldsymbol{y}^{(i)} y(i)
\qquad 计算梯度估计: g ^ ← + 1 m ∇ θ ∑ i L ( f ( x ( i ) ; θ ) , y ( i ) ) \hat{\boldsymbol{g}}\gets +\frac{1}{m}\nabla_\theta\sum_i L(f(\boldsymbol{x}^{(i)};\boldsymbol{\theta}),\boldsymbol{y}^{(i)}) g^←+m1∇θ∑iL(f(x(i);θ),y(i))
\qquad 应用更新: θ ← θ − ϵ g ^ \boldsymbol{\theta}\gets\boldsymbol{\theta}-\epsilon\hat{\boldsymbol{g}} θ←θ−ϵg^
e n d \quad\bold{end} end w h i l e \bold{while} while
-
SGD \text{SGD} SGD算法中的一个关键参数是学习速率。之前,我们介绍的 SGD \text{SGD} SGD使用固定的学习速率。在实践中,有必要随着时间的推移逐渐降低学习速率,因此我们将第 k k k步迭代的学习速率记作 ϵ k \epsilon_k ϵk。
-
这是因为 SGD \text{SGD} SGD梯度估计引入的噪源( m m m个训练样本的随机采样)并不会在极小值处消失。相比之下,当我们使用 batch \text{batch} batch梯度下降到达极小值时,整个代价函数的真实梯度会变得很小,甚至为 0 0 0,因此 batch \text{batch} batch梯度下降可以使用固定的学习速率。保证 SGD \text{SGD} SGD收敛的一个充分条件是:
∑ k = 1 ∞ ϵ k = ∞ \sum\limits_{k=1}^\infty \epsilon_k=\infty k=1∑∞ϵk=∞ — 公式1 \quad\textbf{---\footnotesize{公式1}} —公式1
且
∑ k = 1 ∞ ϵ k 2 < ∞ \sum\limits_{k=1}^\infty \epsilon_k^2<\infty k=1∑∞ϵk2<∞ — 公式2 \quad\textbf{---\footnotesize{公式2}} —公式2 -
实践中,一般会线性衰减学习速率到第 τ \tau τ 次迭代:
ϵ k = ( 1 − α ) ϵ 0 + α ϵ τ \epsilon_k=(1-\alpha)\epsilon_0+\alpha\epsilon_\tau ϵk=(1−α)ϵ0+αϵτ — 公式3 \quad\textbf{---\footnotesize{公式3}} —公式3- 其中 α = k τ \alpha=\displaystyle\frac{k}{\tau} α=τk
- 在 τ \tau τ步迭代之后,一般使 ϵ \epsilon ϵ保持常数
-
学习速率可通过试验和误差来选取,通常最好的选择方法是画出目标函数值随时间变化的学习曲线。
- 与其说是科学,这更是一门艺术,关于这个问题的大多数指导都应该被怀疑地看待。
- 使用线性时间表时,参数选择为 ϵ 0 \epsilon_0 ϵ0, ϵ τ \epsilon_\tau ϵτ, τ \tau τ。
- 通常 τ \tau τ被设为需要反复遍历训练样本几百次的迭代次数。
- 通常 ϵ τ \epsilon_\tau ϵτ应设为大约 1 % 1\% 1% 的 ϵ 0 \epsilon_0 ϵ0。
- 主要问题是如何设置 ϵ 0 \epsilon_0 ϵ0。
- 若 ϵ 0 \epsilon_0 ϵ0太大,学习曲线将会剧烈振荡,代价函数值通常会明显增加。
- 温和的振荡是良好的,特别是训练于随机代价函数上,例如由信号丢失引起的代价函数。
- 如果学习速率太慢,那么学习进程会缓慢。
- 如果初始学习速率太低,那么学习可能会卡在一个相当高的损失值。
- 通常,就总训练时间和最终损失值而言,最优初始学习速率会高于大约迭代 100 100 100步后输出最好效果的学习速率。
- 因此,通常最好是检测最早的几轮迭代,使用一个高于此时效果最佳学习速率的学习速率,但又不能太高以致严重的不稳定性。
-
SGD \text{SGD} SGD和相关的 minibatch \text{minibatch} minibatch或在线基于梯度的优化的最重要的性质是每一步更新的计算时间不会随着训练样本数目而增加。
- 即使训练样本数目非常大时,这也能收敛。
- 对于足够大的数据集, SGD \text{SGD} SGD可能会在处理整个训练集之前就收敛到最终测试集误差的某个固定容差范围内。
-
研究优化算法的收敛率,一般会衡量额外误差(excess error) J ( θ ) − min θ J ( θ ) J(\boldsymbol{\theta}) − \min_{\boldsymbol{\theta}} J(\boldsymbol{\theta}) J(θ)−minθJ(θ),即当前代价函数超出最低可能损失的量。
- SGD \text{SGD} SGD应用于凸问题时, k k k步迭代后的额外误差量级是 O ( 1 k ) \Omicron(\displaystyle\frac{1}{\sqrt{k}}) O(k1),在强凸情况下是 O ( 1 k ) \Omicron(\displaystyle\frac{1}{k}) O(k1)。
- 除非假定额外的条件,否则这些界限不能进一步改进。
- batch \text{batch} batch梯度下降在理论上比随机梯度下降有更好的收敛率。
- 然而,Cramér-Rao界限 (Cramér, 1946; Rao, 1945) 指出,泛化误差的下降速度不会快于 O ( 1 k ) \Omicron(\displaystyle\frac{1}{k}) O(k1)。
- Bottou and Bousquet (2008b) 由此认为对于机器学习任务,不值得探寻收敛快于 O ( 1 k ) \Omicron(\displaystyle\frac{1}{k}) O(k1)的优化算法—更快的收敛可能对应着过拟合。
- 此外,渐近分析掩盖随机梯度下降在少量更新步之后的很多优点。
- 对于大数据集, SGD \text{SGD} SGD初始快速更新只需非常少量样本计算梯度的能力远远超过了其缓慢的渐近收敛。
- 本篇章剩余部分介绍的大多数算法都实现了实践中有用的好处,但是丢失了常数倍 O ( 1 k ) \Omicron(\displaystyle\frac{1}{k}) O(k1)的渐近分析。
- 我们也可以权衡batch梯度下降和随机梯度下降两者的优点,在学习过程中逐渐增大 minibatch \text{minibatch} minibatch的大小。
动量
-
虽然随机梯度下降仍然是非常受欢迎的优化方法,但学习速率有时会很慢。
-
动量方法(Polyak, 1964)旨在加速学习,特别是处理高曲率,小但一致的梯度,或是带噪扰的梯度。
- 动量算法积累了之前梯度指数级衰减的移动平均,并且继续沿该方向移动。
- 动量的效果如图例1所示。
-
从形式上看,动量算法引入了变量 v \boldsymbol{v} v充当速度的角色—它代表参数在参数空间移动的方向和速度。
- 速度被设为负梯度的指数衰减平均。
- 名称动量(momentum)来自物理类比,根据牛顿运动定律,负梯度是移动参数空间中粒子的力。
- 动量在物理学上是质量乘以速度。
- 在动量学习算法中,我们假设是单位质量,因此速度向量 v \boldsymbol{v} v也可以看作是粒子的动量。超参数 α ∈ [ 0 , 1 ) \alpha\in\text{[}0,1\text{)} α∈[0,1)决定了之前梯度的贡献衰减得有多快。
- 更新规则如下:
v ← α v − ϵ ∇ θ ( 1 m ∑ i = 1 m L ( f ( x ( i ) ; θ ) , y ( i ) ) ) \boldsymbol{v}\gets\alpha \boldsymbol{v}-\epsilon\nabla_\theta \left(\displaystyle\frac{1}{m}\sum\limits_{i=1}^m L(f(\boldsymbol{x}^{(i)};\boldsymbol{\theta}),\boldsymbol{y}^{(i)})\right) v←αv−ϵ∇θ(m1i=1∑mL(f(x(i);θ),y(i))) — 公式4 \quad\textbf{---\footnotesize{公式4}} —公式4
θ ← θ + v \boldsymbol{\theta}\gets\boldsymbol{\theta}+\boldsymbol{v} θ←θ+v — 公式5 \quad\textbf{---\footnotesize{公式5}} —公式5 - 速度 v \boldsymbol{v} v累积了梯度元素 ∇ θ ( 1 m ∑ i = 1 m L ( f ( x ( i ) ; θ ) , y ( i ) ) ) \nabla_\theta \left(\displaystyle\frac{1}{m}\sum\limits_{i=1}^m L(f(\boldsymbol{x}^{(i)};\boldsymbol{\theta}),\boldsymbol{y}^{(i)})\right) ∇θ(m1i=1∑mL(f(x(i);θ),y(i)))。相对于 ϵ \epsilon ϵ的 α \alpha α越大,之前梯度对现在方向的影响也越大。带动量的 SGD \text{SGD} SGD算法如算法2所示。
-
算法2:使用动量的随机梯度下降( SGD \text{SGD} SGD)
算法2描述:使用动量的随机梯度下降( SGD \text{SGD} SGD)
伪代码:
R e q u i r e \bold{Require} Require: 学习速率 ϵ k \epsilon_k ϵk,动量参数 α \alpha α
R e q u i r e \bold{Require} Require: 初始参数 θ \boldsymbol{\theta} θ,初始速度 v \boldsymbol{v} v
w h i l e \quad\bold{while} while 没有达到停止准则 d o \bold{do} do
\qquad 从训练集中采包含 m m m个样本 { x ( i ) , … , x ( m ) } \{\boldsymbol{x}^{(i)},\dots,\boldsymbol{x}^{(m)}\} {x(i),…,x(m)}的 minibatch \text{minibatch} minibatch,对应目标为 y ( i ) \boldsymbol{y}^{(i)} y(i)
\qquad 计算梯度估计: g ^ ← 1 m ∇ θ ∑ i L ( f ( x ( i ) ; θ ) , y ( i ) ) \hat{\boldsymbol{g}}\gets \displaystyle\frac{1}{m}\nabla_\theta\sum_i L(f(\boldsymbol{x}^{(i)};\boldsymbol{\theta}),\boldsymbol{y}^{(i)}) g^←m1∇θi∑L(f(x(i);θ),y(i))
\qquad 计算速度更新: v ← α v − ϵ g \boldsymbol{v}\gets\alpha \boldsymbol{v}-\epsilon\boldsymbol{g} v←αv−ϵg
\qquad 应用更新: θ ← θ + v \boldsymbol{\theta}\gets\boldsymbol{\theta}+\boldsymbol{v} θ←θ+v
e n d \quad\bold{end} end w h i l e \bold{while} while
- 之前,步长只是梯度范数乘以学习速率。现在,步长取决于梯度序列的大小和排列。
- 当许多连续的梯度指向相同的方向时,步长最大。
- 如果动量算法总是观测到梯度 g \boldsymbol{g} g,那么它会在方向 − g −g −g上不停加速,直到达到最后速度的步长为: ϵ ∥ g ∥ 1 − α \displaystyle\frac{\epsilon\Vert\boldsymbol{g}\Vert}{1-\alpha} 1−αϵ∥g∥ — 公式6 \quad\textbf{---\footnotesize{公式6}} —公式6
- 因此将动量的超参数视为 1 1 − α \displaystyle\frac{1}{1-\alpha} 1−α1有助于理解。例如, α = 0.9 \alpha=0.9 α=0.9对应着最大速度 10 10 10倍于梯度下降算法。
- 在实践中, α \alpha α的一般取值为 0.5 0.5 0.5, 0.9 0.9 0.9, 0.99 0.99 0.99。和学习速率一样, α \alpha α也会随着时间变化。一般初始值是一个较小的值,随后会慢慢变大。随着时间推移改变 α \alpha α没有收缩 ϵ \epsilon ϵ更重要。
-
我们可以将动量算法视为模拟连续时间下牛顿动力学下的粒子。这种物理类比有助于直觉上理解动量和梯度下降算法是如何表现的。
- 粒子在任意时间点的位置由 θ ( t ) \boldsymbol{\theta}(t) θ(t)给定。粒子会受到净力 f ( t ) \boldsymbol{f}(t) f(t)。该力会导致粒子加速: f ( t ) = ∂ 2 ∂ t 2 θ ( t ) \boldsymbol{f}(t)=\displaystyle\frac{\partial^2}{\partial t^2}\boldsymbol{\theta}(t) f(t)=∂t2∂2θ(t) — 公式7 \quad\textbf{---\footnotesize{公式7}} —公式7
- 与其将其视为位置的二阶微分方程,我们不如引入表示粒子在时间 t t t处速度的变量 v ( t ) \boldsymbol{v}(t) v(t),将牛顿动力学重写为一阶微分方程:
v ( t ) = ∂ ∂ t θ ( t ) \boldsymbol{v}(t)=\displaystyle\frac{\partial}{\partial t}\boldsymbol{\theta}(t) v(t)=∂t∂θ(t) — 公式8 \quad\textbf{---\footnotesize{公式8}} —公式8
\quad
f ( t ) = ∂ ∂ t v ( t ) \boldsymbol{f}(t)=\displaystyle\frac{\partial}{\partial t}\boldsymbol{v}(t) f(t)=∂t∂v(t) — 公式9 \quad\textbf{---\footnotesize{公式9}} —公式9 - 由此,动量算法包括由数值模拟求解微分方程。求解微分方程的一个简单数值方法是欧拉方法,通过在每个梯度方向上小且有限的步来简单模拟该等式定义的动力学。
-
这解释了动量更新的基本形式,但具体什么是力呢?
- 力正比于代价函数的负梯度: − ∇ θ J ( θ ) -\nabla_{\boldsymbol{\theta}}J(\boldsymbol{\theta}) −∇θJ(θ)。
- 该力推动粒子沿着代价函数表面下坡的方向移动。
- 梯度下降算法基于每个梯度简单地更新一步,而使用动量算法的牛顿方案则使用该力改变粒子的速度。
- 我们可以将粒子视作在冰面上滑行的冰球。
- 每当它沿着表面最陡的部分下降时,它会累积继续在该方向上滑行的速度,直到其开始向上滑动为止。
- 另一个力也是必要的。如果代价函数的梯度是唯一的力,那么粒子可能永远不会停下来。
- 想象一下,假设冰面没有摩擦,一个冰球从山谷的一端下滑,上升到另一端,永远来回振荡。
- 要解决这个问题,我们添加另一个正比于 − v ( t ) −\boldsymbol{v}(t) −v(t)的力。
- 在物理术语中,此力对应于粘性阻力,就像粒子必须通过一个抵抗介质,如糖浆。
- 这会导致粒子随着时间推移逐渐失去能量,最终收敛到局部极小点。
- 力正比于代价函数的负梯度: − ∇ θ J ( θ ) -\nabla_{\boldsymbol{\theta}}J(\boldsymbol{\theta}) −∇θJ(θ)。
-
为什么要特别使用 − v ( t ) -\boldsymbol{v}(t) −v(t)和粘性阻力呢?
- 部分原因是因为 − v ( t ) -\boldsymbol{v}(t) −v(t)在数学上的便利——速度的整数幂很容易处理。
- 然而,其他物理系统具有基于速度的其他整数幂的其他类型的阻力。
- 例如,颗粒通过空气时会受到正比于速度平方的湍流阻力,而颗粒沿着地面移动时会受到恒定大小的摩擦力。这些选择都不合适。
- 湍流阻力,正比于速度的平方,在速度很小时会很弱。
- 不够强到使粒子停下来。
- 非零值初始速度的粒子仅受到湍流阻力,会从初始位置永远地移动下去,和初始位置的距离大概正比于 O ( log t ) \Omicron(\log t) O(logt)。
- 因此我们必须使用速度较低幂次的力。如果幂次为零,相当于干摩擦,那么力太强了。
- 当代价函数的梯度表示的力很小但非零时,由于摩擦导致的恒力会使得粒子在达到局部极小点之前就停下来。
- 粘性阻力
- 粘性阻力避免了这两个问题——它足够弱,可以使梯度引起的运动直到达到最小,但又足够强,使得坡度不够时可以阻止运动。
- 部分原因是因为 − v ( t ) -\boldsymbol{v}(t) −v(t)在数学上的便利——速度的整数幂很容易处理。
Nesterov动量
-
受 Nesterov 加速梯度算法 (Nesterov, 1983, 2004) 启发,Sutskever et al. (2013)提出了动量算法的一个变种。这种情况的更新规则如下:
v ← α v − ϵ ∇ θ [ 1 m ∑ i = 1 m L ( f ( x ( i ) ; θ + α v ) , y ( i ) ) ] \boldsymbol{v}\gets\alpha \boldsymbol{v}-\epsilon\nabla_\theta \left[\displaystyle\frac{1}{m}\sum\limits_{i=1}^m L(f(\boldsymbol{x}^{(i)};\boldsymbol{\theta}+\alpha\boldsymbol{v}),\boldsymbol{y}^{(i)})\right] v←αv−ϵ∇θ[m1i=1∑mL(f(x(i);θ+αv),y(i))] — 公式10 \quad\textbf{---\footnotesize{公式10}} —公式10
θ ← θ + v \boldsymbol{\theta}\gets\boldsymbol{\theta}+\boldsymbol{v} θ←θ+v — 公式11 \quad\textbf{---\footnotesize{公式11}} —公式11 -
其中参数 α \alpha α和 ϵ \epsilon ϵ发挥了和标准动量方法中类似的作用。 Nesterov \text{Nesterov} Nesterov动量和标准动量之间的区别体现在梯度计算上。 Nesterov \text{Nesterov} Nesterov动量中,梯度计算在施加当前速度之后。因此, Nesterov \text{Nesterov} Nesterov动量可以解释为往标准动量方法中添加了一个校正因子。完整的 Nesterov \text{Nesterov} Nesterov动量算法如算法3所示。
-
算法3:使用 Nesterov \text{Nesterov} Nesterov动量的随机梯度下降( SGD \text{SGD} SGD)
算法3描述:使用 Nesterov \text{Nesterov} Nesterov动量的随机梯度下降( SGD \text{SGD} SGD)
伪代码:
R e q u i r e \bold{Require} Require: 学习速率 ϵ k \epsilon_k ϵk,动量参数 α \alpha α
R e q u i r e \bold{Require} Require: 初始参数 θ \boldsymbol{\theta} θ,初始速度 v \boldsymbol{v} v
w h i l e \quad\bold{while} while 没有达到停止准则 d o \bold{do} do
\qquad 从训练集中采包含 m m m个样本 { x ( i ) , … , x ( m ) } \{\boldsymbol{x}^{(i)},\dots,\boldsymbol{x}^{(m)}\} {x(i),…,x(m)}的 minibatch \text{minibatch} minibatch,对应目标为 y ( i ) \boldsymbol{y}^{(i)} y(i)
\qquad 应用临时更新: θ ~ ← θ + α v \tilde{\boldsymbol{\theta}}\gets\boldsymbol{\theta}+\alpha\boldsymbol{v} θ~←θ+αv
\qquad 计算梯度(在临时点): g ← 1 m ∇ θ ∑ i L ( f ( x ( i ) ; θ ) , y ( i ) ) \boldsymbol{g}\gets \displaystyle\frac{1}{m}\nabla_\theta\sum_i L(f(\boldsymbol{x}^{(i)};\boldsymbol{\theta}),\boldsymbol{y}^{(i)}) g←m1∇θi∑L(f(x(i);θ),y(i))
\qquad 计算速度更新: v ← α v − ϵ g \boldsymbol{v}\gets\alpha \boldsymbol{v}-\epsilon\boldsymbol{g} v←αv−ϵg
\qquad 应用更新: θ ← θ + v \boldsymbol{\theta}\gets\boldsymbol{\theta}+\boldsymbol{v} θ←θ+v
e n d \quad\bold{end} end w h i l e \bold{while} while
-
在凸 batch \text{batch} batch梯度的情况下, Nesterov \text{Nesterov} Nesterov动量将额外误差收敛率从 O ( 1 k ) \Omicron(\displaystyle\frac{1}{k}) O(k1)( k k k步后)改进到 O ( 1 k 2 ) \Omicron(\displaystyle\frac{1}{k^2}) O(k21),如Nesterov(1983)所示。不幸的是,在随机梯度的情况下, Nesterov \text{Nesterov} Nesterov动量没有改进收敛率。
-
图例1:动量的主要目的是解决两个问题: Hessian \text{Hessian} Hessian矩阵的不良条件数和随机梯度的方差。
-
动量的主要目的是解决两个问题: Hessian \text{Hessian} Hessian矩阵的不良条件数和随机梯度的方差。
-
说明:
- 我们通过此图说明动量如何克服这两个问题的第一个。
- 轮廓线描绘了一个二次损失函数(具有不良条件数的 Hessian \text{Hessian} Hessian矩阵)。
- 横跨轮廓的红色路径表示动量学习规则所遵循的路径,它使该函数最小化。
- 我们在每个步骤画一个箭头,指示梯度下降将在该点采取的步骤。
- 我们可以看到,一个条件数较差的二次目标函数看起来像一个长而窄的山谷或陡峭的峡谷。
- 动量正确地纵向穿过峡谷,而梯度步骤则会浪费时间在峡谷的窄轴上来回移动。比较图:梯度下降无法利用包含在Hessian矩阵中的曲率信息,它也显示了没有动量的梯度下降的行为。
-
总结
深度模型中的优化算法是提升模型性能的重要工具。从基础的梯度下降法到先进的自适应学习率算法,这些算法在不断演进中解决了计算效率、收敛速度及稳定性等问题。
未来,随着深度学习应用的不断拓展,优化算法的研究将继续深入,为更高效的模型训练提供有力支持。
往期内容回顾
应用数学与机器学习基础 - 随机梯度下降算法篇
应用数学与机器学习基础 - 数值计算之梯度之上Jacobian和Hessian矩阵篇
深度网络现代实践 - 深度前馈网络之基于梯度的学习篇
梯度下降算法之随机梯度下降