吳恩達作業(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前進步驟的功能。
我們?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)如下圖:
多層模型的前向傳播計算模型代碼如下:
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表達式如下圖所示:
計算成本
我們已經(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ù)計算應該是:
現(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值來進行反向傳播笛洛。
所以我們要計算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ù)公式如下:
代碼如下:
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)絡模型圖如下:
該模型可以概括為: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
迭代完成之后我們就可以預測了,預測函數(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)
代碼如下:
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
通過準確度來說,從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)化!