吳恩達深度學習筆記-搭建多層神經(jīng)網(wǎng)絡

吳恩達作業(yè)-搭建多層神經(jīng)網(wǎng)絡当犯。神經(jīng)網(wǎng)絡的結(jié)構(gòu)可以有很多層休玩,結(jié)構(gòu)是輸入層>隱藏層>隱藏層>>>輸出層躏结,在每一層中,首先計算的是矩陣相乘[linear_forward]夸研,然后再計算激活函數(shù)[linear_activation_forward],合并起來就是這一層的計算方式邦蜜,所以每一層的計算都有兩個步驟『ブ粒可參照如下圖:

計算步驟表示圖

文末附全部代碼鏈接

計算偽代碼如下:
1.初始化網(wǎng)絡參數(shù)
2.前向傳播
(1)計算一層的線性求和部分
(2)計算激活函數(shù)的部分
(3)結(jié)合線性求和與激活函數(shù)
3.計算誤差
4.反向傳播
(1)線性部分的反向傳播公式
(2)激活函數(shù)部分的反向傳播公式
(3)結(jié)合線性部分與激活函數(shù)的反向傳播公式
5.更新參數(shù)

每一個前向傳播函數(shù)都對應一個反向傳播函數(shù)

準備軟件庫

開始之前我們要準備軟件庫:

import numpy as np
import h5py
import matplotlib.pyplot as plt
import testCases 
from dnn_utils import sigmoid, sigmoid_backward, relu, relu_backward 
import lr_utils 

然后開始構(gòu)建初始化參數(shù)的函數(shù)悼沈,指定隨機種子

np.random.seed(1)

初始化參數(shù)

對于一個兩層的神經(jīng)網(wǎng)絡結(jié)構(gòu)而言,模型結(jié)構(gòu)是線性->ReLU->線性->sigmoid函數(shù)姐扮。
初始化函數(shù)如下:

def initialize_parameters(n_x,n_h,n_y):
    """
    此函數(shù)是為了初始化兩層網(wǎng)絡參數(shù)而使用的函數(shù)絮供。
    參數(shù):
        n_x - 輸入層節(jié)點數(shù)量
        n_h - 隱藏層節(jié)點數(shù)量
        n_y - 輸出層節(jié)點數(shù)量
    
    返回:
        parameters - 包含你的參數(shù)的python字典:
            W1 - 權(quán)重矩陣,維度為(n_h,n_x)
            b1 - 偏向量茶敏,維度為(n_h壤靶,1)
            W2 - 權(quán)重矩陣,維度為(n_y惊搏,n_h)
            b2 - 偏向量贮乳,維度為(n_y,1)

    """
    W1 = np.random.randn(n_h, n_x) * 0.01
    b1 = np.zeros((n_h, 1))
    W2 = np.random.randn(n_y, n_h) * 0.01
    b2 = np.zeros((n_y, 1))
    
    #使用斷言確保我的數(shù)據(jù)格式是正確的
    assert(W1.shape == (n_h, n_x))
    assert(b1.shape == (n_h, 1))
    assert(W2.shape == (n_y, n_h))
    assert(b2.shape == (n_y, 1))
    
    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}
    
    return parameters  

初始化之后我們測試一下:

print("==============測試initialize_parameters==============")
parameters = initialize_parameters(3,2,1)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

測試結(jié)果:

W1 = [[ 0.01624345 -0.00611756 -0.00528172]
 [-0.01072969  0.00865408 -0.02301539]]
b1 = [[0.]
 [0.]]
W2 = [[ 0.01744812 -0.00761207]]
b2 = [[0.]]

兩層的神經(jīng)網(wǎng)絡已經(jīng)測試完畢胀屿。
現(xiàn)在定義一個計算的函數(shù)塘揣,

def initialize_parameters_deep(layers_dims):
    """
    此函數(shù)是為了初始化多層網(wǎng)絡參數(shù)而使用的函數(shù)。
    參數(shù):
        layers_dims - 包含我們網(wǎng)絡中每個圖層的節(jié)點數(shù)量的列表
    
    返回:
        parameters - 包含參數(shù)“W1”宿崭,“b1”亲铡,...,“WL”,“bL”的字典:
                     W1 - 權(quán)重矩陣奖蔓,維度為(layers_dims [1]赞草,layers_dims [1-1])
                     bl - 偏向量,維度為(layers_dims [1]吆鹤,1)
    """
    np.random.seed(3)
    parameters = {}
    L = len(layers_dims)
    
    for l in range(1,L):
        parameters["W" + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) / np.sqrt(layers_dims[l - 1])
        parameters["b" + str(l)] = np.zeros((layers_dims[l], 1))
        
        #確保我要的數(shù)據(jù)的格式是正確的
        assert(parameters["W" + str(l)].shape == (layers_dims[l], layers_dims[l-1]))
        assert(parameters["b" + str(l)].shape == (layers_dims[l], 1))
        
    return parameters

其中np.random.randn返回一個或一組服從正態(tài)分布的隨機樣本值厨疙。
接下來測試一下這個函數(shù)

#測試initialize_parameters_deep
print("==============測試initialize_parameters_deep==============")
layers_dims = [5,4,3]
parameters = initialize_parameters_deep(layers_dims)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

測試結(jié)果為:

==============測試initialize_parameters_deep==============
W1 = [[ 0.79989897  0.19521314  0.04315498 -0.83337927 -0.12405178]
 [-0.15865304 -0.03700312 -0.28040323 -0.01959608 -0.21341839]
 [-0.58757818  0.39561516  0.39413741  0.76454432  0.02237573]
 [-0.18097724 -0.24389238 -0.69160568  0.43932807 -0.49241241]]
b1 = [[0.]
 [0.]
 [0.]
 [0.]]
W2 = [[-0.59252326 -0.10282495  0.74307418  0.11835813]
 [-0.51189257 -0.3564966   0.31262248 -0.08025668]
 [-0.38441818 -0.11501536  0.37252813  0.98805539]]
b2 = [[0.]
 [0.]
 [0.]]

我們現(xiàn)在就已經(jīng)構(gòu)建了兩層神經(jīng)網(wǎng)絡的初始化參數(shù)的函數(shù),現(xiàn)在我們開始構(gòu)建前向傳播函數(shù)疑务。

前向傳播函數(shù)

前向傳播共有三個步驟
1.linear
2.linear->activation(其中激活函數(shù)將會使用ReLU或Sigmoid)
3.[linear->RELU]*(L-1)->linear->sigmoid(整個模型)
其中線性正向傳播模塊使用如下公式計算


正向傳播公式
線性部分linear

前向傳播中沾凄,線性部分計算如下:

def linear_forward(A,W,b):
    """
    實現(xiàn)前向傳播的線性部分。

    參數(shù):
        A - 來自上一層(或輸入數(shù)據(jù))的激活知允,維度為(上一層的節(jié)點數(shù)量撒蟀,示例的數(shù)量)
        W - 權(quán)重矩陣,numpy數(shù)組温鸽,維度為(當前圖層的節(jié)點數(shù)量保屯,前一圖層的節(jié)點數(shù)量)
        b - 偏向量,numpy向量涤垫,維度為(當前圖層節(jié)點數(shù)量姑尺,1)

    返回:
         Z - 激活功能的輸入,也稱為預激活參數(shù)
         cache - 一個包含“A”蝠猬,“W”和“b”的字典切蟋,存儲這些變量以有效地計算后向傳遞
    """
    Z = np.dot(W,A) + b
    assert(Z.shape == (W.shape[0],A.shape[1]))
    cache = (A,W,b)
     
    return Z,cache

測試一下線性部分:

#測試linear_forward
print("==============測試linear_forward==============")
A,W,b = testCases.linear_forward_test_case()
Z,linear_cache = linear_forward(A,W,b)
print("Z = " + str(Z))

測試結(jié)果:

==============測試linear_forward==============
Z = [[ 3.26295337 -1.23429987]]
線性激活部分linear->activation

為了方便,我們把線性和激活功能分組為一個功能吱雏。因此我們將實現(xiàn)一個執(zhí)行l(wèi)inear前進的步驟敦姻,然后執(zhí)行activation前進步驟的功能。


激活函數(shù)表達式

我們?yōu)榱藢崿F(xiàn)線性激活這個步驟歧杏,使用的公式是
線性激活表達式

其中函數(shù)g會是sigmoid或者是relu镰惦,但是sigmoid函數(shù)只會在輸出層使用!
前向線性激活部分如下:
def linear_activation_forward(A_prev,W,b,activation):
    """
    實現(xiàn)LINEAR-> ACTIVATION 這一層的前向傳播

    參數(shù):
        A_prev - 來自上一層(或輸入層)的激活犬绒,維度為(上一層的節(jié)點數(shù)量旺入,示例數(shù))
        W - 權(quán)重矩陣,numpy數(shù)組凯力,維度為(當前層的節(jié)點數(shù)量茵瘾,前一層的大小)
        b - 偏向量咐鹤,numpy陣列拗秘,維度為(當前層的節(jié)點數(shù)量,1)
        activation - 選擇在此層中使用的激活函數(shù)名祈惶,字符串類型雕旨,【"sigmoid" | "relu"】

    返回:
        A - 激活函數(shù)的輸出扮匠,也稱為激活后的值
        cache - 一個包含“l(fā)inear_cache”和“activation_cache”的字典,我們需要存儲它以有效地計算后向傳遞
    """
    
    if activation == "sigmoid":
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = sigmoid(Z)
    elif activation == "relu":
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = relu(Z)
    
    assert(A.shape == (W.shape[0],A_prev.shape[1]))
    cache = (linear_cache,activation_cache)
    
    return A,cache

接下來測試一下:

#測試linear_activation_forward
print("==============測試linear_activation_forward==============")
A_prev, W,b = testCases.linear_activation_forward_test_case()

A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "sigmoid")
print("sigmoid凡涩,A = " + str(A))

A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "relu")
print("ReLU棒搜,A = " + str(A))

測試結(jié)果:

==============測試linear_activation_forward==============
sigmoid,A = [[0.96890023 0.11013289]]
ReLU活箕,A = [[3.43896131 0.        ]]

現(xiàn)在為止力麸,兩層模型的前向傳播函數(shù)已經(jīng)完成了,那多層網(wǎng)絡模型的前向傳播要怎么做呢育韩,我們繼續(xù)調(diào)用上面的函數(shù)來實現(xiàn)它們克蚂,為了實現(xiàn)在L層神經(jīng)網(wǎng)絡時更加方便,我們需要一個函數(shù)來復制前一個函數(shù)(ReLU)L-1次筋讨,然后用一個帶有Sigmoid函數(shù)來跟蹤它陨舱,結(jié)構(gòu)如下圖:


多層網(wǎng)絡結(jié)構(gòu)

多層模型的前向傳播計算模型代碼如下:

def L_model_forward(X,parameters):
    """
    實現(xiàn)[LINEAR-> RELU] *(L-1) - > LINEAR-> SIGMOID計算前向傳播,也就是多層網(wǎng)絡的前向傳播版仔,為后面每一層都執(zhí)行LINEAR和ACTIVATION
    
    參數(shù):
        X - 數(shù)據(jù),numpy數(shù)組误墓,維度為(輸入節(jié)點數(shù)量蛮粮,示例數(shù))
        parameters - initialize_parameters_deep()的輸出
    
    返回:
        AL - 最后的激活值
        caches - 包含以下內(nèi)容的緩存列表:
                 linear_relu_forward()的每個cache(有L-1個,索引為從0到L-2)
                 linear_sigmoid_forward()的cache(只有一個谜慌,索引為L-1)
    """
    caches = []
    A = X
    L = len(parameters) // 2
    for l in range(1,L):
        A_prev = A 
        A, cache = linear_activation_forward(A_prev, parameters['W' + str(l)], parameters['b' + str(l)], "relu")
        caches.append(cache)
    
    AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], "sigmoid")
    caches.append(cache)
    
    assert(AL.shape == (1,X.shape[1]))
    
    return AL,caches

然后測試一下:

==============測試L_model_forward==============
AL = [[0.17007265 0.2524272 ]]
caches 的長度為 = 2

測試結(jié)果如上所示然想,其中AL表達式如下圖所示:


AL表達式

計算成本

我們已經(jīng)把模型的前向傳播部分完成了,接下來需要計算成本(誤差)欣范,以確定它到底有沒有在學習变泄,成本的計算公式如下:


成本計算公式

代碼如下:

def compute_cost(AL,Y):
    """
    實施等式(4)定義的成本函數(shù)。

    參數(shù):
        AL - 與標簽預測相對應的概率向量恼琼,維度為(1妨蛹,示例數(shù)量)
        Y - 標簽向量(例如:如果不是貓,則為0晴竞,如果是貓則為1)蛙卤,維度為(1,數(shù)量)

    返回:
        cost - 交叉熵成本
    """
    m = Y.shape[1]
    cost = -np.sum(np.multiply(np.log(AL),Y) + np.multiply(np.log(1 - AL), 1 - Y)) / m
        
    cost = np.squeeze(cost)
    assert(cost.shape == ())

    return cost

接下來測試一下這個函數(shù)

#測試compute_cost
print("==============測試compute_cost==============")
Y,AL = testCases.compute_cost_test_case()
print("cost = " + str(compute_cost(AL, Y)))

誤差結(jié)果

==============測試compute_cost==============
cost = 0.414931599615397

誤差值已經(jīng)計算出來了噩死,現(xiàn)在進行反向傳播颤难!

反向傳播

反向傳播用于計算相對于參數(shù)的損失函數(shù)的梯度,首先我們看下前向和后向傳播的流程圖:


前向反向傳播流程圖

然后對于線性部分的公式如下圖


線性部分公式

然后我們使用鏈式求導法則通過dZ來計算三個輸出已维,公式如下:
求導公式

與前向傳播類似行嗤,我們需要使用三個步驟來構(gòu)建反向傳播:
1.linear后向計算
2.linear-activation后向計算,其中activation計算ReLU或Sigmoid結(jié)果
3.linear->ReLU*(L-1)->linear->Sigmoid后向計算

線性部分(linear backward)

首先實現(xiàn)后向傳播線性部分:

def linear_backward(dZ,cache):
    """
    為單層實現(xiàn)反向傳播的線性部分(第L層)

    參數(shù):
         dZ - 相對于(當前第l層的)線性輸出的成本梯度
         cache - 來自當前層前向傳播的值的元組(A_prev垛耳,W栅屏,b)

    返回:
         dA_prev - 相對于激活(前一層l-1)的成本梯度飘千,與A_prev維度相同
         dW - 相對于W(當前層l)的成本梯度,與W的維度相同
         db - 相對于b(當前層l)的成本梯度既琴,與b維度相同
    """
    A_prev, W, b = cache
    m = A_prev.shape[1]
    dW = np.dot(dZ, A_prev.T) / m
    db = np.sum(dZ, axis=1, keepdims=True) / m
    dA_prev = np.dot(W.T, dZ)
    
    assert (dA_prev.shape == A_prev.shape)
    assert (dW.shape == W.shape)
    assert (db.shape == b.shape)
    
    return dA_prev, dW, db

接下來測試函數(shù)

#測試linear_backward
print("==============測試linear_backward==============")
dZ, linear_cache = testCases.linear_backward_test_case()

dA_prev, dW, db = linear_backward(dZ, linear_cache)
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db))

測試結(jié)果:

==============測試linear_backward==============
dA_prev = [[ 0.51822968 -0.19517421]
 [-0.40506361  0.15255393]
 [ 2.37496825 -0.89445391]]
dW = [[-0.10076895  1.40685096  1.64992505]]
db = [[0.50629448]]

線性激活部分(linear->activation backward)

這兒為了實現(xiàn)linear_activation_backward占婉,這兒有兩個后向傳播函數(shù):
sigmoid_backward

dZ = sigmoid_backward(deactivation_cache)

relu_backward

dZ = relu_backward(deactivation_cache)

如果g(.)是激活函數(shù),那么上述兩個后向傳播函數(shù)計算應該是:


計算dZ

現(xiàn)在開始實現(xiàn)后向線性激活:

def linear_activation_backward(dA,cache,activation="relu"):
    """
    實現(xiàn)LINEAR-> ACTIVATION層的后向傳播甫恩。
    
    參數(shù):
         dA - 當前層l的激活后的梯度值
         cache - 我們存儲的用于有效計算反向傳播的值的元組(值為linear_cache逆济,activation_cache)
         activation - 要在此層中使用的激活函數(shù)名,字符串類型磺箕,【"sigmoid" | "relu"】
    返回:
         dA_prev - 相對于激活(前一層l-1)的成本梯度值奖慌,與A_prev維度相同
         dW - 相對于W(當前層l)的成本梯度值,與W的維度相同
         db - 相對于b(當前層l)的成本梯度值松靡,與b的維度相同
    """
    linear_cache, activation_cache = cache
    if activation == "relu":
        dZ = relu_backward(dA, activation_cache)
        dA_prev, dW, db = linear_backward(dZ, linear_cache)
    elif activation == "sigmoid":
        dZ = sigmoid_backward(dA, activation_cache)
        dA_prev, dW, db = linear_backward(dZ, linear_cache)
    
    return dA_prev,dW,db

測試上述函數(shù):

#測試linear_activation_backward
print("==============測試linear_activation_backward==============")
AL, linear_activation_cache = testCases.linear_activation_backward_test_case()
 
dA_prev, dW, db = linear_activation_backward(AL, linear_activation_cache, activation = "sigmoid")
print ("sigmoid:")
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db) + "\n")
 
dA_prev, dW, db = linear_activation_backward(AL, linear_activation_cache, activation = "relu")
print ("relu:")
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db))

測試結(jié)果:

==============測試linear_activation_backward==============
sigmoid:
dA_prev = [[ 0.11017994  0.01105339]
 [ 0.09466817  0.00949723]
 [-0.05743092 -0.00576154]]
dW = [[ 0.10266786  0.09778551 -0.01968084]]
db = [[-0.05729622]]

relu:
dA_prev = [[ 0.44090989  0.        ]
 [ 0.37883606  0.        ]
 [-0.2298228   0.        ]]
dW = [[ 0.44513824  0.37371418 -0.10478989]]
db = [[-0.20837892]]

現(xiàn)在我們已經(jīng)把兩層模型的后向計算完成了简僧,對于多層模型我們也需要這兩個函數(shù)來完成,流程圖如下:


反向傳播流程圖

在之前的前向計算中雕欺,我們存儲了一些包含(X岛马,w,b屠列,z)的cache啦逆,在每一步中,我們需要用那一層的cache值來進行反向傳播笛洛。

上面提到了AL屬于輸出層夏志,
AL

所以我們要計算dAL,我們可以使用下面代碼來計算
dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))

計算完之后我們可以使用此激活后的梯度dAL繼續(xù)向后計算苛让,如下代碼構(gòu)建多層模型向后傳播函數(shù):

def L_model_backward(AL,Y,caches):
    """
    對[LINEAR-> RELU] *(L-1) - > LINEAR - > SIGMOID組執(zhí)行反向傳播沟蔑,就是多層網(wǎng)絡的向后傳播
    
    參數(shù):
     AL - 概率向量,正向傳播的輸出(L_model_forward())
     Y - 標簽向量(例如:如果不是貓狱杰,則為0瘦材,如果是貓則為1),維度為(1仿畸,數(shù)量)
     caches - 包含以下內(nèi)容的cache列表:
                 linear_activation_forward("relu")的cache宇色,不包含輸出層
                 linear_activation_forward("sigmoid")的cache
    
    返回:
     grads - 具有梯度值的字典
              grads [“dA”+ str(l)] = ...
              grads [“dW”+ str(l)] = ...
              grads [“db”+ str(l)] = ...
    """
    grads = {}
    L = len(caches)
    m = AL.shape[1]
    Y = Y.reshape(AL.shape)
    dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))
    
    current_cache = caches[L-1]
    grads["dA" + str(L)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(dAL, current_cache, "sigmoid")
    
    for l in reversed(range(L-1)):
        current_cache = caches[l]
        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads["dA" + str(l + 2)], current_cache, "relu")
        grads["dA" + str(l + 1)] = dA_prev_temp
        grads["dW" + str(l + 1)] = dW_temp
        grads["db" + str(l + 1)] = db_temp
    
    return grads

測試如下:

#測試L_model_backward
print("==============測試L_model_backward==============")
AL, Y_assess, caches = testCases.L_model_backward_test_case()
grads = L_model_backward(AL, Y_assess, caches)
print ("dW1 = "+ str(grads["dW1"]))
print ("db1 = "+ str(grads["db1"]))
print ("dA1 = "+ str(grads["dA1"]))

結(jié)果如下:

dW1 = [[0.41010002 0.07807203 0.13798444 0.10502167]
 [0.         0.         0.         0.        ]
 [0.05283652 0.01005865 0.01777766 0.0135308 ]]
db1 = [[-0.22007063]
 [ 0.        ]
 [-0.02835349]]
dA1 = [[ 0.          0.52257901]
 [ 0.         -0.3269206 ]
 [ 0.         -0.32070404]
 [ 0.         -0.74079187]]

更新參數(shù)

我們現(xiàn)在把前向后向傳播都完成了,現(xiàn)在開始更新參數(shù)颁湖,更新參數(shù)公式如下:


更新參數(shù)公式

代碼如下:

def update_parameters(parameters, grads, learning_rate):
    """
    使用梯度下降更新參數(shù)
    
    參數(shù):
     parameters - 包含你的參數(shù)的字典
     grads - 包含梯度值的字典宣蠕,是L_model_backward的輸出
    
    返回:
     parameters - 包含更新參數(shù)的字典
                   參數(shù)[“W”+ str(l)] = ...
                   參數(shù)[“b”+ str(l)] = ...
    """
    L = len(parameters) // 2 #整除
    for l in range(L):
        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)]
        
    return parameters

測試代碼如下:

#測試update_parameters
print("==============測試update_parameters==============")
parameters, grads = testCases.update_parameters_test_case()
parameters = update_parameters(parameters, grads, 0.1)
 
print ("W1 = "+ str(parameters["W1"]))
print ("b1 = "+ str(parameters["b1"]))
print ("W2 = "+ str(parameters["W2"]))
print ("b2 = "+ str(parameters["b2"]))

測試結(jié)果如下:

==============測試update_parameters==============
W1 = [[-0.59562069 -0.09991781 -2.14584584  1.82662008]
 [-1.76569676 -0.80627147  0.51115557 -1.18258802]
 [-1.0535704  -0.86128581  0.68284052  2.20374577]]
b1 = [[-0.04659241]
 [-1.28888275]
 [ 0.53405496]]
W2 = [[-0.55569196  0.0354055   1.32964895]]
b2 = [[-0.84610769]]

目前為止,我們已經(jīng)實現(xiàn)了該神經(jīng)網(wǎng)絡中所有需要的函數(shù)甥捺。接下來抢蚀,我們將這些方法組合在一起,構(gòu)成一個神經(jīng)網(wǎng)絡類镰禾,可以方便使用皿曲。



搭建一個兩層神經(jīng)網(wǎng)絡

一個兩層神經(jīng)網(wǎng)絡模型圖如下:

兩層神經(jīng)網(wǎng)絡模型圖

該模型可以概括為:input->linear->relu->linear->sigmoid->output下面開始正式構(gòu)建兩層神經(jīng)網(wǎng)絡:

def two_layer_model(X,Y,layers_dims,learning_rate=0.0075,num_iterations=3000,print_cost=False,isPlot=True):
    """
    實現(xiàn)一個兩層的神經(jīng)網(wǎng)絡唱逢,【LINEAR->RELU】 -> 【LINEAR->SIGMOID】
    參數(shù):
        X - 輸入的數(shù)據(jù),維度為(n_x屋休,例子數(shù))
        Y - 標簽坞古,向量,0為非貓劫樟,1為貓痪枫,維度為(1,數(shù)量)
        layers_dims - 層數(shù)的向量,維度為(n_y,n_h,n_y)
        learning_rate - 學習率
        num_iterations - 迭代的次數(shù)
        print_cost - 是否打印成本值叠艳,每100次打印一次
        isPlot - 是否繪制出誤差值的圖譜
    返回:
        parameters - 一個包含W1奶陈,b1,W2附较,b2的字典變量
    """
    np.random.seed(1)
    grads = {}
    costs = []
    (n_x,n_h,n_y) = layers_dims
    
    """
    初始化參數(shù)
    """
    parameters = initialize_parameters(n_x, n_h, n_y)
    
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]
    
    """
    開始進行迭代
    """
    for i in range(0,num_iterations):
        #前向傳播
        A1, cache1 = linear_activation_forward(X, W1, b1, "relu")
        A2, cache2 = linear_activation_forward(A1, W2, b2, "sigmoid")
        
        #計算成本
        cost = compute_cost(A2,Y)
        
        #后向傳播
        ##初始化后向傳播
        dA2 = - (np.divide(Y, A2) - np.divide(1 - Y, 1 - A2))
        
        ##向后傳播吃粒,輸入:“dA2,cache2拒课,cache1”徐勃。 輸出:“dA1,dW2早像,db2;還有dA0(未使用)疏旨,dW1,db1”扎酷。
        dA1, dW2, db2 = linear_activation_backward(dA2, cache2, "sigmoid")
        dA0, dW1, db1 = linear_activation_backward(dA1, cache1, "relu")
        
        ##向后傳播完成后的數(shù)據(jù)保存到grads
        grads["dW1"] = dW1
        grads["db1"] = db1
        grads["dW2"] = dW2
        grads["db2"] = db2
        
        #更新參數(shù)
        parameters = update_parameters(parameters,grads,learning_rate)
        W1 = parameters["W1"]
        b1 = parameters["b1"]
        W2 = parameters["W2"]
        b2 = parameters["b2"]
        
        #打印成本值,如果print_cost=False則忽略
        if i % 100 == 0:
            #記錄成本
            costs.append(cost)
            #是否打印成本值
            if print_cost:
                print("第", i ,"次迭代遏匆,成本值為:" ,np.squeeze(cost))
    #迭代完成法挨,根據(jù)條件繪制圖
    if isPlot:
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations (per tens)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()
    
    #返回parameters
    return parameters

現(xiàn)在開始加載數(shù)據(jù)集,圖像數(shù)據(jù)集參考貓的圖像數(shù)據(jù)集幅聘,代碼如下:

train_set_x_orig , train_set_y , test_set_x_orig , test_set_y , classes = lr_utils.load_dataset()

train_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T 
test_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T

train_x = train_x_flatten / 255
train_y = train_set_y
test_x = test_x_flatten / 255
test_y = test_set_y

數(shù)據(jù)集加載完成凡纳,正式開始訓練:

n_x = 12288
n_h = 7
n_y = 1
layers_dims = (n_x,n_h,n_y)

parameters = two_layer_model(train_x, train_set_y, layers_dims = (n_x, n_h, n_y), num_iterations = 2500, print_cost=True,isPlot=True)

訓練結(jié)果如下:

第 0 次迭代,成本值為: 0.6930497356599891
第 100 次迭代帝蒿,成本值為: 0.6464320953428849
第 200 次迭代荐糜,成本值為: 0.6325140647912677
第 300 次迭代,成本值為: 0.6015024920354665
第 400 次迭代葛超,成本值為: 0.5601966311605748
第 500 次迭代暴氏,成本值為: 0.515830477276473
第 600 次迭代,成本值為: 0.4754901313943325
第 700 次迭代绣张,成本值為: 0.4339163151225749
第 800 次迭代答渔,成本值為: 0.40079775362038866
第 900 次迭代,成本值為: 0.3580705011323798
第 1000 次迭代侥涵,成本值為: 0.3394281538366414
第 1100 次迭代沼撕,成本值為: 0.3052753636196265
第 1200 次迭代宋雏,成本值為: 0.2749137728213017
第 1300 次迭代,成本值為: 0.24681768210614827
第 1400 次迭代务豺,成本值為: 0.198507350374661
第 1500 次迭代磨总,成本值為: 0.17448318112556616
第 1600 次迭代,成本值為: 0.17080762978096295
第 1700 次迭代笼沥,成本值為: 0.1130652456216473
第 1800 次迭代蚪燕,成本值為: 0.09629426845937158
第 1900 次迭代,成本值為: 0.0834261795972687
第 2000 次迭代敬拓,成本值為: 0.07439078704319091
第 2100 次迭代邻薯,成本值為: 0.06630748132267937
第 2200 次迭代,成本值為: 0.05919329501038175
第 2300 次迭代乘凸,成本值為: 0.05336140348560559
第 2400 次迭代厕诡,成本值為: 0.04855478562877021
迭代cost值

迭代完成之后我們就可以預測了,預測函數(shù)如下:

def predict(X, y, parameters):
    """
    該函數(shù)用于預測L層神經(jīng)網(wǎng)絡的結(jié)果营勤,當然也包含兩層
    
    參數(shù):
     X - 測試集
     y - 標簽
     parameters - 訓練模型的參數(shù)
    
    返回:
     p - 給定數(shù)據(jù)集X的預測
    """
    
    m = X.shape[1]
    n = len(parameters) // 2 # 神經(jīng)網(wǎng)絡的層數(shù)
    p = np.zeros((1,m))
    
    #根據(jù)參數(shù)前向傳播
    probas, caches = L_model_forward(X, parameters)
    
    for i in range(0, probas.shape[1]):
        if probas[0,i] > 0.5:
            p[0,i] = 1
        else:
            p[0,i] = 0
    
    print("準確度為: "  + str(float(np.sum((p == y))/m)))
        
    return p

預測函數(shù)構(gòu)建好之后灵嫌,我們就開始預測,查看訓練集和測試集的準確性:

predictions_train = predict(train_x, train_y, parameters) #訓練集
predictions_test = predict(test_x, test_y, parameters) #測試集

預測結(jié)果:

準確度為: 1.0
準確度為: 0.72

結(jié)果比第一次的70要高一點葛作,如果使用更多層的神經(jīng)網(wǎng)絡的話寿羞,會不會效率更高一點呢?

搭建多層神經(jīng)網(wǎng)絡

首先查看多層神經(jīng)網(wǎng)絡結(jié)構(gòu)


多層神經(jīng)網(wǎng)絡模型

代碼如下:

def L_layer_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=3000, print_cost=False,isPlot=True):
    """
    實現(xiàn)一個L層神經(jīng)網(wǎng)絡:[LINEAR-> RELU] *(L-1) - > LINEAR-> SIGMOID赂蠢。
    
    參數(shù):
        X - 輸入的數(shù)據(jù)绪穆,維度為(n_x,例子數(shù))
        Y - 標簽虱岂,向量玖院,0為非貓,1為貓第岖,維度為(1,數(shù)量)
        layers_dims - 層數(shù)的向量难菌,維度為(n_y,n_h,···,n_h,n_y)
        learning_rate - 學習率
        num_iterations - 迭代的次數(shù)
        print_cost - 是否打印成本值,每100次打印一次
        isPlot - 是否繪制出誤差值的圖譜
    
    返回:
     parameters - 模型學習的參數(shù)蔑滓。 然后他們可以用來預測郊酒。
    """
    np.random.seed(1)
    costs = []
    
    parameters = initialize_parameters_deep(layers_dims)
    
    for i in range(0,num_iterations):
        AL , caches = L_model_forward(X,parameters)
        
        cost = compute_cost(AL,Y)
        
        grads = L_model_backward(AL,Y,caches)
        
        parameters = update_parameters(parameters,grads,learning_rate)
        
        #打印成本值,如果print_cost=False則忽略
        if i % 100 == 0:
            #記錄成本
            costs.append(cost)
            #是否打印成本值
            if print_cost:
                print("第", i ,"次迭代键袱,成本值為:" ,np.squeeze(cost))
    #迭代完成燎窘,根據(jù)條件繪制圖
    if isPlot:
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations (per tens)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()
    return parameters

加載數(shù)據(jù)集信息:

train_set_x_orig , train_set_y , test_set_x_orig , test_set_y , classes = lr_utils.load_dataset()

train_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T 
test_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T

train_x = train_x_flatten / 255
train_y = train_set_y
test_x = test_x_flatten / 255
test_y = test_set_y

訓練神經(jīng)網(wǎng)絡:

layers_dims = [12288, 20, 7, 5, 1] #  5-layer model
parameters = L_layer_model(train_x, train_y, layers_dims, num_iterations = 2500, print_cost = True,isPlot=True)

訓練結(jié)果:

第 0 次迭代,成本值為: 0.715731513413713
第 100 次迭代蹄咖,成本值為: 0.6747377593469114
第 200 次迭代荠耽,成本值為: 0.6603365433622127
第 300 次迭代,成本值為: 0.6462887802148751
第 400 次迭代比藻,成本值為: 0.6298131216927773
第 500 次迭代铝量,成本值為: 0.606005622926534
第 600 次迭代倘屹,成本值為: 0.5690041263975134
第 700 次迭代,成本值為: 0.519796535043806
第 800 次迭代慢叨,成本值為: 0.46415716786282285
第 900 次迭代纽匙,成本值為: 0.40842030048298916
第 1000 次迭代,成本值為: 0.37315499216069026
第 1100 次迭代拍谐,成本值為: 0.3057237457304711
第 1200 次迭代烛缔,成本值為: 0.26810152847740837
第 1300 次迭代,成本值為: 0.23872474827672677
第 1400 次迭代轩拨,成本值為: 0.20632263257914715
第 1500 次迭代践瓷,成本值為: 0.17943886927493619
第 1600 次迭代,成本值為: 0.15798735818801737
第 1700 次迭代亡蓉,成本值為: 0.14240413012274625
第 1800 次迭代晕翠,成本值為: 0.12865165997889375
第 1900 次迭代,成本值為: 0.11244314998166524
第 2000 次迭代砍濒,成本值為: 0.08505631034986234
第 2100 次迭代淋肾,成本值為: 0.05758391198619335
第 2200 次迭代,成本值為: 0.044567534547003976
第 2300 次迭代爸邢,成本值為: 0.038082751666008864
第 2400 次迭代樊卓,成本值為: 0.03441074901842407

預測結(jié)果:

準確度為: 0.9952153110047847
準確度為: 0.78
截屏2020-02-10下午9.34.21.png

通過準確度來說,從70%到72%到78%杠河,可以看到的是準確度在一點點增加碌尔,如果調(diào)整迭代次數(shù)或者學習率等參數(shù),準確率可能就會有要高一點券敌。




我們可以看下哪些東西在l層模型中被錯誤的標記了唾戚,導致準確率沒有提高。代碼如下:

def print_mislabeled_images(classes, X, y, p):
    """
    繪制預測和實際不同的圖像陪白。
        X - 數(shù)據(jù)集
        y - 實際的標簽
        p - 預測
    """
    a = p + y
    mislabeled_indices = np.asarray(np.where(a == 1))
    plt.rcParams['figure.figsize'] = (40.0, 40.0) # set default size of plots
    num_images = len(mislabeled_indices[0])
    for i in range(num_images):
        index = mislabeled_indices[1][I]
        
        plt.subplot(2, num_images, i + 1)
        plt.imshow(X[:,index].reshape(64,64,3), interpolation='nearest')
        plt.axis('off')
        plt.title("Prediction: " + classes[int(p[0,index])].decode("utf-8") + " \n Class: " + classes[y[0,index]].decode("utf-8"))


print_mislabeled_images(classes, test_x, test_y, pred_test)
未成功識別的貓

這些未識別的貓可以看得出來都是識別難度較大的圖片,所以模型的準確率還有待提高膳灶,這一次的作業(yè)就做到這兒咱士,希望后面的作業(yè)還能對這個數(shù)據(jù)集做進一步優(yōu)化!

完整代碼鏈接




了解更多請關(guān)注作者微信公眾號:

一技破萬法
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末轧钓,一起剝皮案震驚了整個濱河市序厉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌毕箍,老刑警劉巖弛房,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異而柑,居然都是意外死亡文捶,警方通過查閱死者的電腦和手機荷逞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粹排,“玉大人种远,你說我怎么就攤上這事⊥缍” “怎么了筛严?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵塞俱,是天一觀的道長。 經(jīng)常有香客問我,道長主卫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任殴泰,我火速辦了婚禮隔躲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宪郊。我一直安慰自己掂恕,他們只是感情好,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布弛槐。 她就那樣靜靜地躺著懊亡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乎串。 梳的紋絲不亂的頭發(fā)上店枣,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機與錄音叹誉,去河邊找鬼鸯两。 笑死,一個胖子當著我的面吹牛长豁,可吹牛的內(nèi)容都是我干的钧唐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼匠襟,長吁一口氣:“原來是場噩夢啊……” “哼钝侠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酸舍,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤帅韧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啃勉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忽舟,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叮阅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刁品。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖帘饶,靈堂內(nèi)的尸體忽然破棺而出哑诊,到底是詐尸還是另有隱情,我是刑警寧澤及刻,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布镀裤,位于F島的核電站,受9級特大地震影響缴饭,放射性物質(zhì)發(fā)生泄漏暑劝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一颗搂、第九天 我趴在偏房一處隱蔽的房頂上張望担猛。 院中可真熱鬧,春花似錦丢氢、人聲如沸傅联。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒸走。三九已至,卻和暖如春貌嫡,著一層夾襖步出監(jiān)牢的瞬間比驻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工岛抄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留别惦,地道東北人。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓夫椭,卻偏偏與公主長得像掸掸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蹭秋,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容