优化算法 (Optimization algorithms)

课程来自CS230    
优化算法,这能让你的神经网络运行得更快。机器学习的应用是一个高度依赖经验的过程,伴随着大量迭代的过程,你需要训练诸多模型,才能找到合适的那一个,所以,优化算法能够帮助你快速训练模型。

Mini-batch

深度学习可以在大数据领域发挥出最大的效果,我们可以利用一个巨大的数据集来训练神经网络,但在这个体量的数据集上,迭代训练的速度将会很慢。所以首先来谈谈 mini-batch 梯度下降法。

        之前的课程课程提到过,python的广播机制能让向量化有效地对所有𝑚个样本进行计算,允许你处理整个训练集,而无需某个明确的公式。当 我们要把训练样本放大巨大的矩阵 𝑋 当中去, 𝑋 = [𝑥^ (1) 𝑥^ (2) 𝑥^ (3) … … 𝑥^ (𝑚) ] 𝑌也是如此, 𝑌 = [𝑦^ (1) 𝑦^ (2) 𝑦^ (3) … … 𝑦^ (𝑚) ]
        
        所以𝑋 的维数是 (𝑛 𝑥 , 𝑚) 𝑌 的维数是 (1, 𝑚) ,向量化能够让你相对较快地处理所有 𝑚 个样本。如果𝑚 很大的话,处理速度仍然缓慢。比如说,如果 𝑚 500 万或 5000 万或者更大的一个数,在对整个训练集执行梯度下降法时,必须处理整个训练集,然后才能进行一步梯度下降法,然后你需要再重新处理 500 万个训练样本,才能进行下一步梯度下降法。所以如果你在处理完整个 500 万个样本的训练集之前,先让梯度下降法处理一部分,你的算法速度会更快。
     
        你可以把训练集分割为小一点的子集训练,这些子集被取名为 mini-batch ,假设每一个子集中只有 1000 个样本,那么把其中的 𝑥^ (1) 𝑥^ (1000) 取出来,将其称为第一个子训练集,也叫做 mini-batch ,然后你再取出接下来的 1000 个样本,从 𝑥^ (1001) 𝑥^ (2000) ,然后再取 1000个样本,以此类推。
        把𝑥 (1) 𝑥 (1000) 称为 𝑋^ {1} 𝑥^ (1001) 𝑥^ (2000) 称为 𝑋^ {2} ,如果 你的训练样本一共有 500 万个,每个 mini-batch 都有 1000 个样本,也就是说,你有 5000 mini-batch.  对 𝑌 也要进行相同处理,你也要相应地拆分 𝑌 的训练集,所以这是𝑌^{1},然后从𝑦^(1001)到𝑦^(2000),这个叫𝑌^{2},一直到𝑌^{5000}。 mini-batch 的数量  𝑡  组成了  𝑋^ {𝑡}  和  𝑌^ {𝑡} ,这就是 1000 个训练样本,包含相应的输入输出对。
            
𝑋 {𝑡} 𝑌 {𝑡} 的维数:如果 𝑋^ {1} 是一个有 1000 个样本的训练集,或者说是 1000 个样本的 𝑥 值,所以维数应该是(𝑛 𝑥 , 1000) 𝑋^ {2} 的维数应该是 (𝑛 𝑥 , 1000) ,以此类推。因此所有的子集维数都是(𝑛 𝑥 , 1000) ,而这些( 𝑌^ {𝑡} )的维数都是 (1,1000)

mini-batch 的梯度下降法

每次同时处理的单个的 mini-batch 𝑋^ {𝑡} 𝑌^ {𝑡} ,而不是同时处理全部的  𝑋  和  𝑌  训练集。 还是使用前面500万训练样本数据集的例子在训练集上运行 mini-batch 梯度下降法,
运行 for t=1, ……, 5000,因为我们有 5000 个各有 1000 个样本的组,在 for 循环里 就是对𝑋^ {𝑡} 𝑌^ {𝑡} 执行一步梯度下降法。假设你有一个拥有 1000 个样本的训练集, 之前的学习中已经很熟悉一次性处理完的方法,现在就是用之前向量化的方法去处理 1000 个样本。
        首先对输入也就是 𝑋 {𝑡} ,执行前向传播,然后执行 𝑧^ [1] = 𝑊^ [1] 𝑋 + 𝑏^ [1],这个公式是之前batch前向传播的公式,是处理整个训练集,代码如下:
parameters["W" + str(l+1)] = parameters["W" + str(l+1)] - learning_rate * grads['dW' + str(l+1)]
parameters["b" + str(l+1)] = parameters["b" + str(l+1)] - learning_rate * grads['db' + str(l+1)]
这里需要处理第一个 mini-batch,所以在处理 mini-batch 时 𝑋 改成 𝑋{𝑡},即𝑧^[1] = 𝑊^[1]𝑋^{𝑡} + 𝑏^[1],然后一直到𝐴^[𝐿] = 𝑔^[𝐿](𝑍^[𝐿]),这就是得到的预测值。这个向量化的执行命令,一次性处理 1000 个而不是 500 万个样本。
         接下来计算损失成本函数𝐽,因为子集规模是 1000,易得损失函数 𝐽 为: 
                
         也可以使用正则化:

                 

        因为这是一个 mini-batch 的损失,所以将 𝐽 损失加上上角标𝑡,放在大括号里

                

        其实跟之前的 batch 执行梯度下降法如出一辙,除了你现在的对象不是𝑋,𝑌,而是𝑋^{𝑡}𝑌^{𝑡}。接下来,执行反向传播来计算𝐽^{𝑡}的梯度,只需要使用𝑋^{𝑡}𝑌^{𝑡}代替𝑋,𝑌,然后更新加权值

                 

        这是使用 mini-batch 梯度下降法训练样本的一步(1 epoch)的训练。只是遍历了一次训练集

 

        使用 batch 梯度下降法,一次遍历训练集只能让你做一个梯度下降,使用 mini-batch 梯度下降法,一次遍历训练集,能让你做 5000 个梯度下降。当然正常来说你想要多次遍历训练集,还需要为另一个 while 循环设置另一个 for 循环。所以你可以一直处理遍历训练集,直到最后你能收敛到一个合适的精度。
mini-batch代码:
    """
    Arguments:
    X -- input data, of shape (input size, number of examples)
    Y -- true "label" vector (1 for blue dot / 0 for red dot), of shape (1, number of examples)
    mini_batch_size -- size of the mini-batches, integer
    """


    # Step 1: Shuffle (X, Y)
    permutation = list(np.random.permutation(m)) # 随机排序
    shuffled_X = X[:, permutation]
    shuffled_Y = Y[:, permutation].reshape((1,m))

    # Step 2: Partition (shuffled_X, shuffled_Y). Minus the end case.
    num_complete_minibatches = math.floor(m/mini_batch_size) # number of mini batches of size mini_batch_size in your partitionning
    for k in range(0, num_complete_minibatches):
        ### START CODE HERE ### (approx. 2 lines)
        mini_batch_X = shuffled_X[:, k*mini_batch_size : (k+1)*mini_batch_size]
        mini_batch_Y = shuffled_Y[:, k*mini_batch_size : (k+1)*mini_batch_size]
        ### END CODE HERE ###
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)

    # Handling the end case (last mini-batch < mini_batch_size)
    if m % mini_batch_size != 0:
        ### START CODE HERE ### (approx. 2 lines)
        mini_batch_X = shuffled_X[:, num_complete_minibatches*mini_batch_size : m]
        mini_batch_Y = shuffled_Y[:, num_complete_minibatches*mini_batch_size : m]
        ### END CODE HERE ###
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)

简单理解 mini-batch

        使用 batch 梯度下降法时,每次迭代你都需要历遍整个训练集,可以预期每次迭代成本都会下降,所以如果成本函数𝐽 是迭代次数的一个函数,它应该会随着每次迭代而减少,如果𝐽 在某次迭代中增加了,那肯定出了问题,也许你的学习率太大。
         使用 mini-batch 梯度下降法,如果你作出成本函数在整个过程中的图,则并不是每次迭代都是下降的如上图右,特别是在每次迭代中,你要处理的是𝑋^{𝑡}和𝑌^{𝑡},如果要作出成本函数𝐽^{𝑡}的图,而𝐽^{𝑡}只和𝑋^{𝑡},𝑌^{𝑡}有关,也就是每次迭代下你都在训练不同的样本集或者说训练不同的 mini-batch,如果你要作出成本函数𝐽的图,你很可能会看到这样的结果,走向朝下,但有更多的噪声,所以如果你作出𝐽^{𝑡}的图,因为在训练 mini-batch 梯度下降法时,会经过多轮epoch,你可能会看到这样的曲线。没有每次迭代都下降是不要紧的,但走势应该向下,噪声产生的原因在于也许𝑋^{1}和𝑌^{1}是比较容易计算的 mini-batch,因此成本会低一些。不过也许出于偶然,𝑋^{2}和𝑌^{2}是比较难运算的 mini-batch,或许有一些残缺的样本,这样一来,成本会更高一些,所以才会出现这些摆动。
        你需要决定的变量之一是 mini-batch 的大小,𝑚是训练集的大小,极端情况下:
        如果 mini-batch 的大小等于𝑚,在这种极端情况下,就只有 𝑋^{1}和𝑌^{1},其实就是 batch 梯度下降法。
        另一个极端情况,假设 mini-batch 大小为 1,此时该算法也叫做随机梯度下降法(stochastic gradient descent,SGD),每个样本都是独立的 mini-batch,一次只处理一个。

         看在两种极端下成本函数的优化情况,如果这是你想要最小化的成本函数的轮廓,假设最小值在红点,batch 梯度下降法从某处开始,相对噪声低些,幅度也大一些,大部分情况下都可以找到最小值。
        相反,在随机梯度下降法中,选取一个起始点开始,每次迭代,你 只对一个样本进行梯度下降,大部分时候你向着全局最小值靠近,有时候你会远离最小值, 因为那个样本恰好给你指的方向不对,因此随机梯度下降法是有很多噪声的,平均来看,它最终会靠近最小值,不过有时候也会方向错误,因为随机梯度下降法永远不会收敛,而是会一直在最小值附近波动,并不会在达到最小值并停留在此。

         mini-batch 大小在二者之间,大小在 1 和𝑚之间,而 1 太小了,𝑚太大了。用 mini-batch 梯度下降法,它不会总朝向最小值靠近,但它比随机梯度下降要更持续地靠近最小值的方向,它也不一定在很小的范围内收敛或者波动,如果出现这个问题,可以慢慢减少学习率。
        用 batch 梯度下降法,mini-batch 的大小为𝑚,每个迭代需要处理大量训练样本,该算法的主要弊端在于特别是在训练样本数量巨大的时候,单次迭代耗时太长。如果训练样本不大,batch 梯度下降法运行地很好。
        相反,如果使用随机梯度下降法,如果你只要处理一个样本,那这个方法很好,这样做没有问题,通过减小学习率,噪声会被改善或有所减小,但随机梯度下降法的一大缺点是,你会失去所有向量化带给你的加速,因为一次性只处理了一个训练样本,这样效率过于低下,所以实践中最好选择不大不小的 mini-batch 尺寸,实际上学习率达到最快。mini-batch有两个好处,一方面,你得到了大量向量化,前面的例子中,如果 mini-batch 大小为1000 个样本,你就可以对 1000 个样本向量化,比你一次性处理多个样本快得多。另一方面,你不需要等待整个训练集被处理完就可以开始进行后续工作,再用一下上个视频的数字,每次训练集允许我们采取 5000 个梯度下降步骤,所以实际上一些位于中间的 mini-batch 大小效果最好。

mini-batch 大小(batch_size选取)

         如果 mini-batch 大小既不是 1 也不是𝑚,应该取中间值,那应该怎么选择呢?其实是有指导原则的。
        首先,如果训练集较小,直接使用 batch 梯度下降法,样本集较小就没必要使用 mini-batch 梯度下降法,你可以快速处理整个训练集,所以使用 batch 梯度下降法也很好,这里 的少是说小于 2000 个样本,这样比较适合使用 batch 梯度下降法。
        一般的 mini-batch 大小为 64 到 512,考虑到电脑内存设置和使用的方式,如果 mini-batch 大小是 2 的𝑛次方,代码会运行地快一些,64 就是 2 的 6 次方,以此类推,128 是 2 的 7 次方,256 是 2 的 8 次方,512 是 2 的 9 次方。所以经常把 mini-batch 大小设成 2 的次方。在上面的例子中,mini-batch 大小设为了 1000,建议可以试一下 1024,也就是2 的 10 次方,不过1024的设置比较少见,64 到 512 的 mini-batch 比较常见。
        最后需要注意的是在你的 mini-batch 中,要确保𝑋{𝑡}和𝑌{𝑡}要符合 CPU/GPU 内存,取决于你的应用方向以及训练集的大小。如果你处理的 mini-batch CPU/GPU 内存不相符,不管你用什么方法处理数据,你会注意到算法的表现急转直下变得惨不忍睹,所以我希望你对一般人们使用的 mini-batch 大小有一个直观了解。事实上 mini-batch 大小是另一个重要的变量,你需要做一个快速尝试,才能找到能够最有效地减少成本函数的那个,一般会尝试几个不同的值,几个不同的 2 次方,然后看能否找到一个让梯度下降优化算法最高效的大小。
加深理解:

动量梯度下降法(Gradient descent with Momentum

为了进一步加速梯度下降算法的速度,可以计算梯度的指数加权平均数,并利用该梯度更新你的权重,也就是动量梯度下降法。动量梯度下降法、RMSprop Adam 也可以防止陷入局部最优和快速通过鞍点

例如,如果你要优化成本函数,函数形状如图,红点代表最小值的位置

假设你从这里 (蓝色点)开始梯度下降法,如果进行梯度下降法的一次迭代,无论是 batch mini-batch 下降法,也许会指向这里,现在在椭圆的另一边,计算下一步梯度下降,结果或许如此,然后再计算下去,你会发现梯度下降法要很多计算步骤对吧。

慢慢摆动到最小值,这种上下波动减慢了梯度下降法的速度,你就无法使用更大的学习率,如果你要用较大的学习率(紫色箭头),结果可能会偏离函数的范围,为了避免摆动过大,你要用一个较小的学习率。
另一个看待问题的角度是,在纵轴上,你希望学习慢一点,因为你不想要这些摆动,但是在横轴上,你希望加快学习,你希望快速从左向右移,移向最小值,移向红点。所以使用动量梯度下降法,你需要做的是,在每次迭代中,确切来说在第𝑡 次迭代的过程中,你会计算微分𝑑𝑊 𝑑𝑏( 省略上标 [𝑙]) ,你用现有的 mini-batch 计算 𝑑𝑊 𝑑𝑏 。如果你用 batch 梯度下降法,现在的 mini-batch 就是全部的 batch ,对于 batch 梯度下降法的效果是一样的。如果现有的 mini-batch 就是整个训练集,效果也不错,你要做的是计算
                

 得到𝑑𝑊的移动平均数(moving average), 接着同样地计算𝑣𝑑𝑏。

                

然后重新赋值权重
                     
这样就可以减缓梯度下降的幅度。
        例如,在上几个导数中,你会发现这些纵轴上的摆动平均值接近于零,所以在纵轴方向, 你希望放慢一点,平均过程中,正负数相互抵消,所以平均值接近于零。但在横轴方向,所有的微分都指向横轴方向,因此横轴方向的平均值仍然较大,因此用算法几次迭代后,你发现动量梯度下降法,最终纵轴方向的摆动变小了,横轴方向运动更快,因此你的算法走了一条更加直接的路径,在抵达最小值的路上减少了摆动。
具体如何计算:
有两个超参数,学习率 𝛼 以及参数𝛽 𝛽 控制着指数加权平均数。 𝛽 最常用的值是 0.9, 效果不错,你可以尝试不同的值,可以做一些超参数的研究,不过 0.9 是很棒的鲁棒数。
动量梯度下降法代码:
    #Initialize velocity
    for l in range(L):
        v["dW" + str(l+1)] = np.zeros((parameters['W' + str(l+1)].shape[0], parameters['W' + str(l+1)].shape[1]))
        v["db" + str(l+1)] = np.zeros((parameters['b' + str(l+1)].shape[0], parameters['b' + str(l+1)].shape[1]))



    # Momentum update for each parameter
    for l in range(L):
        
        ### START CODE HERE ### (approx. 4 lines)
        # compute velocities
        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)]
        # update parameters
        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)]
        ### END CODE HERE ###

RMSprop

知道了动量( Momentum )可以加快梯度下降,还有一个叫做 RMSprop 的算法, 全称是 root mean square prop 算法,它也可以加速梯度下降,看看它是如何运作的。
还是之前的例子,如果你执行梯度下降,虽然横轴方向正在推进,但纵轴方向 会有大幅度摆动,为了分析这个例子,假设纵轴代表参数𝑏 ,横轴代表参数 𝑊 ,可能有 𝑊 1 , 𝑊2 或者其它重要的参数,为了便于理解,称为 𝑏 𝑊。
想减缓𝑏方向的学习,即纵轴方向,同时加快,至少不是减缓横轴方向的学习, RMSprop 算法可以实现这一点。
在第𝑡 次迭代中,该算法会照常计算当下 mini-batch 的微分 𝑑𝑊 𝑑𝑏 ,所以我会保留这个指数加权平均数,我们用到新符号𝑆 𝑑𝑊 ,而不是 𝑣 𝑑𝑊 ,公式如下:
        
        
并这样更新参数:
        
理解一下其原理。记得在横轴方向或者在例子中的𝑊 方向,我们希望学习速度快,而在垂直方向,也就是例子中的 𝑏  方向,我们希望减缓纵轴上的摆动,所以有了  𝑆 𝑑𝑊  和  𝑆 𝑑𝑏 ,我们希望  𝑆 𝑑𝑊 会相对较小,所以我们要除以一个较小的数,而希望𝑆 𝑑𝑏 又较大,所以这里我们要除以较大的数字,这样就可以减缓纵轴上的变化。这些微分垂直方向的要比水平方向的大得多,所以斜率在𝑏方向特别大,所以这些微分中,𝑑𝑏较大,𝑑𝑊较小,因为函数的倾斜程度,在纵轴上,也就是 b 方向上要大于在横轴上,也就是 𝑊 方向上。𝑑𝑏的平方较大,所以𝑆𝑑𝑏也会较大,而相比之下,𝑑𝑊会小一些,亦或𝑑𝑊平方会小一些,因此𝑆𝑑𝑊会小一些,结果就是纵轴上的更新要被一个较大的数相除,就能消除摆动,而水平方向的更新则被较小的数相除。
RMSprop 的影响就是你的更新最后会变成这样(绿色线),纵轴方向上摆动较小,而横 轴方向继续推进。还有个影响就是,你可以用一个更大学习率 𝛼,然后加快学习,而无须在纵轴上垂直方向偏离。
要说明一点,例子中一直把纵轴和横轴方向分别称为 𝑏 𝑊 ,只是为了方便展示而已。实际中,你会处于参数的高维度空间,所以需要消除摆动的垂直维度,你需要消除摆动,实际上是参数𝑊 1 𝑊 2 等的合集,水平维度可能 𝑊 3 𝑊 4 等等,因此把 𝑊 𝑏 分开只是方便说明。实际中𝑑𝑊 是一个高维度的参数向量, 𝑑𝑏 也是一个高维度参数向量,但是你的直觉是,在你要消除摆动的维度中,最终你要计算一个更大的和值,这个平方和微分的加权平均值,所以你最后去掉了那些有摆动的方向。所以这就是 RMSprop ,全称是均方根,因为你将微分进行平方,然后最后使用平方根。
要确保你的算法不会除以 0 ,如果 𝑆 𝑑𝑊 的平方根趋近于 0 怎么办?得到的答案就非常大,为了确保数值稳定,在实际操练的时候,你要在分母上加上一个很小很小的𝜀 ,𝜀是多少没关系, 10^ −8 是个不错的选择,这只是保证数值能稳定一些。

 

这样无论什么原因,你都不会除以一个很小很小的数。

 RMSprop Momentum 有很相似的一点,可以消除梯度下降中的摆动,包括mini-batch 梯度下降,并允许你使用一个更大的学习率 𝛼,从而加快你的算法学习速度。

Adam 优化算法(Adam optimization algorithm)

 RMSprop 以及 Adam 优化算法,是少有的经受住人们考验的两种算法,已被证明适用于不同的深度学习结构,很好地解决了许多问题。

Adam 优化算法基本上就是将 Momentum RMSprop 结合在一起。

本算法中有很多超参数,超参数学习率 𝛼 很重要,也经常需要调试,你可以尝试一系列值,然后看哪个有效。𝛽1 常用的缺省值为 0.9,这是 𝑑𝑊的移动平均数,也就是 𝑑𝑊  的加权平均数,这是 Momentum 涉及的项。至于超参数 𝛽 2 Adam 论文作者,也就是 Adam 算法的发明者,推荐使用 0.999 ,这是在计算 (𝑑𝑊) 2 以及 (𝑑𝑏) 2 的移动加权平均值,关于 𝜀 的选择其实没那么重要,Adam 论文的作者建议 𝜀 10 −8 ,但你并不需要设置它,因为它并不会影响算法表现。但是在使用 Adam 的时候,人们往往使用缺省值即可, 𝛽 1 𝛽 2 𝜀 都是如此,一般没人会去调整𝜀,然后尝试不同的𝛼值,看看哪个效果最好。也可以调整𝛽1和𝛽2,但通常很少这么干。
Adam 代码:
               
def update_parameters_with_adam(parameters, grads, v, s, t, learning_rate = 0.01,
                                beta1 = 0.9, beta2 = 0.999,  epsilon = 1e-8):
    """
    Update parameters using Adam
    
    Arguments:
    parameters -- python dictionary containing your parameters:
                    parameters['W' + str(l)] = Wl
                    parameters['b' + str(l)] = bl
    grads -- python dictionary containing your gradients for each parameters:
                    grads['dW' + str(l)] = dWl
                    grads['db' + str(l)] = dbl
    v -- Adam variable, moving average of the first gradient, python dictionary
    s -- Adam variable, moving average of the squared gradient, python dictionary
    learning_rate -- the learning rate, scalar.
    beta1 -- Exponential decay hyperparameter for the first moment estimates 
    beta2 -- Exponential decay hyperparameter for the second moment estimates 
    epsilon -- hyperparameter preventing division by zero in Adam updates

    Returns:
    parameters -- python dictionary containing your updated parameters 
    v -- Adam variable, moving average of the first gradient, python dictionary
    s -- Adam variable, moving average of the squared gradient, python dictionary
    """
    
    L = len(parameters) // 2                 # number of layers in the neural networks
    v_corrected = {}                         # Initializing first moment estimate, python dictionary
    s_corrected = {}                         # Initializing second moment estimate, python dictionary
    
    # Perform Adam update on all parameters
    for l in range(L):
        # Moving average of the gradients. Inputs: "v, grads, beta1". Output: "v".
        ### START CODE HERE ### (approx. 2 lines)
        v["dW" + str(l+1)] = beta1 * v["dW" + str(l+1)] + (1-beta1) * grads['dW' + str(l+1)]
        v["db" + str(l+1)] = beta1 * v["db" + str(l+1)] + (1-beta1) * grads['db' + str(l+1)]
        ### END CODE HERE ###

        # Compute bias-corrected first moment estimate. Inputs: "v, beta1, t". Output: "v_corrected".
        ### START CODE HERE ### (approx. 2 lines)
        v_corrected["dW" + str(l+1)] = v["dW" + str(l+1)]/(1-(beta1)**t)
        v_corrected["db" + str(l+1)] = v["db" + str(l+1)]/(1-(beta1)**t)
        ### END CODE HERE ###

        # Moving average of the squared gradients. Inputs: "s, grads, beta2". Output: "s".
        ### START CODE HERE ### (approx. 2 lines)
        s["dW" + str(l+1)] = beta2*s["dW" + str(l+1)] + (1-beta2)*(grads['dW' + str(l+1)]**2)
        s["db" + str(l+1)] = beta2*s["db" + str(l+1)] + (1-beta2)*(grads['db' + str(l+1)]**2)
        ### END CODE HERE ###

        # Compute bias-corrected second raw moment estimate. Inputs: "s, beta2, t". Output: "s_corrected".
        ### START CODE HERE ### (approx. 2 lines)
        s_corrected["dW" + str(l+1)] = s["dW" + str(l+1)]/(1-(beta2)**t)
        s_corrected["db" + str(l+1)] = s["db" + str(l+1)]/(1-(beta2)**t)
        ### END CODE HERE ###

        # Update parameters. Inputs: "parameters, learning_rate, v_corrected, s_corrected, epsilon". Output: "parameters".
        ### START CODE HERE ### (approx. 2 lines)
        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))
        ### END CODE HERE ###

    return parameters, v, s

效果对比

假设需要分类的数据集如下图所示:

 各个算法运行效果:

Mini-batch Gradient descent:

Mini-batch gradient descent with momentum:

 

Mini-batch with Adam:

 

学习率衰减(Learning rate decay)

加快学习算法的一个办法就是随时间慢慢减少学习率,我们将之称为学习率衰减。首先通过一个例子看看,为什么要计算学习率衰减。

 ​

假设你要使用 mini-batch 梯度下降法,mini-batch 数量不大,大概 64 或者 128 个样本,在迭代过程中会有噪音(蓝色线),下降朝向这里的最小值,但是不会精确地收敛,所以你的算法最后在附近摆动,并不会真正收敛,因为你用的𝛼是固定值,不同的 mini-batch 中有噪音。

但要慢慢减少学习率 𝛼 的话,在初期的时候,𝛼 学习率还较大,你的学习还是相对较快,但随着𝛼变小,你的步伐也会变慢变小,所以最后你的曲线(绿色线)会在最小值附近的一小块区域里摆动,而不是在训练过程中,大幅度在最小值附近摆动。

所以慢慢减少𝛼的本质在于,在学习初期,你能承受较大的步伐,但当开始收敛的时候,小一些的学习率能让你步伐小一些。
将 𝛼 学习率设为
        
  decay-rate 称为衰减率, epoch- num 为代数, 𝛼 0 为初始学习率),注意这个衰减率是另一个你需要调整的超参数

其它公式有

         

        𝑡为 mini-batch 的数字)

有时人们也会用一个离散下降的学习率,也就是某个步骤有某个学习率,一会之后,学习率减少了一半,一会儿减少一半,一会儿又一半,这就是离散下降(discrete stair cease

学习率衰减的确大有裨益,有时候可以加快训练,但它并不是率先尝试的内容。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值