优化器算法
梯度下降算法
首先引用动手学深度学习中对梯度下降算法的直观理解与推导。说明了不断的迭代可能会使得f(x)的值不断下降,从直观上解释了梯度下降的可能性。
- 将损失函数在x点处一阶泰勒展开。
f ( x + ϵ ) = f ( x ) + ϵ f ′ ( x ) + O ( ϵ 2 ) . f(x+\epsilon)=f(x)+\epsilon f^{\prime}(x)+\mathcal{O}\left(\epsilon^{2}\right) . f(x+ϵ)=f(x)+ϵf′(x)+O(ϵ2).
即在一阶近似中,f(x十ε)可通过x处的函数值f(x)和一阶导数f’(x)得出。我们可以假设在负梯度方向上移动的ε会减少f。为了简单起见,我们选择固定步长 n>0,然后取ε = -nf’(x)。
- 将其代入泰勒展开式中可以得到下面的式子:n>0和f’(x)的平方大于0经过化简可以得到第二个式子。
f ( x − η f ′ ( x ) ) = f ( x ) − η f ′ 2 ( x ) + O ( η 2 f ′ 2 ( x ) ) . f\left(x-\eta f^{\prime}(x)\right)=f(x)-\eta f^{\prime 2}(x)+\mathcal{O}\left(\eta^{2} f^{\prime 2}(x)\right) . f(x−ηf′(x))=f(x)−ηf′2(x)+O(η2f′2(x)).
f ( x − η f ′ ( x ) ) ≲ f ( x ) . f\left(x-\eta f^{\prime}(x)\right) \lesssim f(x) . f(x−ηf′(x))≲f(x).
- 最后我们说明了如果使用
下面的式子
来迭代x的值则会使得f(x)的值不断的下降到极小值,梯度为0时终止。
x ← x − η f ′ ( x ) x \leftarrow x-\eta f^{\prime}(x) x←x−ηf′(x)
总结:梯度下降算法最初提出是解决凸优化的问题,但在神经网络中损失函数的优化问题不一定全部是凸优化问题,通常情况下是找一个局部的极值。
L ( f ( x i , θ ) , y i ) 损失函数 L\left(f\left(x_{i}, \theta\right), y_{i}\right) \text { 损失函数 } L(f(xi,θ),yi) 损失函数
∇ θ L ( f ( x i , θ ) , y i ) g = 1 N ∇ θ ∑ i = 1 N L ( f ( x i , θ ) , y i ) θ ← θ − ε g \begin{array}{l} \nabla_{\theta} L\left(f\left(x_{i}, \theta\right), y_{i}\right) \\ g=\frac{1}{N} \nabla_{\theta} \sum_{i=1}^{N} L\left(f\left(x_{i}, \theta\right), y_{i}\right) \\ \theta \leftarrow \theta-\varepsilon g \end{array} ∇θL(f(xi,θ),yi)g=N1∇θ∑i=1NL(f(xi,θ),yi)θ←θ−εg
梯度下降的步骤
梯度下降算法的核心思想是通过迭代的调整参数,逐步找到函数的局部最小值这个过程可以概括为以下几个步骤:
-
初始化参数:选择一个初始点作为参数的起始值,这些参数对应于损失函数的变量!
-
计算梯度:在当前参数值处,计算损失函数的梯度(即导数)。梯度指向损失函数变化最快的方向。(或者是求梯度的平均值)
-
更新参数:根据梯度和一个预先设定的学习率(步长)来更新参数。参数更新的公式通常是:
θ = θ − η ⋅ ∇ J ( θ ) \theta=\theta-\eta \cdot \nabla J(\theta) θ=θ−η⋅∇J(θ)
一维梯度下降
首先从最简单的一元线性回归来说明梯度下降算法的步骤,损失函数采用回归任务中最常用的均方误差损失。
L = 1 2 ∑ i = 1 3 [ y i − ( w ^ x i + b ) ] 2 \begin{array}{c} L=\frac{1}{2} \sum_{i=1}^{3}\left[y_{i}-\left(\widehat{w} x_{i}+b\right)\right]^{2} \\ \end{array} L=21∑i=13[yi−(w xi+b)]2
L = 1 2 ∑ i = 1 3 b 2 + 2 ( w ^ x i − y i ) b + ( y i − w ^ x i ) 2 L=\frac{1}{2} \sum_{i=1}^{3} b^{2}+2\left(\widehat{w} x_{i}-y_{i}\right) b+\left(y_{i}-\widehat{w} x_{i}\right)^{2} L=21i=1∑3b2+2(w xi−yi)b+(yi−w xi)2
将损失函数求最小值的问题转换为了二次函数求最值的问题,二次函数显然是凸函数,是一个典型的凸优化问题。
多维梯度下降
现在我们对单变量的情况有了更好的理解,让我们考虑一下X[x1,x2,x3…xd]的情况。 即目标函数含有多个变量的问题,区别在于在求导时采用的时求解的是梯度向量的形式。
∇ f ( x ) = [ ∂ f ( x ) ∂ x 1 , ∂ f ( x ) ∂ x 2 , … , ∂ f ( x ) ∂ x d ] ⊤ \nabla f(\mathbf{x})=\left[\frac{\partial f(\mathbf{x})}{\partial x_{1}}, \frac{\partial f(\mathbf{x})}{\partial x_{2}}, \ldots, \frac{\partial f(\mathbf{x})}{\partial x_{d}}\right]^{\top} ∇f(x)=[∂x1∂f(x),∂x2∂f(x),…,∂xd∂f(x)]⊤
对每一个变量参数分别进行迭代优化:
x
i
←
x
i
−
η
∗
∇
f
(
X
)
x_{i} \leftarrow x_{i}-\eta * \nabla f(X)
xi←xi−η∗∇f(X)
梯度下降算法分类
梯度下降法有三种不同的形式:
- BGD(Batch GradientDescent):批量梯度下降,每次参数更新使用所有样本
- SGD(Stochastic GradientDescent):随机梯度下降,每次参数更新只使用1个样本
- MBGD(Mini-Batch GradientDescent):小批量随机梯度下降,每次参数更新使用小批量数据样本(minibatch)
小批量随机梯度下降
梯度下降(gradient descent)的方法, 这种方法几乎可以优化所有深度学习模型。 它通过不断地在损失函数递减的方向上更新参数来降低误差。
梯度下降最简单的用法是计算损失函数(数据集中所有样本的损失均值) 关于模型参数的导数(在这里也可以称为梯度)。 但实际中的执行可能会非常慢:因为在每一次更新参数之前,我们必须遍历整个数据集。 因此,我们通常会在每次需要计算更新的时候随机抽取一小批样本, 这种变体叫做小批量随机梯度下降(minibatch stochastic gradient descent)。
我们计算小批量的平均损失关于模型参数的导数(也可以称为梯度)。 最后,我们将梯度乘以一个预先确定的正数n,并从当前参数的值中减掉。
w ← w − η ∣ B ∣ ∑ i ∈ B ∂ w l ( i ) ( w , b ) = w − η ∣ B ∣ ∑ i ∈ B x ( i ) ( w ⊤ x ( i ) + b − y ( i ) ) , b ← b − η ∣ B ∣ ∑ i ∈ B ∂ b l ( i ) ( w , b ) = b − η ∣ B ∣ ∑ i ∈ B ( w ⊤ x ( i ) + b − y ( i ) ) . \begin{aligned} \mathbf{w} & \leftarrow \mathbf{w}-\frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{\mathbf{w}} l^{(i)}(\mathbf{w}, b)=\mathbf{w}-\frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \mathbf{x}^{(i)}\left(\mathbf{w}^{\top} \mathbf{x}^{(i)}+b-y^{(i)}\right), \\ b & \leftarrow b-\frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{b} l^{(i)}(\mathbf{w}, b)=b-\frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}}\left(\mathbf{w}^{\top} \mathbf{x}^{(i)}+b-y^{(i)}\right) . \end{aligned} wb←w−∣B∣ηi∈B∑∂wl(i)(w,b)=w−∣B∣ηi∈B∑x(i)(w⊤x(i)+b−y(i)),←b−∣B∣ηi∈B∑∂bl(i)(w,b)=b−∣B∣ηi∈B∑(w⊤x(i)+b−y(i)).
( w , b ) ← ( w , b ) − η ∣ B ∣ ∑ i ∈ B ∂ ( w , b ) l ( i ) ( w , b ) . (\mathbf{w}, b) \leftarrow(\mathbf{w}, b)-\frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w}, b)} l^{(i)}(\mathbf{w}, b) . (w,b)←(w,b)−∣B∣ηi∈B∑∂(w,b)l(i)(w,b).
我们通常所说的SGD其实指定就是小批量随机梯度下降算法。
优缺点总结
- 优点:算法简洁,当学习率取值恰当时,可以收敛到全局最优点(凸函数)或局部最优点(非凸函数)。
缺点
:
- 对超参数学习率比较敏感:过小导致收敛速度过慢,过大又越过极值点。
- 学习率除了敏感,有时还会因其在迭代过程中保持不变,很容易造成算法被卡在鞍点的位置。
- 在较平坦的区域,由于梯度接近于0,优化算法会因误判,在还未到达极值点时,就提前结束迭代,陷入局部极小值。
之后的算法优化是从梯度方面和学习率方面对整个优化器算法进行优化。
动量法
动量法可以看作是:带有动量的随机梯度下降算法。
思想:让参数的更新具有惯性,每一步更新都是由前面梯度的累积和当前点梯度g组合而成。
优化器算法的执行步骤:累加梯度更新+参数更新
累加梯度更新:
v ← α v + ( 1 − α ) g . 其中, α 为动量参数, v 为累计梯度, v 为当前梯度, η 为学习率 v \leftarrow \alpha v+(1-\alpha) g \text {. 其中, } \alpha \text { 为动量参数, } v \text { 为累计梯度, } v \text { 为当前梯度, } \eta \text { 为学习率 } v←αv+(1−α)g. 其中, α 为动量参数, v 为累计梯度, v 为当前梯度, η 为学习率
参数更新:
x ← x − η ∗ v x \leftarrow x-\eta * v x←x−η∗v
动手学深度学习中给出的动量法公式:
v t ← β v t − 1 + g t , x t ← x t − 1 − η t v t . \begin{array}{l} \mathbf{v}_{t} \leftarrow \beta \mathbf{v}_{t-1}+\mathbf{g}_{t}, \\ \mathbf{x}_{t} \leftarrow \mathbf{x}_{t-1}-\eta_{t} \mathbf{v}_{t} . \end{array} vt←βvt−1+gt,xt←xt−1−ηtvt.
我们通过a变量来控制动量。
优点:
-
加快收敛能帮助参数在正确的方向上加速前进
-
可以帮助跳出局部最小值
AdaGrad算法
Adagrad优化算法被称为自适应学习率优化算法
之前我们讲的随机梯度下降法,对所有的参数,都是使用相同的、固定的学习率进行优化的,但是不同的参数的梯度差异可能很大,使用相同的学习率
,效果不会很好。
举例 : 假设损失函数是 f ( x ) = x 1 2 + 10 x 2 2 , x 和 y 的初值分别为 x 1 = 40 , x 2 = 20 举例: 假设损失函数是 f(x)=x_{1}^{2}+10 x_{2}^{2}, x 和 y 的初值分别为 x_{1}=40, x_{2}=20 举例:假设损失函数是f(x)=x12+10x22,x和y的初值分别为x1=40,x2=20
( 通过观察 , 我们即可知道 , x 1 = 0 , x 2 = 0 就是两个参数的极值点 ) (通过观察, 我们即可知道, x_{1}=0, x_{2}=0 就是两个参数的极值点) (通过观察,我们即可知道,x1=0,x2=0就是两个参数的极值点)
→ ∂ l o s s ∂ x 1 = 80 , ∂ l o s s ∂ x 2 = 400 → x 1 \rightarrow \frac{\partial l o s s}{\partial x_{1}}=80, \frac{\partial l o s s}{\partial x_{2}}=400 \quad \rightarrow x_{1} →∂x1∂loss=80,∂x2∂loss=400→x1
将要移动的幅度小于 x 2 将移动的幅度而 x 1 距离离极值点 x 1 = 0 是较远的 , 所以 , 我们使用梯度下降法 , 效果并不会好 将要移动的幅度 小于 x_{2} 将移动的幅度而 x_{1} 距离离极值点 x_{1}=0 是较远的, 所以, 我们使用梯度下降法, 效果并不会好 将要移动的幅度小于x2将移动的幅度而x1距离离极值点x1=0是较远的,所以,我们使用梯度下降法,效果并不会好
Adagrad思想:对于不同参数,设置不同的学习率
算法步骤
- 方法:对于每个参数,初始化一个累计平方梯度r=0将该参数的梯度平方求和累加到这个变量r上:
g
=
1
m
∇
θ
∑
i
=
1
m
L
(
f
(
x
i
,
θ
)
,
y
i
)
g=\frac{1}{m} \nabla_{\theta} \sum_{i=1}^{m} L\left(f\left(x_{i}, \theta\right), y_{i}\right)
g=m1∇θi=1∑mL(f(xi,θ),yi)
r
←
r
+
g
2
r \leftarrow r+g^{2}
r←r+g2
- 然后,在更新这个参数的时候,学习率就变为:
θ ← θ − ε r + δ g \theta \leftarrow \theta-\frac{\varepsilon}{\sqrt{r}+\delta} g θ←θ−r+δεg
δ 是一个小量,稳定数值计算一般取值为 1 0 − 10 \delta 是一个小量,稳定数值计算一般取值为10^{-10} δ是一个小量,稳定数值计算一般取值为10−10
- 最后我们进行
权重的更新
完成整个算法:
w ← w − η r + δ ∗ g w \leftarrow w-\frac{\eta}{\sqrt{r+\delta}} * g w←w−r+δη∗g
这样,不同的参数由于梯度不同,他们对应的r大小也就不同,所以学习率也就不同,这也就实现了自适应的学习率。
总结:Adagrad 的核心想法就是,如果一个参数的梯度一直都非常大,那么其对应的学习率就变小一点,防止震荡,而一个参数的梯度一直都非常小,那么这个参数的学习率就变大一点,使得其能够更快地更新,这就是Adagrad算法加快深层神经网络的训练速度的核心。
RMSProp算法
RMSProp:Root MeanSquare Propagation均方根传播。
RMSProp是在adagrad的基础上,进一步在学习率的方向上优化经过改进后在2012年提出的一个算法。
g = 1 m ∇ θ ∑ i = 1 m L ( f ( x i , θ ) , y i ) g=\frac{1}{m} \nabla_{\theta} \sum_{i=1}^{m} L\left(f\left(x_{i}, \theta\right), y_{i}\right) g=m1∇θi=1∑mL(f(xi,θ),yi)
在adagrad算法中r的变化之和梯度g有关,可能会存在让学习率过小而无法进行控制的问题 在此基础上我们引入了一个新的变量衰减系数p
衰减系数p
可以手动调节从而优化学习过程。
r ← ρ r + ( 1 − ρ ) g 2 θ ← θ − ε r + δ g \begin{array}{l} r \leftarrow \rho r+(1-\rho) g^{2} \\ \theta \leftarrow \theta-\frac{\varepsilon}{\sqrt{r+\delta}} g \end{array} r←ρr+(1−ρ)g2θ←θ−r+δεg
Adam算法
Adam算法可以理解为在原始梯度下降的基础上,同时对梯度
和学习率
两个方面同时进行改进。并结合了之前所提出算法的优点。
是使用了动量和自适应学习率的集大成算法,也是目前使用最为广泛的优化器算法之一。
算法步骤
Adam算法的关键组成部分之一是:它使用指数加权移动平均值来估算梯度的动量和二次矩,即它使用状态变量:
- 在梯度方向增加动量,同时采用和RMSProp算法相同的学习率调整方法,进行
累计梯度平方的计算
v t ← β 1 v t − 1 + ( 1 − β 1 ) g t s t ← β 2 s t − 1 + ( 1 − β 2 ) g t 2 \begin{array}{l} \mathbf{v}_{t} \leftarrow \beta_{1} \mathbf{v}_{t-1}+\left(1-\beta_{1}\right) \mathbf{g}_{t} \\ \mathbf{s}_{t} \leftarrow \beta_{2} \mathbf{s}_{t-1}+\left(1-\beta_{2}\right) \mathbf{g}_{t}^{2} \end{array} vt←β1vt−1+(1−β1)gtst←β2st−1+(1−β2)gt2
- 进行偏差的调整与纠正
v ^ t = v t 1 − β 1 t and s ^ t = s t 1 − β 2 t . \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}} . v^t=1−β1tvt and s^t=1−β2tst.
- 写出更新方程并进行权重的更新操作。(将学习率和动量值结合在一起进行实现)
g t ′ = η v ^ t s ^ t + ϵ . \mathbf{g}_{t}^{\prime}=\frac{\eta \hat{\mathbf{v}}_{t}}{\sqrt{\hat{\mathbf{s}}_{t}}+\epsilon} . gt′=s^t+ϵηv^t.
x t ← x t − 1 − g t ′ \mathbf{x}_{t} \leftarrow \mathbf{x}_{t-1}-\mathbf{g}_{t}^{\prime} xt←xt−1−gt′
w ← w − η r ^ + δ ∗ v ^ w \leftarrow w-\frac{\eta}{\sqrt{\hat{r}+\delta}} * \hat{v} w←w−r^+δη∗v^