深度學習第二週--第二課優化算法實戰

聲明

本文參考何寬念師
在開始之前,說明一下我們要做什麼。我們需要做的是分割數據集優化梯度下降算法,所以需要做以下幾件事:
1、分割數據集
2、優化梯度下降算法:

  • 2.1、不使用任何優化算法
  • 2.2、mini-batch梯度下降法
  • 2.3、使用具有動量的梯度下降算法
  • 2.4、使用adam算法
    到目前爲止,我們始終都是在使用梯度下降法學習,本文中,將使用一些更加高級的優化算法,利用這些優化算法,可以提高我們算法的收斂速度,並在最終得到更好的分離結果。這些方法可以加快學習速度,甚至可以爲成本函數提供更好的最終值,在相同的結果下,有一個好的優化算法可以是等待幾天和幾個小時之間的差異。
    我們想象一下成本函數J,最小化成本就像找到丘陵的最低點,在訓練的每一步中,都會按照某個方向更新參數,以儘可能達到最低點,它類似於最快的下山的路,如下圖:
    在這裏插入圖片描述
    導入庫函數
import numpy as np
import matplotlib.pyplot as plt
import scipy.io
import math
import sklearn
import sklearn.datasets

import opt_utils
import testCase

#%matplotlib inline
plt.rcParams['figure.figsize']=(7.0,4.0)
plt.rcParams['image.interpolation']='nearest'
plt.rcParams['image.cmap']='gray'

梯度下降

def update_parameters_with_gd(parameters,grads,learning_rate):
    """
    使用梯度下降更新參數
    
    參數:
        parameters - 字典,包含待更新的參數
            parameters['W' + str(l)] = Wl
            parameters['b' + str(l)] = bl
        grads - 字典,包含每一個梯度值用以更新參數
        learning_rate - 學習率
    返回:
        parameters - 字典,包含更新後的參數
    """
    L = len(parameters)//2
    
    for l in range(1,L):
        parameters['W'+str(l)] = parameters['W'+str(l)] - learning_rate*grads['dW'+str(l)]
        parameters['b'+str(l)] = parameters['b'+str(l)] - learning_rate*grads['db'+str(l)]
        
    return parameters

測試:

parameters,grads,learning_rate = testCase.update_parameters_with_gd_test_case()
parameters = update_parameters_with_gd(parameters,grads,learning_rate)
print(parameters['W1'],parameters['b1'],parameters['W2'],parameters['b2'])

結果:

[[ 1.63535156 -0.62320365 -0.53718766]
 [-1.07799357  0.85639907 -2.29470142]] [[ 1.74604067]
 [-0.75184921]] [[ 0.3190391  -0.24937038  1.46210794]
 [-2.06014071 -0.3224172  -0.38405435]
 [ 1.13376944 -1.09989127 -0.17242821]] [[-0.87785842]
 [ 0.04221375]
 [ 0.58281521]]

由梯度下降算法演變而來的有隨機梯度下降(SGD)算法和小批量梯度下降算法,隨機梯度下降(SGD),相當於小批量梯度下降,但是和mini-bacth不同的是其中每個小批量mini-batch僅有1個樣本,和梯度下降不同的是你一次只能在一個訓練樣本上計算梯度,而不是在整個訓練集上計算梯度。來看它們的差異:

# 不運行
# 批量梯度下降算法,又叫梯度下降
X = data_input
Y = labels

parameters = initializa_parameters(layers_dims)
for i in range(0,num_iterations):
    A,cache = forward_propagation(X,parameters)
    cost = compit_cosy(A,Y)
    grads = backward_propagation(X,Y.cache)
    parameters = update_parameters(parameters,grads)

# 隨即梯度下降算法
X = data_input
Y = labels

parameters = initializa_parameters(layers_dims)
for i in range(0,num_iterations):
    for j in m:
        A,cache = forward_propagation(X,parameters)
        cost = compit_cosy(A,Y)
        grads = backward_propagation(X,Y.cache)
        parameters = update_parameters(parameters,grads)
  • 梯度下降算法:無震盪,平穩地逼近最低點,但迭代次數較多。
  • 隨機梯度下降法:上下波動大。在更新梯度之前,只使用1個訓練樣本。當訓練集較大時,隨機梯度下降可以更快,但是參數會向最小值擺動,而不是平穩地收斂。
  • mini-batch梯度下降法:上下波動小。綜合了梯度下降法和隨機梯度下降法,在每次迭代中,既不是選擇全部的數據來學習,也不是選擇一個樣本來學習,而是把所有的數據集分割爲一小塊一小塊來學習,它會隨機選擇一小塊mini-batch,塊大小一般爲2的n次方倍。一方面,充分利用GPU的並行性,另一方面,不會讓計算時間特別長。如下圖所示:
    隨機梯度下降vs梯度下降
    隨機梯度下降vs小批量梯度下降

mini-batch梯度下降法

要使用mini-batch梯度下降,得經過兩個步驟:
1、把訓練集打亂,但是X和Y依舊是一一對應,之後,X的第i列是與Y中的第i個標籤對應的樣本。亂序步驟確保將樣本被隨機分成不同的小批次。如下圖,X和Y的每一列代表一個樣本。
在這裏插入圖片描述
2、切分,把訓練集打亂後,就可以對它進行切分了。這裏切分的大小是64,如下圖:
在這裏插入圖片描述

def random_mini_batches(X,Y,mini_batch_size=64,seed=0):
    """
    從(X,Y)中創建一個隨機的mini_batch列表
    
    參數:
        X - 輸入數據,維度爲(輸入節點數量,樣本的數量)
        Y - 對應的是x的標籤,[1|0](藍|紅),維度爲(1,樣本的數量)
        mini_bacthes - 每個mini_bacth的樣本數量
    返回:
        mini_bacthes - 一個同步列表,維度爲(mini_batch_X,mini_batch_Y)
    """
    
    np.random.seed(seed)
    m = X.shape[1]
    mini_batches = []
    
    permutation = list(np.random.permutation(m))
    shuffled_X = X[:,permutation]
    shuffled_Y = Y[:,permutation].reshape((1,m))
    
    num_complete_minibatches = math.floor(m/mini_batch_size)
    for k in range(0,num_complete_minibatches):
        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]
        mini_batch = (mini_batch_X,mini_batch_Y)
        mini_batches.append(mini_batch)
        
    if m%mini_batch_size!=0:
        mini_batch_X = shuffled_X[:,mini_batch_size*num_complete_minibatches:m]
        mini_batch_Y = shuffled_Y[:,mini_batch_size*num_complete_minibatches:m]
        mini_batch = (mini_batch_X,mini_batch_Y)
        mini_batches.append(mini_batch)
        
    return mini_batches

測試:

X_assess,Y_assess,mini_batch_size = testCase.random_mini_batches_test_case()
mini_batches = random_mini_batches(X_assess,Y_assess,mini_batch_size)
print(mini_batches[0][0].shape,mini_batches[0][1].shape,mini_batches[1][0].shape,mini_batches[1][1].shape,mini_batches[2][0].shape,mini_batches[2][1].shape)

結果:

(12288, 64) (1, 64) (12288, 64) (1, 64) (12288, 20) (1, 20)

具有動量的梯度下降法

由於小批量梯度下降只看到了一個子集的參數更新,更新的方向有一定的差異,所以小批量梯度下降的路徑將“震盪地”走向收斂,使用動量可以減小這些震盪,動量考慮了過去的梯度以平滑更新,我們將把以前梯度的方向存儲在變量v中,從形式上講,這將是前面的梯度的指數加權平均值。我們也可以把v看作是滾下坡的速度,根據山坡的坡度建立動量。如下圖所示:
紅色箭頭顯示具有動量的小批量梯度下降一步時所採取的方向,藍色的點顯示每個步驟的梯度方向(相對於當前的小批量)
我們不僅要觀察梯度,還要讓v影響梯度,然後朝着v方向前進一步,儘量讓前進的方向指向最小值,既然我們要影響梯度的方向,而梯度需要使用到dW和db,那麼我們就要建立一個和dW、db相同結構的變量來影響他們,我們現在來進行初始化:

def initialize_velocity(parameters):
    """
    初始化速度,velocity是一個字典:
        - keys:‘dW1’,‘db1’,...,'dWL','dbL'
        - values:與相應的梯度/參數 維度相同的值爲零的矩陣。
        
    參數:
        parameters - 一個字典,包含了以下參數:
            parameters['W'+str(1)] = W1
            parameters['b'+str(1)] = b1
    返回:
        v - 一個字典變量,包含了以下參數:
            v['dW'+str(1)] = dW1的速度
            v['db'+str(1)] = db1的速度
    """
    
    L = len(parameters)//2
    v = {}
    
    for l in range(L):
        v['dW'+str(l+1)] = np.zeros_like(parameters['W'+str(l+1)])
        v['db'+str(l+1)] = np.zeros_like(parameters['b'+str(l+1)])
    return v

測試:

parameters = testCase.initialize_velocity_test_case()
v = initialize_velocity(parameters)
print(v['dW1'],v['db1'],v['dW2'],v['db2'])

結果:

[[0. 0. 0.]
 [0. 0. 0.]] [[0.]
 [0.]] [[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]] [[0.]
 [0.]
 [0.]]

既然初始化完成了,我們就開始影響梯度的方向,需要使用以下公式:
{vdW[l]=βvdW[l]+(1β)dW[l]W[l]=W[l]αvdW[l]\begin{cases} v_{dW^{[l]}}=\beta v_{dW^{[l]}}+(1-\beta)dW^{[l]} \\ W^{[l]}=W^{[l]}-\alpha v_{dW^{[l]}} \end{cases}
{vdb[l]=βvdb[l]+(1β)db[l]b[l]=b[l]αvdb[l]\begin{cases} v_{db^{[l]}}=\beta v_{db^{[l]}}+(1-\beta)db^{[l]} \\ b^{[l]}=b^{[l]}-\alpha v_{db^{[l]}} \end{cases}
其中:

  • l是當前神經網絡的層數
  • β\beta是動量,是一個實數,通常爲0.9
  • α\alpha是學習率
def update_parameters_with_momentum(parameters,grads,v,beta,learning_rate):
   """
   使用動量更新參數
   
   參數:
       parameters - 一個字典變量,具有以下字段
           parameters["W" + str(l)] = Wl
           parameters["b" + str(l)] = bl
       grads - 一個包含梯度值的字典變量,具有以下字段
           grads["dW" + str(l)] = dWl
           grads["db" + str(l)] = dbl
       v - 包含當前速度的字典變量,具有以下字段
           v["dW" + str(l)] = ...
           v["db" + str(l)] = ...
       beta - 超參數,動量,實數
       learning_rate - 學習率,實數
   返回:
       parameters - 更新後的參數字典
       v - 更新後的速度變量
   """
   L = len(parameters)//2
   for l in range(L):
       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

測試:

parameters,grads,v = testCase.update_parameters_with_momentum_test_case()
parameters,v = update_parameters_with_momentun(parameters,grads,v,beta=0.9,learning_rate=0.01)
print(parameters['W1'],parameters['b1'],parameters['W2'],parameters['b2'])
print(v['dW1'],v['db1'],v['dW2'],v['db2'])

結果:

[[ 1.62544598 -0.61290114 -0.52907334]
 [-1.07347112  0.86450677 -2.30085497]] [[ 1.74493465]
 [-0.76027113]] [[ 0.31930698 -0.24990073  1.4627996 ]
 [-2.05974396 -0.32173003 -0.38320915]
 [ 1.13444069 -1.0998786  -0.1713109 ]] [[-0.87809283]
 [ 0.04055394]
 [ 0.58207317]]
[[-0.11006192  0.11447237  0.09015907]
 [ 0.05024943  0.09008559 -0.06837279]] [[-0.01228902]
 [-0.09357694]] [[-0.02678881  0.05303555 -0.06916608]
 [-0.03967535 -0.06871727 -0.08452056]
 [-0.06712461 -0.00126646 -0.11173103]] [[0.02344157]
 [0.16598022]
 [0.07420442]]

需要注意的是速度v是用0來初始化的,因此,該算法需要經過幾次迭代才能把速度提升上來並開始跨越更大步伐。當β\beta=0時,該算法相當於沒有使用動量梯度下降算法的標準的梯度下降算法。當β\beta越大時,說明平滑的作用越明顯,通常0.9是比較合適的值,那如何才能在開始的時候就保持很快的速度向最小誤差哪裏前進呢?接下來可以看看Adam算法。

Adam優化後的梯度下降法

本算法結合了RMSProp算法與Momentum算法。步驟:
1、計算以前的梯度的指數加權平均值,並將其存儲在變量v(偏正校驗前)和vcorrectedv^{corrected}(偏正校驗後)中。
2、計算以前梯度的平方的指數加權平均值,並將其存儲在變量s(偏正校驗前)和scorrecteds^{corrected}(偏正校驗後)中。
3、根據1和2更新參數。
公式如下:
{vdW[l]=β1vdW[l]+(1β1)dW[l]vdW[l]corrected=vdW[l]1(β1)tsdW[l]=β2sdW[l]+(1β2)(dW[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)dW^{[l]} \\ v_{dW^{[l]}}^{corrected}=\frac{v_{dW^{[l]}}}{1-(\beta_1)^t} \\ s_{dW^{[l]}}=\beta _2 s_{dW^{[l]}}+(1-\beta_2)(dW^{[l]})^2 \\s_{dW^{[l]}}^{corrected}=\frac{s_{dW^{[l]}}}{1-(\beta_2)^t} \\ W^{[l]}=W^{[l]}-\alpha \frac{v_{dW^{[l]}}^{corrected}}{s_{dW^{[l]}}^{corrected}+\xi} \end{cases}
其中:

  • t:當前迭代次數
  • l:當前神經網絡的層數
  • α\alpha:學習率
  • ξ\xi:一個非常小的數,用於避免除零操作,一般爲10810^{-8}
def initialize_adam(parameters):
    """
    初始化v和s,它們都是字典類型的變量,都包含了以下字段:
       - keys:‘dW1’,‘db1’,...,'dWL','dbL'
        - values:與相應的梯度/參數 維度相同的值爲零的矩陣。
        
    參數:
        parameters - 包含了以下參數的字典變量
            parameters["W" + str(l)] = Wl
            parameters["b" + str(l)] = bl
    返回:
        v - 包含梯度的指數加權平均值,字段如下:
            v["dW" + str(l)] = ...
            v["db" + str(l)] = ...
        s - 包含平方梯度的指數加權平均值,字段如下:
            s["dW" + str(l)] = ...
            s["db" + str(l)] = ...
    """
    
    L = len(parameters)//2
    v = {}
    s = {}
    
    for l in range(L):
        v['dW'+str(l+1)] = np.zeros_like(parameters['W'+str(l+1)])
        v['db'+str(l+1)] = np.zeros_like(parameters['b'+str(l+1)])
        
        s['dW'+str(l+1)] = np.zeros_like(parameters['W'+str(l+1)])
        s['db'+str(l+1)] = np.zeros_like(parameters['b'+str(l+1)])
    return v,s

測試:

parameters = testCase.initialize_adam_test_case()
v,s = initialize_adam(parameters)
print(v['dW1'],v['db1'],v['dW2'],v['db2'])
print(s['dW1'],s['db1'],s['dW2'],s['db2'])

結果:

[[0. 0. 0.]
 [0. 0. 0.]] [[0.]
 [0.]] [[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]] [[0.]
 [0.]
 [0.]]
[[0. 0. 0.]
 [0. 0. 0.]] [[0.]
 [0.]] [[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]] [[0.]
 [0.]
 [0.]]
def update_parameters_with_adam(parameters,grads,v,s,t,beta1=0.9,beta2=0.999,epsilon=1e-8,learning_rate=0.01):
    """
    使用adam更新參數:
    
    參數:
        parameters - 一個字典變量,具有以下字段
            parameters["W" + str(l)] = Wl
            parameters["b" + str(l)] = bl
        grads - 一個包含梯度值的字典變量,具有以下字段
            grads["dW" + str(l)] = dWl
            grads["db" + str(l)] = dbl
        v - Adam的變量,第一個梯度的移動平均值,是一個字段類型的變量
        s - Adam的變量,平方梯度的移動平均值,是一個字典類型的變量
        t - 當前迭代的次數
        beta1 - 超參數,動量,用於第一階段,使得曲線的Y值不從0開始
        beta2 - RMSprop的一個參數,超參數
        learning_rate - 學習率,實數
        epsilon - 防止除零操作(分母爲0)
    返回:
        parameters - 更新後的參數
        v - 第一個梯度的移動平均值,是一個字典類型的變量
        s - 平方梯度的移動平均值,是一個字典類型的變量
    """
    
    L = len(parameters)//2
    v_corrected = {}
    s_corrected = {}
    
    for l in range(L):
        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)]
        
        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['dW'+str(l+1)] = beta2*s['dW'+str(l+1)]+(1-beta2)*np.square(grads['dW'+str(l+1)])
        s['db'+str(l+1)] = beta2*s['db'+str(l+1)]+(1-beta2)*np.square(grads['db'+str(l+1)])
        
        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['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

測試:

parameters , grads , v , s = testCase.update_parameters_with_adam_test_case()
parameters,v,s = update_parametes_with_adam(parameters,grads,v,s,t=2)
print(parameters['W1'],parameters['b1'],parameters['W2'],parameters['b2'])
print(v['dW1'],v['db1'],v['dW2'],v['db2'])
print(s['dW1'],s['db1'],s['dW2'],s['db2'])

結果:

[[ 1.63178673 -0.61919778 -0.53561312]
 [-1.08040999  0.85796626 -2.29409733]] [[ 1.75225313]
 [-0.75376553]] [[ 0.32648046 -0.25681174  1.46954931]
 [-2.05269934 -0.31497584 -0.37661299]
 [ 1.14121081 -1.09245036 -0.16498684]] [[-0.88529978]
 [ 0.03477238]
 [ 0.57537385]]
[[-0.11006192  0.11447237  0.09015907]
 [ 0.05024943  0.09008559 -0.06837279]] [[-0.01228902]
 [-0.09357694]] [[-0.02678881  0.05303555 -0.06916608]
 [-0.03967535 -0.06871727 -0.08452056]
 [-0.06712461 -0.00126646 -0.11173103]] [[0.02344157]
 [0.16598022]
 [0.07420442]]
[[0.00121136 0.00131039 0.00081287]
 [0.0002525  0.00081154 0.00046748]] [[1.51020075e-05]
 [8.75664434e-04]] [[7.17640232e-05 2.81276921e-04 4.78394595e-04]
 [1.57413361e-04 4.72206320e-04 7.14372576e-04]
 [4.50571368e-04 1.60392066e-07 1.24838242e-03]] [[5.49507194e-05]
 [2.75494327e-03]
 [5.50629536e-04]]

測試

加載數據集

train_X, train_Y = opt_utils.load_dataset(is_plot=True)

在這裏插入圖片描述

定義模型

def model(X,Y,layers_dims,optimizer,learning_rate=0.007,mini_batch_size=64,beta=0.9,beta1=0.9,beta2=0.999,epsilon=1e-8,num_epochs=10000,print_cost=True,is_plot=True):
    """
    可以運行在不同優化器模式下的3層神經網絡模型
    
    參數:
        X - 輸入數據,維度爲(2,樣本的數量)
        Y - 對應的是x的標籤,[1|0](藍|紅),維度爲(1,樣本的數量)
        layers_dims - 包含層數和節點數量的列表
        optimizer - 字符串類型的參數,用於選擇優化類型,['gd'|'momentum'|'adam']
        learning_rate - 學習率
        mini_batch_size - 每個小批量數據集的大小
        beta - 用於動量優化的一個超參數
        beta1 - 用於計算梯度後的指數衰減的估計的超參數
        beta2 - 用於平方梯度後的指數衰減的估計的超參數
        epsilon - 用於在Adam中避免除零操作的超參數,一般不更改
        num_epochs - 整個訓練集的遍歷次數,相當於之前的num_iteration
        print_cost - 是否打印誤差值,每遍歷1000次數據集打印一次,但是每100次記錄一個誤差值,又稱每1000代打印一次
        is_plot - 是否繪製出曲線圖
    返回:
        parameters - 包括了學習後的參數
    """
    
    L = len(layers_dims)
    costs = []
    t = 0
    seed = 10
    
    parameters = opt_utils.initialize_parameters(layers_dims)
    
    if optimizer=='gd':
        pass
    elif optimizer=='momentum':
        v = initialize_velocity(parameters)
    elif optimizer=='adam':
        v,s = initialize_adam(parameters)
    else:
        print('optimizer參數錯誤,程序退出。')
        exit(1)
        
    for i in range(num_epochs):
        seed = seed + 1 
        minibatches = random_mini_batches(X,Y,mini_batch_size,seed)
        
        for minibatch in minibatches:
            minibatch_X,minibatch_Y = minibatch
            
            A3,caches = opt_utils.forward_propagation(minibatch_X,parameters)
            
            cost = opt_utils.compute_cost(A3,minibatch_Y)
            
            grads = opt_utils.backward_propagation(minibatch_X,minibatch_Y,caches)
            
            if optimizer=='gd':
                parameters = update_parameters_with_gd(parameters,grads,learning_rate)
            elif optimizer=='momentum':
                parameters,v = update_parameters_with_momentum(parameters,grads,v,beta,learning_rate)
            elif optimizer=='adam':
                t = t + 1
                parameters,v,s = update_parameters_with_adam(parameters,grads,v,s,t,learning_rate,beta1,beta2,epsilon)
        
        if i%100==0:
            costs.append(cost)
            if print_cost and i%1000==0:
                print('i=',i,',cost=',cost)
                
    if is_plot:
        plt.plot(costs)
        plt.ylabel('cost')
        plt.xlabel('epochs(per 100)')
        plt.title("learning rate = "+str(learning_rate))
        plt.show()
        
    return parameters

mini-batch梯度下降測試

layers_dims = [train_X.shape[0],5,2,1]
parameters = model(train_X,train_Y,layers_dims,optimizer='gd')
predictions = opt_utils.predict(train_X,train_Y,parameters)

結果:

i= 0 ,cost= 0.6906348872353164
i= 1000 ,cost= 0.529515191486897
i= 2000 ,cost= 0.6179369981287265
i= 3000 ,cost= 0.42394384381259426
i= 4000 ,cost= 0.45474164616291884
i= 5000 ,cost= 0.4904732180685857
i= 6000 ,cost= 0.4318205596870036
i= 7000 ,cost= 0.45309933341108904
i= 8000 ,cost= 0.4469028252590609
i= 9000 ,cost= 0.45757140084424625
Accuracy: 0.797

在這裏插入圖片描述

具有動量的梯度下降測試

layers_dims = [train_X.shape[0],5,2,1]
parameters = model(train_X,train_Y,layers_dims,optimizer='momentum')
predictions = opt_utils.predict(train_X,train_Y,parameters)

結果:

i= 0 ,cost= 0.6907324373984821
i= 1000 ,cost= 0.4492654516390006
i= 2000 ,cost= 0.3758336613787371
i= 3000 ,cost= 0.2615252863821062
i= 4000 ,cost= 0.30240281858054535
i= 5000 ,cost= 0.14262280299160454
i= 6000 ,cost= 0.14335101507523898
i= 7000 ,cost= 0.041849280242154195
i= 8000 ,cost= 0.13333187378180045
i= 9000 ,cost= 0.19900064349545424
Accuracy: 0.797

在這裏插入圖片描述

Adam優化後的梯度下降測試

layers_dims = [train_X.shape[0],5,2,1]
parameters = model(train_X,train_Y,layers_dims,optimizer='adam')
predictions = opt_utils.predict(train_X,train_Y,parameters)

結果:

i= 0 ,cost= 0.6907422847195794
i= 1000 ,cost= 0.7279949298531373
i= 2000 ,cost= 0.6852897046889893
i= 3000 ,cost= 0.6895006058785884
i= 4000 ,cost= 0.7039897353411535
i= 5000 ,cost= 0.7040415668136771
i= 6000 ,cost= 0.6989152351921109
i= 7000 ,cost= 0.7169684815916847
i= 8000 ,cost= 0.6927794629984747
i= 9000 ,cost= 0.6933613021850875
Accuracy: 0.94

在這裏插入圖片描述

總結

優化算法 準確度 曲線平滑度
mini-batch梯度下降 79.7% 震盪
具有動量的梯度下降 79.7% 震盪
Adam優化後的梯度下降 94% 平滑
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章