学习和纯优化的不同
纯优化:最小化目标J本身,比如线性模型的正规方程
学习:减低代价函数J,比如全连接层的梯度下降。有以下几个方面
- 会使用训练集代替数据本身。整个数据带来的期望泛化误差叫风险, 使用训练集带来的期望泛化误差叫经验风险
- 批量算法和小批量算法。使用整个数据集叫批量 使用介于单个和整个数据集之间的叫小批量
- 代理损失函数和提前终止:使用一些函数如RELU替代0-1损失函数, 在验证集上拥有低损失时终止,防止过拟合
代理损失函数
从左图可以看出上面介绍的这些损失函数都可以 看作是0-1损失的单调连续近似函数,而因为这些损失函数通常是凸的连续函数,因此常用来代替 0-1损失进行优化。它们的相同点是都随 margin → − ∞ \operatorname{margin} \rightarrow-\infty margin→−∞而加大惩罚;不同点在于,他们增长方式不同。
代理损失函数可以进一步拉开不同类别的距离以改进分类器的鲁棒性,获得一个更强壮的、更值得信赖的分类器,从而,相对于简单地最小化训 练集上的平均 0 − 1 损失,它能够从训练数据中抽取更多信息。
批量算法
小批量的大小通常由以下几个因素决定:
- 更大的批量会计算更精确的梯度估计,但是回报却是小于线性的。
- 极小批量通常难以充分利用多核架构。这促使我们使用一些绝对最小批量,低于这个值的小批量处理不会减 少计算时间。
- 如果批量处理中的所有样本可以并行地处理(通常确是如此),那么内存消耗和批量大小会正比。对于很多硬件设施,这是批量大小的限制因素。
- 在某些硬件上使用特定大小的数组时,运行时间会更少。尤其是在使用 GPU 时,通常使用 2 的幂数作为批量大小可以获得更少的运行时间。一般,2 的幂数的取值范围是 32 到 256,16 有时在尝试大模型时使用。
- 可能是由于小批量在学习过程中加入了噪声,它们会有一些正则化效果 。泛化误差通常在批量大小为 1 时 最好。因为梯度估计的高方差,小批量训练需要较小的学习率以保持稳定性。因为降低的学习率和消耗更多步骤来遍历整个训练集都会产生更多的步骤,所以会导致总的运行时间非常大。
神经网络优化中的挑战
- 病态:在训练中很小的步长会增加代价函数,常见于H病态中
- 局部极小值:在高维空间中,局部极小值一般不是问题的主要因素
高原、鞍点和其他平坦区域
鞍点
鞍点就是代价函数在某个横截面上的局部极小值. 它在一个维度方向上有极小值,而在另一个维度方向上可能是极大值,而非极小值。
悬崖和梯度爆炸
(图片来源:https://arxiv.org/pdf/1211.5063.pdf)
悬崖是由于几较大个的权重相乘 导致的。遇到斜率极大的悬崖结构时,梯度更新会很大程度地改 变参数值,通常会完全跳过这类悬崖结构(我们可以看到一个局 部最小值在悬崖结构中间)。我们可以利用梯度截断(clipping)解决
长期依赖
由于变身的结构使模型丧失了学习到先前信息的能力,让优化变得极其困难。比如说RNN网络,如果时间跨度较大,后面的依赖关系就很难学习到早期序列的信息。经过许多阶段传播后的梯度倾向于消失(大部分情况)或者爆炸(很少,但是对优化过程影响很大)
非精度梯度
在实践中,通常这些量会有噪声,甚至是有偏的估计。在一些情况下,我们希望最小化的目标函数实际上是难以处理的。当目标函数不可解时,通常其梯度也是难以处理的。在这种情况下,我们只能近似梯度。各种神经网络优化算法的设计都考虑到了梯度估计的缺陷。我们可以选择比真实损失函数更容易估计的代理损失函数来避免这个问题。
局部和全局结构间的弱对应
优化的理论限制
优化算法
Batch Gradient Descent
在训练中,每一步迭代都使用训练集的所有内容.
也就是说,利用现有参数对训练集中的每一个输入生成一个估计输出,然后跟实际输 出比较,统计所有误差,求平均以后得到平均误差,以此来作为更新参数的依据.
优点: 由于每一步都利用了训练集中的所有数据,因此当损失函数达到最小值以后, 能够保证此时计算出的梯度为0,换句话说,就是能够收敛(可以看到效果如左图所示 非常平滑).因此,使用BGD时不需要逐渐减小学习速率
缺点: 由于每一步都要使用所有数据,因此随着数据集的增大,运行速度会越来越慢.
Batch Gradient Descent
在训练中,每次使用小批量(既一个小批量m 个训练 样本)的随机采样进行梯度下降。
训练方法和BGD一样,只是BGD最后的误差是对整个样本取平均,SGD是对小批 量的m个样本取平均。
因为小批量不能代表整个样本,使得梯度估计引入的噪声源,让SGD并 不是每次迭代都向着整体最优化方向,虽然包含一定的随机性(表现为 损失函数的震荡),但是从期望上来看,它是等于正确的导数的(表现 为损失函数有减小的趋势)。
优点:是训练速度会比较快。
缺点:是在样本数量较大的情况下,可能只用到了其中一部分数据就完成了训练, 得到的只是全局最优解。另外,小批量样本的噪声较大,所以每次执行梯度下降, 并不一定总是朝着最优的方向前进。
动量(Momentum)
在训练中,采取的学习策略和SGD一样,不一样的是参数的更新。
SGD 在沟壑的情况下容易被困住, 沟壑就是曲面的一个方向比另一个方向更陡 (可以是鞍点),这时 SGD 会发生震荡而迟迟不能接近极小值。我们可以加入一个动量项,使得梯度方向不变的维度上速度变快,梯度方向有所改变的维度上的更新变慢,这样就可以加快收敛并减少震荡。
原来的优化是
{
v
t
=
−
η
∇
J
(
θ
t
)
θ
t
+
1
=
θ
t
+
v
t
\left\{\begin{array}{ll} v_t = -\eta\nabla J(\theta_t) \\ \theta_{t+1} = \theta_{t} + v_{t} \\ \end{array}\right.
{vt=−η∇J(θt)θt+1=θt+vt
加入动量项
α
v
t
−
1
\alpha v_{t-1}
αvt−1
{
v
t
=
−
η
∇
J
(
θ
t
)
+
α
v
t
−
1
θ
t
+
1
=
θ
t
+
v
t
\left\{\begin{array}{ll} v_t = -\eta\nabla J(\theta_t) + \alpha v_{t-1} \\ \theta_{t+1} = \theta_{t} + v_{t} \\ \end{array}\right.
{vt=−η∇J(θt)+αvt−1θt+1=θt+vt
这里超参数 α \alpha α一般取值0.9左右。【可以看出,如果没有动量项,那么从A点走到B点后,B点就会走向 B ′ B^{\prime} B′点,在纵轴维度上方向相反,产生振荡。加入了动量项之后,合成的梯度方向就会更加向横轴方向移动,减少在纵轴方向上的移动,也就抑制了震荡。这样一步一步下去,带着初速度的小球就会极速的奔向损失函数的极小值点。】这里 v t − 1 v_{t-1} vt−1表示之前所有步骤累积的动量和。
缺点:这种情况相当于小球从山上滚下来时是在盲目地沿着坡滚,如果它能具备一些先验知识,例如快要上坡时,就知道需要减速了的话,适应性会更好。
自适应学习率算法
自适应学习率算法主要针对学习率的取值变化
AdaGrad
AdaGrad 算法是借鉴 L 2 L_2 L2 正则化的思想,每次迭代时自适应地调整每个参数的学习率, 也就是对学习率进行了一个约束。
原先我们有 Δ θ t = − η ∇ J \Delta \theta_t=-\eta \nabla J Δθt=−η∇J,现在我们先设定 g t = ∇ J ( θ t ) g_t = \nabla J(\theta_t) gt=∇J(θt)
然后我们计算每个参数梯度平方的累积值
G
t
=
∑
τ
=
1
t
g
τ
⊙
g
τ
G_{t}=\sum_{\tau=1}^{t} g_{\tau} \odot g_{\tau}
Gt=τ=1∑tgτ⊙gτ
也就是
n
t
=
n
t
−
1
+
g
t
2
n_{t}=n_{t-1}+g_{t}^{2}
nt=nt−1+gt2
这里 ⊙ \odot ⊙表示按元素乘积。 g τ ∈ R ∣ θ ∣ g_{\tau} \in \mathbb{R}^{|\theta|} gτ∈R∣θ∣是第 τ \tau τ次迭代时的梯度
然后我们对梯度进行缩放
Δ
θ
t
=
−
η
n
t
+
ϵ
⊙
g
t
\Delta \theta_{t}=-\frac{\eta}{\sqrt{n_{t}+\epsilon}} \odot g_{t}
Δθt=−nt+ϵη⊙gt
【这里是逐元素的应用除、和、求平方根,也就是开平方、除、加运算都是按元素进行的操作 。】
ϵ
\epsilon
ϵ是为了保持数值稳定性而设置的非常小的常数,一般 取值
e
−
7
e^{−7}
e−7 到
e
−
10
e^{−10}
e−10
最后 θ ← θ + Δ θ \boldsymbol{\theta} \leftarrow \boldsymbol{\theta}+\Delta \boldsymbol{\theta} θ←θ+Δθ
注意:此处,对 g t g_t gt从1到t进行一个递推形成一个约束项regularizer,用来保证分母非0.
【简单说,就是通过累计梯度平方调节学习率】
特点:
- 前期 g t g_t gt较小的时候,regularizer较大,能够放大梯度
- 后期 g t g_t gt较大的时候,regularizer较小,能够约束梯度, 适合处理稀疏梯度
缺点:
- 由公式可以看出,仍依赖于人工设置一个全局学习率 ϵ \epsilon ϵ设置过大的话,会使regularizer过于敏感,对梯度的调节太大
- 中后期,分母上梯度平方的累加将会越来越大,使gradient→0,使得训练提前结束。也就是经过一定次数的迭代,如果依然没有找到最优点时,由于这时的学习率已经非常小,很难再继续找到最优点
RMSprop
RMSprop 算法是 Geoff Hinton 提出的一种自适应学习率的方法可以在有些情况下避免 AdaGrad 算法中学习率不断单调下降以至于过早衰减的缺点。 RMSprop可以算作Adadelta的一个特例
RMSprop算法首先计算每次迭代梯度
g
t
g_t
gt平方的指数衰减平均:
n
t
=
β
n
t
−
1
+
(
1
−
β
)
g
t
2
n_{t}=\beta n_{t-1}+(1-\beta) g_{t}^{2}
nt=βnt−1+(1−β)gt2
也就是
G
t
=
β
G
t
−
1
+
(
1
−
β
)
g
t
⊙
g
t
G_{t}=\beta G_{t-1}+(1-\beta) g_{t} \odot g_{t}
Gt=βGt−1+(1−β)gt⊙gt
其中
β
\beta
β是衰减率,一般取值为0.9或者0.5
参数更新差值就变成
Δ
θ
t
=
−
η
G
t
+
ϵ
⊙
g
t
\Delta \theta_{t}=-\frac{\eta}{\sqrt{G_{t}+\epsilon}} \odot g_{t}
Δθt=−Gt+ϵη⊙gt
特点:
- 从上式可以看出,RMSProp 算法和 AdaGrad 算法的区别在于 G t G_t Gt的计算由累积方式变成了指数衰减移动平均。 在迭代过程中,每个参数的学习率并不是呈衰减趋势,既可以变小也可以变大
- RMSprop依然依赖于全局学习率
- RMSprop算是Adagrad的一种发展,和Adadelta的变体,效果趋于二者之间。适合处理非平稳目标 - 对于RNN效果很好
Adam
Adam 算法(Adaptive Moment Estimation Algorithm)可以看作动量法和 RMSprop算法的结合,不但使用动量作为参数更新方向,而且可以自适应调整学习率。它对梯度的一阶矩估计(First Moment Estimation,即梯度的均值)和二阶矩估计(Second Moment Estimation,即梯度的未中心化的方差)进行综合考虑,计算出更新步长。
Adam 算法的提出者描述其为两种随机梯度下降扩展式的优点集合,即:
- 适应性梯度算法(AdaGrad)为每一个参数保留一个学习率以提升在稀疏梯度(即自然语言和计算机视觉问题)上的性能。
- 均方根传播(RMSProp)基于权重梯度最近量级的均值为每一个参数适应性地保留学习率。这意味着算法在非稳态和在线问题上有很有优秀的性能。
假设
t
t
t时刻,目标函数对于参数的一阶导数是
,
g
t
,g_t
,gt那么我们分别计算梯度平方
g
t
2
g^{2}_{t}
gt2的指数加权平均和梯度
g
t
g_t
gt的指数加权平均(和动量法相似)
M
t
=
β
1
M
t
−
1
+
(
1
−
β
1
)
g
t
G
t
=
β
2
G
t
−
1
+
(
1
−
β
2
)
g
t
⊙
g
t
\begin{array}{r} M_{t}=\beta_{1} M_{t-1}+\left(1-\beta_{1}\right) g_{t} \\ G_{t}=\beta_{2} G_{t-1}+\left(1-\beta_{2}\right) g_{t} \odot g_{t} \end{array}
Mt=β1Mt−1+(1−β1)gtGt=β2Gt−1+(1−β2)gt⊙gt
接下来计算修正
M
^
t
=
M
t
1
−
β
1
t
G
^
t
=
G
t
1
−
β
2
t
\begin{aligned} \hat{M}_{t} &=\frac{M_{t}}{1-\beta_{1}^{t}} \\ \hat{G}_{t} &=\frac{G_{t}}{1-\beta_{2}^{t}} \end{aligned}
M^tG^t=1−β1tMt=1−β2tGt
这是因为当t=0时,如果
G
0
=
M
0
=
0
G_0=M_0=0
G0=M0=0, 那么在迭代初期,
G
t
G_t
Gt和
M
t
M_t
Mt的值会比真实的均值和方差要小。如果
β
1
\beta_1
β1和
β
2
\beta_2
β2都接近1时,偏差会很大。
最后我们的梯度更新为
Δ
θ
t
=
−
η
G
^
t
+
ϵ
M
^
t
\Delta \theta_{t}=-\frac{\eta}{\sqrt{\hat{G}_{t}+\epsilon}} \hat{M}_{t}\\
Δθt=−G^t+ϵηM^t
其中学习率
η
\eta
η通常设为0.001, 并且也可以通过
η
t
=
η
0
t
\eta_t=\dfrac{\eta_0}{\sqrt{t}}
ηt=tη0进行衰减操作。
Adam 在深度学习领域内是十分流行的算法,因为它能很快地实现优良的结果。经验性结果证明 Adam 算法 在实践中性能优异,相对于其他种类的随机优化算法具有很大的优势。主要包含以下几个显著的优点:
- 实现简单,计算高效,对内存需求少
- 参数的更新不受梯度的伸缩变换影响
- 超参数具有很好的解释性,且通常无需调整或仅需很少的微调 4. 更新的步长能够被限制在大致的范围内(初始学习率)
- 能自然地实现步长退火过程(自动调整学习率)
- 很适合应用于大规模的数据及参数的场景
- 适用于不稳定目标函数
- 适用于梯度稀疏或梯度存在很大噪声的问题
优化策略和元算法
批量归一化(batch Normalization)
对于一个神经网络,在第 L L L层的输入输出分别是 h L h_L hL和 Z L Z_L ZL, 为了提高优化效率,我们可以对净输入 h L h_L hL做归一化,使得分布一致。【为了提高归一化效率,一般使用标准化将净输入的每一维都归一到标准正态分布】
比如在上图的示例中,假设上一层的输入维度是10, 当前L层的维度是100,当前喂入网络的batch size是30。那么对于L层,在输入到非线性激活函数之前,我们有一个 30 × 100 30\times 100 30×100的矩阵。我们添加batch normalization层之后,对于每一个维度,每一列,我们都提取均值和方差,对所有样本沿着特征维度方向做归一化。比如第0列特征,我们用上面的式子计算新的向量 h ~ L 0 \tilde{h}_{L0} h~L0, 然后再把新的100个向量组成新的矩阵,然后再输入到激活函数。
其中, a a a和 b b b是训练出来。
批量归一化的效果就是让数据的取值分布尽可能的移动到激活函数的有效部分,尤其是sigmoid函数的线性变化区域
监督预训练
有时,如果模型太复杂难以优化,或是如果任务非常困难,直接训练模型来解决特定任务的挑战可能 太大。有时训练一个较简单的模型来求解问题,然后使模型更复杂会更有效。训练模型来求解一个简化的问题,然后转移到最后的问题,有时也会更有效些。这些在直接训练目标模型求解目标问题之前, 训练简单模型求解简化问题的方法统称为预训练(pretraining)
设计有助于优化的模型
改进优化的最好方法并不总是改进优化算法。相反,深度模型中优化的许多改进来自于设计易于优化的模型。
现代神经网络的设计选择体现
- 在层之间的线性变换,
- 几乎处处可导的激活函数
- 大部分定义域都有明显的梯度。
特别地,创新的模型,如 LSTM,整流线性单元和 maxout 单元都比先前的模型(如基于sigmoid 单 元的深度网络)使用更多的线性函数。这些模型都具有简化优化的性质。如果线性变换的 Jacobian 具有相对合理的奇异值,那么梯度能够流经很多层。此外,线性函数在一个方向上一致增加,所以即使模型的输出远离正确值,也可以简单清晰地计算梯度,使其输出方向朝降低损失函数的方向移动。换言之,现代神经网络的设计方案旨在使其局部梯度信息合理地对应着移向一个遥远的解。
其他的模型设计策略有助于使优化更简单。
- 层之间的线性路径或是跳跃连接减少了从较低层参数到输出最短路径的长度,因而缓解了梯度消失的问题(比如ResNet)。
- 一个和跳跃连接相关的想法是添加和网络中间隐藏层相连的输出的额外副本,如 GoogLeNet和深度监督网络 。这些 ‘‘辅助头’’ 被训练来执行和网络顶层主要输出相 同的任务,以确保底层网络能够接受较大的梯度。当训练完成时,辅助头可能被丢弃。这是之前小节介绍到 的预训练策略的替代方法。
以这些方式,我们可以在一个阶段联合训练所有层,而不改变架构,使得中间层 (特别是低层)能够通过更短的路径得到一些如何更新的有用信息。这些信息为底层提供了误差信号。