深度学习中的优化方法(二)
在上一篇文章中 深度学习中的优化方法(一) – ZhiboZhao – 博客园 (cnblogs.com) 我们主要讲到了一维函数 \(f(x):R \rightarrow R\) 的优化方法,在实际情况中,待优化的函数往往是多维的 \(f(x):R^{n} \rightarrow R\),因此本文我们来探讨一下更普遍的多维函数的优化算法。
一、常用的优化算法总结
- 一阶方法:随机梯度下降(SGD)、动量(Momentum)、牛顿动量法(Nesterov动量)、AdaGrad(自适应梯度)、RMSProp(均方差传播)、Adam、Nadam。
- 二阶方法:牛顿法、拟牛顿法、共轭梯度法(CG)、BFGS、L-BFGS。
- 自适应优化算法有哪些?(Adagrad(累积梯度平方)、RMSProp(累积梯度平方的滑动平均)、Adam(带动量的RMSProp,即同时使用梯度的一、二阶矩))。
- 梯度下降陷入局部最优有什么解决办法?可以用BGD、SGD、MBGD、momentum,RMSprop,Adam等方法来避免陷入局部最优。
二、梯度下降法
2.1 梯度下降法的基本原理
对于函数 \(f:R^{n} \rightarrow R\) ,满足 \(f(\text{x}) = c, \text{x} \in R^{n}\) 的所有 \(\text{x}\) 组成的集合,称为函数 \(f\) 的水平集。如下图所示:
如果函数在 \(\text{x}_{0}\) 处的梯度 \(\nabla f(\text{x}_{0})\) 不是0向量,那么它与水平集 \(f(\text{x})=c\) 中任意一条经过 \(\text{x}_{0}\) 的曲线的切向量正交。因此一个实值可微函数在某点处的函数值增加最快额方向正交于经过该点的函数水平集。梯度下降法根据上述的性质,首先给定一个初始点 \(\text{x}^{k}\),由该点出发沿着该点的负梯度方向更新一段距离 \(\alpha_{k}\),称为步长,构造出新的点 \(\text{x}^{k+1}\),如此往复便可得到迭代公式:
\]
这种方法便称为梯度下降法,在搜索过程中,梯度不断变化,越接近极小值梯度就越小,变化越缓慢,因此要适当对步长 \(\alpha_{k}\) 进行调整。梯度下降法是一个类,其中包括很多种不同的具体算法,下面就来简单地介绍一下。
2.2 梯度下降法的具体实现
在介绍具体的算法之前,我们先确定待优化的损失函数:
\]
其中,\(J(θ)\) 是损失函数,\(m\) 代表每次取多少样本进行训练, \(\Theta \in R^{n}\) 表示待优化的参数。于是便可计算出损失函数在任意点处的梯度:
\]
于是,最小化损失函数,所以参数 \(\Theta_{j}\) 按照负梯度的方向来更新:
\]
2.2.1 随机梯度下降(SGD)
随机梯度下降法求梯度时选取一个样本j来求梯度。
\]
写成伪代码如下:
for i in range(nb_epochs):
np.random.shuffle(data)
for example in data:
params_grad = evaluate_gradient(loss_function , example ,params)
params = params - learning_rate * params_grad
优点:(1)由于不是在全部训练数据上的损失函数,而是在每轮迭代中,随机优化某一条训练数据上的损失函数,这样每一轮参数的更新速度大大加快。
缺点:(1)准确度下降。(2)可能会收敛到局部最优,由于单个样本并不能代表全体样本的趋势。(3)不易于并行实现。 SGD 因为更新比较频繁,会造成 cost function 有严重的震荡。
2.2.2 批量梯度下降 (BGD)
批量梯度下降法,是梯度下降法最常用的形式,具体做法也就是在更新参数时使用所有的样本来进行更新。写成伪代码如下:
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params)
params = params - learning_rate * params_grad
优点:(1)一次迭代是对所有样本进行计算,此时利用矩阵进行操作,实现了并行。(2)由全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。
缺点:(1)当样本数目 m 很大时,每迭代一步都需要对所有样本计算,训练过程会很慢。(2)不能投入新数据实时更新模型。
2.2.3 部分批量梯度下降(mini-batch GD)
小批量梯度下降法是是对于m个样本,我们采用x个样子来迭代,1<x<m。一般可以取x=10,当然根据样本的数据,可以调整这个x的值。伪代码如下:
for i in range(nb_epochs):
np.random.shuffle(data)
for batch in get_batches(data, batch_size=50):
params_grad = evaluate_gradient(loss_function, batch, params)
params = params - learning_rate * params_grad
优点:(1)通过矩阵运算,每次在一个batch上优化神经网络参数并不会比单个数据慢太多。(2)每次使用一个batch可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果。(比如上例中的30W,设置batch_size=100时,需要迭代3000次,远小于SGD的30W次)(3)可实现并行化。
2.3 梯度下降法的改进
2.3.1 Momentum
上述梯度下降法仅仅考虑在当前迭代时刻的梯度,这样容易落到极小值点。而动量法模拟的是物体在运动时候的惯性,即更新的时候在一定程度上保留之前更新的方向,同时利用当前batch的梯度微调最终的更新方向。这样一来,可以在一定程度上增加稳定性,从而学习地更快,并且还有一定摆脱局部最优的能力。
v_{t} &=\gamma v_{t-1}+\eta \nabla_{\theta} J(\theta) \\
\theta &=\theta-v_{t}
\end{aligned}
\]
2.3.2 Adagrad
在深度网络训练中,对于经常更新的参数,我们已经积累了大量关于它的知识,不希望被单个样本影响太大,希望学习速率慢一些;对于偶尔更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本身上多学一些,即学习速率大一些。怎么样去度量历史更新频率呢?那就是二阶动量——该维度上,迄今为止所有梯度值的平方和:
梯度更新规则:
\]
其中g为:t时刻参数θ_i的梯度
\]
如果是普通的 SGD, 那么 θ_i 在每一时刻的梯度更新公式为:
\]
但这里的learning rate η也随t和i而变:
\]
其中 Gt 是个对角矩阵, (i,i) 元素就是 t 时刻参数 θi 的梯度平方和。这一方法在稀疏数据场景下表现非常好。它的缺点是分母会不断积累,这样学习率就会收缩并最终会变得非常小,甚至会使得优化过程提前结束。
2.3.3 RMSProp
由于AdaGrad单调递减的学习率变化过于激进,我们考虑一个改变二阶动量计算方法的策略:不累积全部历史梯度,而只关注过去一段时间窗口的下降梯度。梯度更新规则为:
\theta_{t+1}=\theta_{t}-\frac{\eta}{\sqrt{E\left[g^{2}\right]_{t}+\epsilon}} g_{t}
\end{array}
\]
其中 E 的计算公式如下,t 时刻的依赖于前一时刻的平均和当前的梯度:
\]
2.3.4 Adam
Adam 算法和传统的随机梯度下降不同。随机梯度下降保持单一的学习率(即 alpha)更新所有的权重,学习率在训练过程中并不会改变。而 Adam 通过计算梯度的一阶矩估计和二阶矩估计而为不同的参数设计独立的自适应性学习率。这个算法是另一种计算每个参数的自适应学习率的方法,相当于 RMSprop + Momentum。
除了像 Adadelta 和 RMSprop 一样存储了过去梯度的平方 vt 的指数衰减平均值 ,也像 momentum 一样保持了过去梯度 mt 的指数衰减平均值:
m_{t}=\beta_{1} m_{t-1}+\left(1-\beta_{1}\right) g_{t} \\
v_{t}=\beta_{2} v_{t-1}+\left(1-\beta_{2}\right) g_{t}^{2}
\end{array}
\]
如果mt和vt被初始化为0向量,那它们就会向0偏置,所以做了偏差校正,通过计算偏差校正后的mt和vt来抵消这些偏差:
\hat{m}_{t}=\frac{m_{t}}{1-\beta_{1}^{t}} \\
\hat{v}_{t}=\frac{v_{t}}{1-\beta_{2}^{t}}
\end{array}
\]
梯度更新规则:
\]
超参数设定值:建议 β1 = 0.9,β2 = 0.999,ϵ = 10e−8。
实践表明,Adam 比其他适应性学习方法效果要好。
Adam 和 SGD 区别:Adam = Adaptive + Momentum,顾名思义Adam集成了SGD的一阶动量和RMSProp的二阶动量。
三、牛顿法
在确定搜索方向时,梯度下降法只用到了目标函数的一阶导数(梯度),然而如果能在迭代过程中引入二阶导数,其效率有可能会超过梯度下降法。牛顿法就是如此,它同时使用一阶和二阶导数来确定搜索方向。其具体原理如下:
当目标函数 \(f:R^{n} \rightarrow R\) 二阶连续可微时,将函数在 \(x^{k}\) 处进行泰勒展开,得到二次型近似函数:
\]
其中,\(F(x^{k})\) 代表优化函数 \(f(x)\) 在 \(x^{k}\) 处的黑塞矩阵。因此求 \(f(x)\) 的最小值,等效为:
\]
进一步可得,迭代过程为:
\]
类似于一维牛顿搜索法,当 \(f”(x) < 0\) 时,牛顿法无法收敛极小值点,因此当黑塞矩阵 \(F(x^{k})\) 为非正定时,牛顿法确定的搜索方向不一定是目标函数值的下降方向。下面简单回顾一下黑塞矩阵极其性质。
在介绍黑塞矩阵之前,我们先来回顾一下一维函数 \(y=f(x), x \in R\) 在 \(x_{0}\) 处存在极值的充要条件:\(f'(x_{0})=0\) 且 \(f”(x_{0}) != 0\) ,当 $f”(x_{0})>0 $ 时, \(x_{0}\) 为极小值,当 \(f”(x_{0}) < 0\) 时,\(x_{0}\) 为极大值。
对于二维函数 \(z = f(x,y)\) 来说,假设 \(A=f_{xx}(x_{0},y_{0}), B = f_{xy}(x_{0},y_{0}), C_{yy}(x_{0},y_{0})\),那么 \((x_{0}, y_{0})\) 为极值的充要条件为:\(f'(x_{0},y_{0})=0\), 且 \(AC – B^{2} > 0\)。当 \(A>0\) 时为极小值点,当\(A<0\) 时为极大值点。可以写成:
A&B\\
B&C\\
\end{bmatrix}=\begin{bmatrix}
\dfrac{\partial^{2} f(x)}{\partial x^{2}}&\dfrac{\partial^{2} f(x)}{\partial xy}\\
\dfrac{\partial^{2} f(x)}{\partial xy}&\dfrac{\partial^{2} f(x)}{\partial y^{2}}\\
\end{bmatrix}
\]
其中,矩阵 \(H\) 就是黑塞矩阵,其他维度的黑塞矩阵类似。那么对于二维变量来说,判断极值点的条件就等价为:
- \(f'(x_{0},y_{0})=0\);
- \(|H|>0\) 且 \(A>0\),为极小值;\(|H|>0\) 且 \(A<0\),为极大值;
那么对于多维函数 \(f:R^{n} \rightarrow R\) 而言,判断极值点的条件可以推广为:
- \(f'(x_{1}, x_{2},…x_{n})=0\);
- \(|H|>0\) 且 \(H\) 的顺序主子式均大于 0 ,为极小值(\(H\) 为正定矩阵);\(|H|>0\) 且 ,且 \(H\) 的顺序主子式均小于 0(\(H\) 为负定矩阵),为极大值;
因此,牛顿法的缺点为:
- 对目标函数有较严格的要求。函数必须具有连续的一、二阶偏导数,海海森矩阵必须正定。
- 计算相当复杂,除需要计算梯度以外,还需要计算二阶偏导数矩阵和它的逆矩阵。计算量、存储量均很⼤,且均以维数N的平⽅增加,当N很⼤时这个问题更加突出。
⽜顿法虽然收敛速度快,但是计算过程中需要计算目标函数的二阶偏导数,计算复杂度较⼤。而且有时目标函数的海森矩阵无法保持正定,从而使⽜顿法失效。为了克服这两个问题,⼈们提出了拟⽜牛顿法。这个方法的基本思想是:不⽤⼆阶偏导数而构造出可以近似海森矩阵或者海森矩阵的逆的正定对称阵,在拟⽜顿的条件下优化⽬目标函数。不同的构造⽅法就产生了不同的拟牛顿法。
四、参考资料
《最优化导论第四版》孙志强,白圣建等译
CV总复习-深度学习机器学习基础篇(一),作者灯会
https://zhuanlan.zhihu.com/p/32230623