计算机视觉(五):深度学习优化算法

计算机视觉笔记总目录


1 优化算法

优化的目标在于降低训练损失,只关注最小化目标函数上的表现]

深度学习问题中,我们通常会预先定义一个损失函数。有了损失函数以后,我们就可以使用优化算法试图将其最小化。在优化中,这样的损失函数通常被称作优化问题的目标函数(objective function)。依据惯例,优化算法通常只考虑最小化目标函数。

1.1优化遇到的挑战

  • 局部最优
  • 梯度消失

1.2 局部最优

定义: 对于目标函数f(x),如果f(x)在x上的值比在x邻近的其他点的值更小,那么f(x)可能是一个局部最小值(local minimum)。 如果f(x)在x上的值是目标函数在整个定义域上的最小值,那么f(x)是全局最小值(global minimum)。

比如下面给定的函数
f ( x ) = x ⋅ cos ( π x ) , − 1.0 ≤ x ≤ 2.0 f(x) = x \cdot \text{cos}(\pi x), \qquad -1.0 \leq x \leq 2.0 f(x)=xcos(πx),1.0x2.0

在这里插入图片描述
如果拓展到多维上面,比如下面的图形表示一个损失函数。

在这里插入图片描述
当一个优化问题的数值解在局部最优解附近时,由于目标函数有关解的梯度接近或变成零,最终迭代求得的数值解可能只令目标函数局部最小化而非全局最小化。

1.3 鞍点与海森矩阵(Hessian Matric)

刚刚我们提到,梯度接近或变成零可能是由于当前解在局部最优解附近造成的。事实上,另一种可能性是当前解在鞍点(saddle point)附近。

  • 鞍点(saddle) 是函数上的导数为零,但不是轴上局部极值的点。通常梯度为零的点是下图所示的鞍点,而非局部最小值。减少损失的难度也来自误差曲面中的鞍点,而不是局部最低点。

比如给定函数
f ( x ) = x 3 f(x) = x^3 f(x)=x3

在这里插入图片描述
多元函数上显示如下:
在这里插入图片描述
上图中,目标函数在CD方向是一个局部最大值,但是在AB方向是一个局部最小值。所有当某个函数在梯度为0的位置上可能是局部最小值、局部最大值或者鞍点。

条件:

  • 当函数的海森矩阵在梯度为零的位置上的特征值全为正时,该函数得到局部最小值
  • 当函数的海森矩阵在梯度为零的位置上的特征值全为负时,该函数得到局部最大值
  • 当函数的海森矩阵在梯度为零的位置上的特征值有正有负时,该函数得到鞍点

为什么海森矩阵判断?

回想一下我们是如何处理一元函数求极值问题的。例如, f ( x ) = x 2 f(x)=x^2 f(x)=x2,我们会先求一阶导数,即 f ′ ( x ) = 2 x f'(x)=2x f(x)=2x,某点处的一阶导数一定等于 0。但这仅是一个必要条件,而非充分条件。对于 f ( x ) = x 2 f(x)=x^2 f(x)=x2来说,函数的确在一阶导数为零的点取得了极值,但是对于 f ( x ) = x 3 f(x)=x^3 f(x)=x3来说,显然只检查一阶导数是不足以下定论的。

在这里插入图片描述在这里插入图片描述
海森矩阵:

  • 海森矩阵最早于19世纪由德国数学家Ludwig Otto Hesse提出,并以其名字命名。利用黑塞矩阵可判定多元函数的极值问题。
  • 一个多元函数的二阶偏导数构成的方阵

例子:
f ( x , y , z ) = x 2 + y 2 + z 2 + 2 x + 4 y − 6 z f(x,y,z) = x^2+y^2+z^2+2x+4y-6z f(x,y,z)=x2+y2+z2+2x+4y6z

求这个多元函数的极值:

  1. 首先对于某个变量(总共三个变量参数)的一阶导数为 0 0 0,意味着在这个变量方向上是极小或者极大值
    ∂ f ∂ x = 2 x + 2 = 0 , ∂ f ∂ y = 2 y + 4 = 0 , ∂ f ∂ z = 2 z − 6 = 0 \frac{\partial f}{\partial x} = 2x+2=0,\frac{\partial f}{\partial y} = 2y+4=0,\frac{\partial f}{\partial z} = 2z-6=0 xf=2x+2=0,yf=2y+4=0,zf=2z6=0

    则三元函数的驻点 ( − 1 , − 2 , 3 ) (-1, -2, 3) (1,2,3),表示在三个变量方向上都梯度都是为 0 0 0 的,但是这个点不知道是极小值或者极大值或者鞍点

  2. 求二阶导数
    ∂ 2 f ∂ x 2 = 2 , ∂ 2 f ∂ y 2 = 2 , ∂ 2 f ∂ z 2 = 2 \frac{\partial{^2} f}{\partial x{^2}} = 2,\frac{\partial{^2} f}{\partial y{^2}} = 2,\frac{\partial{^2} f}{\partial z{^2}} = 2 x22f=2,y22f=2,z22f=2

    则表示成海森矩阵
    A = ( 2 0 0 0 2 0 0 0 2 ) A = {\begin{pmatrix} 2&0&0\\ 0&2&0\\ 0&0&2 \end{pmatrix}} A=200020002

    A矩阵所有值为正(正定矩阵)故 ( − 1 , − 2 , 3 ) (-1, -2, 3) (1,2,3)是极小值点,极小值为 f ( − 1 , − 2 , 3 ) = − 14 f(-1,-2,3)=-14 f(1,2,3)=14

总结:海森矩阵可用于判断多元函数的极值点问题。

1.4 梯度消失

为什么会造成我们的损失函数难优化,其实有个原因就是因为激活函数存在使得函数计算梯度时候遇到梯度消失问题。在梯度函数上出现的以指数级递增或者递减的情况分别称为梯度爆炸或者梯度消失。​​

假设 g ( z ) = z , b [ l ] = 0 g(z) = z, b^{[l]} = 0 g(z)=z,b[l]=0,对于目标输出有: y ^ = W [ L ] W [ L − 1 ] . . . W [ 2 ] W [ 1 ] X \hat{y} = W^{[L]}W^{[L-1]}...W^{[2]}W^{[1]}X y^=W[L]W[L1]...W[2]W[1]X

  • 对于 W [ l ] W^{[l]} W[l]的值大于 1 的情况,激活函数的值将以指数级递增;
  • 对于 W [ l ] W^{[l]} W[l]的值小于 1 的情况,激活函数的值将以指数级递减。
    在这里插入图片描述

在计算梯度时,根据不同情况梯度函数也会以指数级递增或递减,导致训练导数难度上升,梯度下降算法的步长会变得非常小,需要训练的时间将会非常长。

解决办法有多种形式

通常会结合一些形式一起进行

  • Mini梯度下降法
  • 梯度下降算法的优化
  • 初始化参数策略
  • 学习率衰减

2 批梯度下降算法(Batch Gradient Descent)

定义:批梯度下降法(btach),即同时处理整个训练集。

其在更新参数时使用所有的样本来进行更新。对整个训练集进行梯度下降法的时候,我们必须处理整个训练数据集,然后才能进行一步梯度下降,即每一步梯度下降法需要对整个训练集进行一次处理,如果训练数据集很大的时候,处理速度就会比较慢。

所以换一种方式,每次处理训练数据的一部分进行梯度下降法,则我们的算法速度会执行的更快。

2.1 Mini-Batch Gradient Descent

定义:Mini-Batch 梯度下降法(小批量梯度下降法)每次同时处理固定大小的数据集。

若mini-batch 的大小为 1,即是随机梯度下降法(stochastic gradient descent)

使用 Mini-Batch 梯度下降法,对整个训练集的一次遍历(epoch)只做 mini-batch个样本的梯度下降,一直循环整个训练集。

2.2 批梯度下降与Mini-Batch梯度下降的区别

batch梯度下降法和Mini-batch 梯度下降法代价函数的变化趋势如下:
在这里插入图片描述

2.3 梯度下降优化影响

batch 梯度下降法:

  • 对所有 m 个训练样本执行一次梯度下降,每一次迭代时间较长,训练过程慢;
  • 相对噪声低一些,成本函数总是向减小的方向下降。

随机梯度下降法(Mini-Batch=1):

  • 对每一个训练样本执行一次梯度下降,训练速度快,但丢失了向量化带来的计算加速;
  • 有很多噪声,需要适当减小学习率,成本函数总体趋势向全局最小值靠近,但永远不会收敛,而是一直在最小值附近波动。

在这里插入图片描述
因此,选择一个合适的大小进行 Mini-batch 梯度下降,可以实现快速学习,也应用了向量化带来的好处,且成本函数的下降处于前两者之间。

2.4 大小选择

  • 如果训练样本的大小比较小,如 m ≤ 2000 m ≤ 2000 m\le2000m≤2000 m2000m2000时,选择 batch 梯度下降法;
  • 如果训练样本的大小比较大,选择 Mini-Batch 梯度下降法。为了和计算机的信息存储方式相适应,代码在 mini-batch 大小为 2 的幂次时运行要快一些。典型的大小为 2 6 , 2 7 , 2 8 , 2 9 2^6, 2^7,2^8,2^9 26,27,28,29,mini-batch 的大小要符合 CPU/GPU 内存。

需要根据经验快速尝试,找到能够最有效地减少成本函数的值。那么第二种方式是通过优化梯度下降过程,会比梯度下降算法的速度更快些

3 优化算法

这里我们会介绍三种类型的优化算法,不过很多原理都大同小异。

  • 1、动量更新方法
  • 2、逐参数适应学习率方法
  • 3、二阶方法

3.1 动量梯度下降(Gradient Descent with Momentum)

  • 目的:解决因鞍点问题带来的梯度更新停止问题。
  • 解决办法:在随机梯度下降(SGD)中加入指数加权平均数来更新参数的梯度

3.1.1 指数加权平均

指数加权平均(Exponentially Weight Average) 是一种常用的序列数据处理方式,通常用在序列场景如金融序列分析、温度变化序列分析。

假设给定一个序列,例如北京一年每天的气温值,图中蓝色的点代表真实数据。
在这里插入图片描述
那么这样的气温值变化可以理解成优化的过程波动较大,异常较多。那么怎么平缓一些呢,这时候就要用到加权平均值了,如指数加权平均值。首先看一些效果。
在这里插入图片描述
这条红线怎么计算出来?通过指数加权的公式即:
S t = { Y 1 t = 1 β S t − 1 + ( 1 − β ) Y t t > 1 S_t=\left\{ \begin{array}{lll} Y_1&t=1\\ \beta S_{t-1}+(1-\beta)Y_t&t>1 \end{array} \right. St={Y1βSt1+(1β)Ytt=1t>1

其中 Y t Y_{t} Yt t t t 下的实际值, S t S_{t} St t t t 下加权平均后的值, β \beta β 为权重值。

上图的红线中, β \beta β 0.9 0.9 0.9, 那么第一天的温度计算为 S 1 = Y 1 S_{1} = Y1 S1=Y1

那么:
S 2 = 0.9 S 1 + 0.1 Y 2 . . . S 99 = 0.9 S 98 + 0.1 Y 99 S 100 = 0.9 S 99 + 0.1 Y 100 . . . S_2 = 0.9S_1+0.1Y_2\\ ...\\ S_{99} = 0.9 S_{98} + 0.1 Y_{99}\\ S_{100} = 0.9 S_{99} + 0.1 Y_{100}\\ ... S2=0.9S1+0.1Y2...S99=0.9S98+0.1Y99S100=0.9S99+0.1Y100...
假设就100天,那么合并的结果 S 100 = 0.1 Y 100 + 0.1 ∗ 0.9 Y 99 + 0.1 ∗ ( 0.9 ) 2 Y 98 + . . . S_{100} = 0.1 Y_{100} + 0.1 * 0.9 Y_{99} + 0.1 * {(0.9)}^2 Y_{98} + {...} S100=0.1Y100+0.10.9Y99+0.1(0.9)2Y98+...

下图中,当取权重值 β = 0.98 β=0.98 β=0.98 时,可以得到图中更为平滑的绿色曲线。而当取权重值 β = 0.5 β=0.5 β=0.5 时,得到图中噪点更多的黄色曲线。 β \beta β 越大相当于求取平均利用的天数越多,曲线自然就会越平滑而且越滞后。这些系数被称作偏差修正(Bias Correction)
在这里插入图片描述
在这里插入图片描述
上述点数据,我们是否可以理解成梯度下降的过程,每一迭代优化计算出来的梯度值?

3.1.2 动量梯度下降

动量梯度下降(Gradient Descent with Momentum)计算梯度的指数加权平均数,并利用该值来更新参数值。

其中 β \beta β 通常设置为0.9,动量梯度下降法的整个过程为:

S d W [ l ] = β S d W [ l ] + ( 1 − β ) d W [ l ] S_{dW^{[l]}} = \beta S_{dW^{[l]}} + (1 - \beta) dW^{[l]} SdW[l]=βSdW[l]+(1β)dW[l]

S d b [ l ] = β S d b [ l ] + ( 1 − β ) d b [ l ] S_{db^{[l]}} = \beta S_{db^{[l]}} + (1 - \beta) db^{[l]} Sdb[l]=βSdb[l]+(1β)db[l]

W [ l ] : = W [ l ] − α S d W [ l ] W^{[l]} := W^{[l]} - \alpha S_{dW^{[l]}} W[l]:=W[l]αSdW[l]

b [ l ] : = b [ l ] − α S d b [ l ] b^{[l]} := b^{[l]} - \alpha S_{db^{[l]}} b[l]:=b[l]αSdb[l]
​​
那么这样梯度下降过程会有什么变化,如下图所示:
在这里插入图片描述
使用动量梯度下降时,通过累加过去的梯度值来减少抵达最小值路径上的波动,加速了收敛,因此在横轴方向下降得更快,从而得到图中蓝色的曲线。当前后梯度方向一致时,动量梯度下降能够加速学习;而前后梯度方向不一致时,动量梯度下降能够抑制震荡。

其它改进动量算法,nesterov

3.2 逐参数适应学习率方法

前面讨论的方法都是对学习率进行全局地操作,并且对所有的参数都是一样的。
w 1 ← w 1 − η ∂ f ∂ w 1 , w 2 ← w 2 − η ∂ f ∂ w 2 w_1 \leftarrow w_1 - \eta \frac{\partial{f}}{\partial{w_1}}, w_2 \leftarrow w_2 - \eta \frac{\partial{f}}{\partial{w_2}} w1w1ηw1f,w2w2ηw2f

学习率调参是很耗费计算资源的过程,所以很多工作投入到发明能够适应性地对学习率调参的方法,甚至是逐个参数适应学习率调参。很多这些方法依然需要其他的超参数设置,但是其观点是这些方法对于更广范围的超参数比原始的学习率方法有更良好的表现。

  • 对不同的参数,每个参数更新的学习率会自适应本身参数特点进行梯度更新
  • Adagrad
  • RMSprop
  • Adam

4 AdaGrad

AdaGrad算法会使用一个小批量随机梯度 g t g_t gt 按元素平方累加变量 s t s_t st。在时间步0,AdaGrad将 s 0 s_0 s0中每个元素初始化为0。在时间步t,首先将小批量随机梯度 g t g_t gt按元素平方后累加到变量 s t s_t st
s t ← s t − 1 + g t ⊙ g t {s}_{t} \leftarrow {s}_{t-1} + {g}_{t} \odot {g}_{t} stst1+gtgt

其中 ⊙ \odot 是按元素相乘。接着,我们将目标函数自变量中每个元素的学习率通过按元素运算重新调整一下:
w t ← w t − 1 − α s t + ϵ ⊙ g t {w}_{t} \leftarrow {w}_{t-1} - \frac{\alpha}{\sqrt{s_t + \epsilon}} \odot {g}_{t} wtwt1st+ϵ αgt
​​
其中 α {\alpha} α是学习率, ϵ {\epsilon} ϵ是为了维持数值稳定性而添加的常数,如 1 0 − 6 10^{-6} 106。这里开方、除法和乘法的运算都是按元素运算的。这些按元素运算使得目标函数自变量中每个元素都分别拥有自己的学习率。

理解:

  • 小批量随机梯度按元素平方的累加变量 s t s_t st出现在学习率的分母项中。
  • 1、如果目标函数有关自变量中某个参数的偏导数一直都较大,那么该参数的学习率将下降较快;
  • 2、反之,如果目标函数有关自变量中某个参数的偏导数一直都较小,那么该参数的学习率将下降较慢。
  • 然而,由于 s t s_t st一直在累加按元素平方的梯度,自变量中每个元素的学习率在迭代过程中一直在降低(或不变)。所以,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。

5 RMSProp算法

刚才当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。为了解决这一问题,RMSProp算法对AdaGrad算法做了一点小小的修改。

不同于AdaGrad算法里状态变量 s t s_t st是截至时间步 t t t所有小批量随机梯度 g t g_t gt按元素平方和,RMSProp(Root Mean Square Prop)算法将这些梯度按元素平方做指数加权移动平均

s d w = β s d w + ( 1 − β ) ( d w ) 2 s_{dw} = \beta s_{dw} + (1 - \beta)(dw)^2 sdw=βsdw+(1β)(dw)2

s d b = β s d b + ( 1 − β ) ( d b ) 2 s_{db} = \beta s_{db} + (1 - \beta)(db)^2 sdb=βsdb+(1β)(db)2

w : = w − α s d w + ϵ d w w := w - \frac{\alpha}{\sqrt{s_{dw} + \epsilon}} dw w:=wsdw+ϵ αdw

b : = b − α s d b + ϵ d b b := b - \frac{\alpha}{\sqrt{s_{db} + \epsilon}} db b:=bsdb+ϵ αdb

其中 ϵ \epsilon ϵ是一样为了维持数值稳定一个常数。最终自变量每个元素的学习率在迭代过程中就不再一直降低。RMSProp有助于减少抵达最小值路径上的摆动,并允许使用一个更大的学习率 α α α,从而加快算法学习速度。

6 Adam算法

Adam 优化算法(Adaptive Moment Estimation,自适应矩估计) 将 Momentum 和 RMSProp 算法结合在一起。Adam算法在RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均。

假设用每一个 mini-batch 计算 d W dW dW d b db db,第 t t t次迭代时:

动量计算梯度:

v d W = β 1 v d W + ( 1 − β 1 ) d W v_{dW} = \beta_1 v_{dW} + (1 - \beta_1) dW vdW=β1vdW+(1β1)dW

v d b = β 1 v d b + ( 1 − β 1 ) d b v_{db} = \beta_1 v_{db} + (1 - \beta_1) db vdb=β1vdb+(1β1)db

v d W [ l ] c o r r e c t e d = v d W [ l ] 1 − ( β 1 ) t v^{corrected}_{dW^{[l]}} = \frac{v_{dW^{[l]}}}{1 - (\beta_1)^t} vdW[l]corrected=1(β1)tvdW[l]

RMSProp计算方式:

s d W = β 2 s d W + ( 1 − β 2 ) ( d W ) 2 s_{dW} = \beta_2 s_{dW} + (1 - \beta_2) {(dW)}^2 sdW=β2sdW+(1β2)(dW)2

s d b = β 2 s d b + ( 1 − β 2 ) ( d b ) 2 s_{db} = \beta_2 s_{db} + (1 - \beta_2) {(db)}^2 sdb=β2sdb+(1β2)(db)2

s d W [ l ] c o r r e c t e d = s d W [ l ] 1 − ( β 2 ) t s^{corrected}_{dW^{[l]}} = \frac{s_{dW^{[l]}}}{1 - (\beta_2)^t} sdW[l]corrected=1(β2)tsdW[l]
​​
​​其中 l l l为某一层, t t t为移动平均轮次的值

Adam 算法的参数更新:
在这里插入图片描述
原论文中作者建议的参数设置的值:

  • 学习率 α \alpha α需要尝试一系列的值,来寻找比较合适的
  • β1:常用的缺省值为 0.9
  • β2:Adam 算法的作者建议为 0.999
  • ϵ:Adam 算法的作者建议为epsilon的默认值1e-8

注:β1、β2、ϵ 通常不需要调试

7 所有优化算法效果对比

  • 收敛对比

在这里插入图片描述
在这里插入图片描述

  • 鞍点对比

在这里插入图片描述

资料来自:Alec Radford做的实验对比

8 学习率退火

如果设置一个固定的学习率 α α α

  • 在最小值点附近,由于不同的 batch 中存在一定的噪声,因此不会精确收敛,而是始终在最小值周围一个较大的范围内波动。
  • 如果随着时间慢慢减少学习率 α α α 的大小,在初期 α α α 较大时,下降的步长较大,能以较快的速度进行梯度下降;而后期逐步减小 α α α 的值,即减小步长,有助于算法的收敛,更容易接近最优解。

最常用的学习率退火方法:

  • 1、随步数衰减
  • 2、指数衰减
    α = 0.9 5 e p o c h _ n u m ∗ α 0 \alpha=0.95^{epoch\_num}*\alpha_0 α=0.95epoch_numα0
  • 3、 1 t \frac{1}{t} t1 衰减
    α = 1 1 + d e c a y _ r a t e ∗ e p o c h _ n u m ∗ α 0 \alpha = \frac{1}{1+decay\_rate*epoch\_num}*\alpha_0 α=1+decay_rateepoch_num1α0
    其中,decay_rate为衰减率(超参数),epoch_num为将所有的训练样本完整过一遍的次数。
    对于大型的数据模型,需要使用这些方式去自动进行学习率衰减。而一些小型网络可以直接手动进行调整

9 参数初始化策略与归一化输入

9.1 参数初始化

由于在 z = w 1 x 1 + w 2 x 2 + . . . + w n x n + b z={w}_1{x}_1+{w}_2{x}_2 + ... + {w}_n{x}_n + b z=w1x1+w2x2+...+wnxn+b 公式中,当输入的数量 n n n较大时,如果每个 w i w_i wi 的值都小一些,这样它们的和得到的 z z z 也会非常大,所以会造成我们之前介绍的梯度消失或者梯度爆炸。所以都会初始化比较小的值。

对网络输入的特征进行标准化,能够缓解梯度消失或者梯度爆炸

9.2 归一化输入

标准化公式: x = x − μ σ x = \frac{x-\mu}{\sigma} x=σxμ

这个公式其实与特征工程中的处理是一样的, μ \mu μ为平均值, σ \sigma σ为标准差。标准化的目的是所有特征的平均值为0,标准差为1。这属于机器学习基本的内容不过多进行叙述。
在这里插入图片描述
那么这种有什么好处?主要是对于损失函数带来的好处

标准化前的损失函数:
在这里插入图片描述
标准化后的损失函数:
在这里插入图片描述
这样的话,对于梯度下降无论从哪个位置开始迭代,都能以相对较少的迭代次数找到全局最优解。可以加速网络的学习。

理解这个原理,其实还是最初的这样的公式: z = w 1 x 1 + w 2 x 2 + . . . + w n x n + b z={w}_1{x}_1+{w}_2{x}_2 + ... + {w}_n{x}_n + b z=w1x1+w2x2+...+wnxn+b

如果激活函数的输入X近似设置成均值为 0,标准方差为 1,神经元输出 z 的方差就正则化到1了。虽然没有解决梯度消失和爆炸的问题,但其在一定程度上确实减缓了梯度消失和爆炸的速度。

10 案例:动量梯度下降与Adam优化算法实现

10.1 目的

对以下模型进行优化,分别实现动量和Adam进行对比

# LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID
z1 = np.dot(W1, X) + b1
a1 = relu(z1)
z2 = np.dot(W2, a1) + b2
a2 = relu(z2)
z3 = np.dot(W3, a2) + b3
a3 = sigmoid(z3)

数据为 train_X, train_Y = sklearn.datasets.make_moons(n_samples=300, noise=.2)创建的简单样本的二分类问题。

10.2 步骤分析

  • 1、数据读取、模型前向与反向传播代码封装
  • 2、动量梯度和Adam优化算法的实现

10.3 代码实现

在这里插入图片描述
目录结构为optimization和utils,其中utils为封装好的相关函数(如relu,前向、反向传播函数)这些不需要大家再去实现,前面已经讲解过,optimization中有主要训练逻辑,其中需要大家去进行实现两个优化算法。

动量梯度和Adam优化算法的接口实现

相关包以及封装接口导入

import numpy as np
import math
import sklearn
import sklearn.datasets

from utils import initialize_parameters, forward_propagation, compute_cost, backward_propagation
from utils import load_dataset, predict

momentum算法实现

def initialize_momentum(parameters):
    """
    初始化网络中每一层的动量梯度下降的指数加权平均结果参数
    parameters['W' + str(l)] = Wl
    parameters['b' + str(l)] = bl
    return:
    v['dW' + str(l)] = velocity of dWl
    v['db' + str(l)] = velocity of dbl
    """
    # 得到网络的层数
    L = len(parameters) // 2
    v = {}

    # 初始化动量参数
    for l in range(L):
        v["dW" + str(l + 1)] = np.zeros(parameters['W' + str(l + 1)].shape)
        v["db" + str(l + 1)] = np.zeros(parameters['b' + str(l + 1)].shape)

    return v


def update_parameters_with_momentum(parameters, gradients, v, beta, learning_rate):
    """
    动量梯度下降算法实现
    """
    # 得到网络的层数
    L = len(parameters) // 2

    # 动量梯度参数更新
    for l in range(L):

        v["dW" + str(l + 1)] = beta * v["dW" + str(l + 1)] + (1 - beta) * (gradients["dW" + str(l + 1)])
        v["db" + str(l + 1)] = beta * v["db" + str(l + 1)] + (1 - beta) * (gradients["db" + str(l + 1)])

        parameters["W" + str(l + 1)] = parameters["W" + str(l + 1)] - learning_rate * v["dW" + str(l + 1)]
        parameters["b" + str(l + 1)] = parameters["b" + str(l + 1)] - learning_rate * v["db" + str(l + 1)]

    return parameters, v

adam算法实现

def initialize_adam(parameters):
    """
    初始化Adam算法中的参数
    """
    # 得到网络的参数
    L = len(parameters) // 2
    v = {}
    s = {}

    # 利用输入,初始化参数v,s
    for l in range(L):

        v["dW" + str(l + 1)] = np.zeros(parameters['W' + str(l + 1)].shape)
        v["db" + str(l + 1)] = np.zeros(parameters['b' + str(l + 1)].shape)
        s["dW" + str(l + 1)] = np.zeros(parameters['W' + str(l + 1)].shape)
        s["db" + str(l + 1)] = np.zeros(parameters['b' + str(l + 1)].shape)

    return v, s


def update_parameters_with_adam(parameters, gradients, v, s, t, learning_rate=0.01,
                                beta1=0.9, beta2=0.999, epsilon=1e-8):
    """
    更新Adam算法网络的参数
    """
    # 网络大小
    L = len(parameters) // 2
    v_corrected = {}
    s_corrected = {}

    # 更新所有参数
    for l in range(L):
        # 对梯度进行移动平均计算. 输入: "v, gradients, beta1". 输出: "v".
        # 进行动量那部分的计算
        v["dW" + str(l + 1)] = beta1 * v["dW" + str(l + 1)] + (1 - beta1) * gradients["dW" + str(l + 1)]
        v["db" + str(l + 1)] = beta1 * v["db" + str(l + 1)] + (1 - beta1) * gradients["db" + str(l + 1)]

        # 计算修正结果. 输入: "v, beta1, t". 输出: "v_corrected".
        v_corrected["dW" + str(l + 1)] = v["dW" + str(l + 1)] / (1 - np.power(beta1, t))
        v_corrected["db" + str(l + 1)] = v["db" + str(l + 1)] / (1 - np.power(beta1, t))

        # 平方梯度的移动平均值. 输入: "s, gradients, beta2". 输出: "s".
        s["dW" + str(l + 1)] = beta2 * s["dW" + str(l + 1)] + (1 - beta2) * np.power(gradients["dW" + str(l + 1)], 2)
        s["db" + str(l + 1)] = beta2 * s["db" + str(l + 1)] + (1 - beta2) * np.power(gradients["db" + str(l + 1)], 2)

        # 计算修正的结果. 输入: "s, beta2, t". 输出: "s_corrected".
        s_corrected["dW" + str(l + 1)] = s["dW" + str(l + 1)] / (1 - np.power(beta2, t))
        s_corrected["db" + str(l + 1)] = s["db" + str(l + 1)] / (1 - np.power(beta2, t))

        # 更新参数. 输入: "parameters, learning_rate, v_corrected, s_corrected, epsilon". 输出: "parameters".
        parameters['W' + str(l + 1)] = parameters['W' + str(l + 1)] - learning_rate * v_corrected[
            "dW" + str(l + 1)] / np.sqrt(s_corrected["dW" + str(l + 1)] + epsilon)
        parameters['b' + str(l + 1)] = parameters['b' + str(l + 1)] - learning_rate * v_corrected[
            "db" + str(l + 1)] / np.sqrt(s_corrected["db" + str(l + 1)] + epsilon)

    return parameters, v, s

运行效果如下

# adam算法优化效果0 次迭代的损失值: 0.6905521000 次迭代的损失值: 0.1855012000 次迭代的损失值: 0.1508303000 次迭代的损失值: 0.0744544000 次迭代的损失值: 0.1259595000 次迭代的损失值: 0.1043446000 次迭代的损失值: 0.1006767000 次迭代的损失值: 0.0316528000 次迭代的损失值: 0.1119739000 次迭代的损失值: 0.197940
Accuracy: 0.94

# momentum算法优化效果0 次迭代的损失值: 0.6907411000 次迭代的损失值: 0.6853412000 次迭代的损失值: 0.6471453000 次迭代的损失值: 0.6195944000 次迭代的损失值: 0.5766655000 次迭代的损失值: 0.6073246000 次迭代的损失值: 0.5294767000 次迭代的损失值: 0.4609368000 次迭代的损失值: 0.4657809000 次迭代的损失值: 0.464740
Accuracy: 0.7966666666666666
  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GeniusAng丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值