学习目标

学会实现神经网络常见的优化算法。

笔记

1 小批量梯度下降(Mini batch gradient descent)

1.1 介绍三种梯度下降的方法

我们之前说的梯度下降就指的是批量梯度下降——(Batch) Gradient Descent,就是在每一次迭代中,把整个training set的m个样本全部输入到模型进行训练,更新参数。在training set很大的时候,这样的方法会使参数更新的效率降低,由此提出了小批量梯度下降(Mini batch Gradient Descent),就是把m个样本分割为大小相同的多个批次(batch_size)输入模型进行训练。
在这里插入图片描述在这里插入图片描述
当batch_size为样本数时,就成了随机梯度下降(Stochastic Gradient Descent),随机梯度下降一次仅在一个训练样本上计算梯度,当training set很大时,SDG会使参数向最小值“摆动”而不是平稳地收敛。
在这里插入图片描述

1.2 从训练集(X,Y)中构建小批次数据

第一步,shuffle。就是把训练集随机打乱,注意每个样本与其标签一一对应。
在这里插入图片描述
第二步,partition。就是把打乱后的数据集分割成多个批次(batch)。这里会指定一个mini_batch_size作为每个批次的包含的样本数。最后一个批次的大小由(m−mini_batch_size×⌊mmini_batch_size⌋)\left(m-mini_\_batch_\_size \times \left\lfloor \frac{m}{mini\_batch\_size}\right\rfloor\right)(mmini_batch_size×mini_batch_sizem)公式推出。图中示例的mini_batch_size=64.通常选择2的幂作为mini_batch_size,例如16、32、64、128.
在这里插入图片描述

2 冲量梯度下降(gradient descent with momentum)

利用冲量可以减少梯度下降过程中的振荡(振荡会减慢梯度下降的速度,而且阻止了我们使用较大的学习率)。

2.1 什么是冲量

主要思想:计算梯度的指数滑动加权平均vdθv_{d\theta}vdθ,然后用vdθv_{d\theta}vdθ更新参数θ\thetaθ
在这里插入图片描述
图中红色箭头显示了带冲量的小批量梯度下降。蓝点表示每一步的梯度方向(相对于当前的小批量)。让梯度影响v而不是仅遵循梯度,然后朝v的方向迈出一步。

理解指数滑动加权平均
在这里插入图片描述

2.2 实现带冲量的参数更新

dθ{d\theta}dθ是当前的梯度,vdθv_{d\theta}vdθdθ{d\theta}dθ的指数滑动加权平均值,根据公式vt=βvt−1+(1−β)θtv_{t} = \beta v_{t-1} + (1 - \beta) \theta_{t}vt=βvt1+(1β)θt,可得梯度dβ{d\beta}dβdb{db}db的指数滑动加权平均值计算如下:
vdW[l]=βvdW[l]+(1−β)dW[l]v_{dW^{[l]}} = \beta v_{dW^{[l]}} + (1 - \beta) dW^{[l]}vdW[l]=βvdW[l]+(1β)dW[l]

vdb[l]=βvdb[l]+(1−β)db[l]v_{db^{[l]}} = \beta v_{db^{[l]}} + (1 - \beta) db^{[l]}vdb[l]=βvdb[l]+(1β)db[l]
利用梯度的指数滑动加权平均值vdW[l]v_{dW^{[l]}}vdW[l]vdb[l]v_{db^{[l]}}vdb[l]更新参数:W[l]=W[l]−αvdW[l]W^{[l]} = W^{[l]} - \alpha v_{dW^{[l]}}W[l]=W[l]αvdW[l]

b[l]=b[l]−αvdb[l]b^{[l]} = b^{[l]} - \alpha v_{db^{[l]}}b[l]=b[l]αvdb[l]
具体在python中实现这一过程时还需分两步:首先,对v进行初始化。v与参数形状相同,初始化为0。

def initialize_velocity(parameters):
    L = len(parameters) // 2 # L是神经网络的层数
    v = {}
    
    # 初始化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

然后进行v的计算和参数更新。

def update_parameters_with_momentum(parameters, grads, v, beta, learning_rate):
    L = len(parameters) // 2 # L是神经网络的层数
    for l in range(L):
        
        # 计算v
        v["dW" + str(l + 1)] = beta*v["dW" + str(l + 1)]+(1-beta)*grads['dW' + str(l+1)]
        v["db" + str(l + 1)] = beta*v["db" + str(l + 1)]+(1-beta)*grads['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

注:

  1. β\betaβ是冲量,如果β=0\beta=0β=0,则变为没有冲量的梯度下降;
  2. β\betaβ越大,更新越平滑,β\betaβ常用值范围是0.8到0.999,通常取β=0.9\beta=0.9β=0.9作为默认值;
  3. 冲量应用于批量梯度下降,小批次梯度下降或随机梯度下降。

3 均方根传递(Root Mean Square Prop, RMSprop)

RMSprop是加快梯度下降、减少振荡的另一种方法。用RMSprop更新参数的公式与上一小节类似:
首先,计算当前批次的dWdWdWdbdbdb
然后,计算sdWs_{dW}sdWsdbs_{db}sdb,类似于上文的vdWv_{dW}vdWvdbv_{db}vdb
sdW=β2∗sdW+(1−β2)dW2s_{dW} = \beta_2 * s_{dW} + (1 - \beta_2) dW^{2}sdW=β2sdW+(1β2)dW2

sdb=β2∗sdb+(1−β2)db2s_{db} = \beta_2 * s_{db} + (1 - \beta_2) db^{2}sdb=β2sdb+(1β2)db2
最后,更新参数:
W=W−α∗dWsdW+ϵW = W - \alpha * \frac{dW}{\sqrt{s_{dW}}+\epsilon}W=WαsdW +ϵdW

b=b−α∗dbsdb+ϵb = b - \alpha * \frac{db}{\sqrt{s_{db}}+\epsilon}b=bαsdb +ϵdb
注:ϵ\epsilonϵ是为了保证分母不为0而添加的一个很小的量,一般为10−810^{-8}108

4 Adam

Adam的本质是将冲量和RMSprop结合。

4.1 用Adam进行参数更新(parameters update with Adam)

{vdW[l]=β1vdW[l]+(1−β1)∂J∂W[l]vdW[l]corrected=vdW[l]1−(β1)tsdW[l]=β2sdW[l]+(1−β2)(∂J∂W[l])2sdW[l]corrected=sdW[l]1−(β2)tW[l]=W[l]−αvdW[l]correctedsdW[l]corrected+ε\begin{cases} v_{dW^{[l]}} = \beta_1 v_{dW^{[l]}} + (1 - \beta_1) \frac{\partial \mathcal{J} }{ \partial W^{[l]} } \\ v^{corrected}_{dW^{[l]}} = \frac{v_{dW^{[l]}}}{1 - (\beta_1)^t} \\ s_{dW^{[l]}} = \beta_2 s_{dW^{[l]}} + (1 - \beta_2) (\frac{\partial \mathcal{J} }{\partial W^{[l]} })^2 \\ s^{corrected}_{dW^{[l]}} = \frac{s_{dW^{[l]}}}{1 - (\beta_2)^t} \\ W^{[l]} = W^{[l]} - \alpha \frac{v^{corrected}_{dW^{[l]}}}{\sqrt{s^{corrected}_{dW^{[l]}}} + \varepsilon} \end{cases}vdW[l]=β1vdW[l]+(1β1)W[l]JvdW[l]corrected=1(β1)tvdW[l]sdW[l]=β2sdW[l]+(1β2)(W[l]J)2sdW[l]corrected=1(β2)tsdW[l]W[l]=W[l]αsdW[l]corrected +εvdW[l]corrected

def update_parameters_with_adam(parameters, grads, v, s, t, learning_rate = 0.01,
                                beta1 = 0.9, beta2 = 0.999,  epsilon = 1e-8):
    
    L = len(parameters) // 2               
    v_corrected = {}                    
    s_corrected = {}                        
    
    # 对所有参数进行Adam更新
    for l in range(1, L + 1):
        v["dW" + str(l)] = beta1 * v["dW" + str(l)] + (1 - beta1) * grads['dW' + str(l)]
        v["db" + str(l)] = beta1 * v["db" + str(l)] + (1 - beta1) * grads['db' + str(l)]
        v_corrected["dW" + str(l)] = v["dW" + str(l)]/(1 - beta1**t)
        v_corrected["db" + str(l)] = v["db" + str(l)]/(1 - beta1**t)

        s["dW" + str(l)] = beta2 * s["dW" + str(l)] +(1 - beta2) * grads['dW' + str(l)]**2
        s["db" + str(l)] = beta2 * s["db" + str(l)] +(1 - beta2) * grads['db' + str(l)]**2
        s_corrected["dW" + str(l)] = s["dW" + str(l)]/(1 - beta2**t)
        s_corrected["db" + str(l)] = s["db" + str(l)]/(1 - beta2**t)
		
		#更新参数
        parameters["W" + str(l)] = parameters["W" + str(l)] - learning_rate * v_corrected["dW" + str(l)]/(np.sqrt(s_corrected["dW" + str(l)])+epsilon)
        parameters["b" + str(l)] = parameters["b" + str(l)] - learning_rate * v_corrected["db" + str(l)]/(np.sqrt(s_corrected["db" + str(l)])+epsilon)

    return parameters, v, s, v_corrected, s_corrected
4.2 评价Adam
  1. Adam是一种很好的优化器,适用于不同的神经网络模型;
  2. 不用怎么调整超参数(除了学习率)就可以得到很好的结果;
  3. 使用Adam使得模型收敛更快。

5 学习率(Learning Rate)

5.1 学习率衰减(Learning Rate Decay)

第一种方式:Decay on every iteration,即每迭代一次学习率下降一点:
α=11+decayRate×epochNumber∗α0\alpha = \frac{1}{1 + decayRate \times epochNumber} * \alpha_{0}α=1+decayRate×epochNumber1α0
第一种方式中学习率减小的太快会导致参数不怎么更新,一般不用。

第二种方式:Fixed Interval Scheduling,即每迭代几次学习率下降一点:
α=11+decayRate×⌊epochNumtimeInterval⌋∗α0\alpha = \frac{1}{1 + decayRate \times \lfloor\frac{epochNum}{timeInterval}\rfloor} * \alpha_{0}α=1+decayRate×timeIntervalepochNum1α0
在这里插入图片描述

6 在月亮数据集上比较不同优化器的效果

6.1 数据集可视化

6.2 学习率不变时的三种优化器比较

学习率不变(均为0.0007),迭代次数相同,采用小批量梯度下降,比较三种优化方法(梯度下降、冲量、Adam)的结果。
在这里插入图片描述在这里插入图片描述在这里插入图片描述
可见当学习率固定时,三种模型中只有使用Adam优化器的模型表现好且收敛快。

6.2 学习率衰减时(第二种)的三种优化器比较

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可见使用学习率衰减(第二种)后,三种模型的准确率都很高,但其实Adam的收敛更快。

总结

  1. 数据集很大时通常采用小批量的方式进行梯度下降;
  2. 优化算法的思路就是加快收敛,包括更快地向损失最小值迈进和减少振荡;
  3. 常见的优化算法包括:冲量、RMSprop、Adam,显然Adam是性价比之选;
  4. 优化算法与学习率衰减结合可以达到更好的效果。

需要注意的地方

  1. 未来还可以总结更多的优化算法;
  2. 学习率衰减对Adam的影响看起来不大,值得探究。
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐