一、綜述
本文根據吳恩達老師第三週的深度學習課程的課後編程作業來寫的,其中涉及到的test_cases.py
和planar_utils.py
在此處下載。
二、準備工作
2.1 分析問題
我們要做的是:建立一個包含一個隱藏層,一個輸出層的神經網絡。該神經網的功能與第二週的Logistic Regression迴歸處理的問題是相似的,都是分類問題。但是,此次的數據集根據單純的Logistic Resgression迴歸處理的結果是不太好的,因此使用帶有隱藏層的神經網絡來處理。
2.2 分析數據
首先,我們查看此次實驗的數據:
# 分析數據
X, Y = planar_utils.load_planar_dataset()
print(np.shape(X))
print(np.shape(Y))
# 可視化
plt.scatter(X[0, :], X[1, :], c=Y, s=40, cmap=plt.cm.Spectral) #繪製散點圖
plt.show()
# 上一語句如出現問題,請使用下面的語句:
# plt.scatter(X[0, :], X[1, :], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral) #繪製散點圖
輸出:
# X(2, 400)
# 也就說明有兩個特徵,即X1 X2,一共有400組特徵輸入
(2, 400)
# Y(1,400)
# 輸出分別是400組輸入的label
(1, 400)
三、分析網絡
我們要建立的網絡結構如下:
3.1 公式及含義
本次實驗涉及到的公式及相關含義:
其中J是交叉熵損失,在《統計學方法》(李航 著)第六章中有詳細講解。其餘公式在吳恩達老師的深度學習課程第一課第三週中講過,如果有什麼忘記或者不清楚的,建議及時回看。
(PS:附上PPT中的梯度下降算法更新參數部分的公式)
其中
四、構建網絡
構建網絡的一般方法如下:
1.定義神經網絡結構(輸入特徵值個數,隱藏層規模,輸出層規模等)
2.初始化模型參數
3.循環優化參數:
3.1 正向傳播
3.2 計算損失
3.3 後向傳播
3.4 更新參數
4.1 定義神經網絡結構
結構如分析網絡時的圖片,有兩個特徵輸入,隱藏層有四個神經元,輸出層有一個神經元,有一個輸出值。
# 定義神經網絡結構
def init_layer_size(x, y):
# 輸出層數量(特徵值個數)
n_x = x.shape[0]
# 隱藏層數量(神經元個數)
n_h = 4
# 輸出層數量
n_y = y.shape[0]
return n_x, n_y, n_h
4.2 初始化模型參數
# 初始化模型參數
# n_x :特徵值類別
# n_y :輸出層輸出個數
# n_h :隱藏層神經元個數
def initialize_parameters(n_x, n_y, n_h):
# 隱藏層
# n_h個神經元(隱藏層輸出個數),n_x個輸入
W1 = np.random.randn(n_h, n_x) * 0.01
# 加到每個神經元上的,所以是(神經元個數,1)
b1 = np.zeros(shape=(n_h, 1))
# 輸出層
# n_y個神經元(輸出層輸出個數),n_h個輸入(來自於隱藏層的輸出)
W2 = np.random.randn(n_y, n_h) * 0.01
# 加到每個神經元上的,所以是(神經元個數,1)
b2 = np.zeros(shape=(n_y, 1))
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))
res = {
'W1': W1,
'b1': b1,
'W2': W2,
'b2': b2
}
return res
4.3 循環優化參數
4.3.1 正向傳播參數
# 正向傳播參數
# X 輸入
# parameters 參數
def forward_propagation(X, parameters):
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
# W1 (4, 2)
# X (2, 400)
# b1 (4, 1)
Z1 = np.dot(W1, X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2, A1) + b2
# A2 (1, 400)
A2 = sigmoid(Z2)
# 確保數據的正確性
assert (A2.shape == (1, X.shape[1]))
res = {
'Z1': Z1,
'A1': A1,
'Z2': Z2,
'A2': A2
}
return A2, res
4.3.2 計算損失
# 計算交叉熵損失(Cost Function)
# A2 (1, 400)
# Y (1, 400)
def compute_cost(A2, Y):
# 訓練集組數
m = Y.shape[1]
cost = (-1 / m) * np.sum(Y * np.log(A2) + (1 - Y) * (np.log(1 - A2))) # 成本函數
cost = float(np.squeeze(cost))
assert (isinstance(cost, float))
return cost
4.3.3 反向傳播
# 反向傳播
def background_propagation(parameters, res, X, Y):
m = Y.shape[1]
W1 = parameters['W1']
W2 = parameters['W2']
A1 = res['A1']
A2 = res['A2']
dZ2 = A2 - Y
dW2 = (1 / m) * np.dot(dZ2, A1.T)
db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)
dZ1 = np.multiply(np.dot(W2.T, dZ2), (1 - np.power(A1, 2)))
dW1 = (1 / m) * np.dot(dZ1, X.T)
db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)
res = {
'dW1': dW1,
'db1': db1,
'dW2': dW2,
'db2': db2,
}
return res
4.3.4 更新參數
# 使用梯度下降算法更新參數
def update_parameters(parameters, res, learning_rate=0.5):
W1, W2 = parameters['W1'], parameters['W2']
b1, b2 = parameters['b1'], parameters['b2']
dW1, dW2 = res['dW1'], res['dW2']
db1, db2 = res['db1'], res['db2']
W1 = W1 - learning_rate * dW1
b1 = b1 - learning_rate * db1
W2 = W2 - learning_rate * dW2
b2 = b2 - learning_rate * db2
res = {
'W1': W1,
'b1': b1,
'W2': W2,
'b2': b2,
}
return res
4.4 預測
def predict(parameters, X):
A2, res = forward_propagation(X, parameters)
predictions = np.round(A2)
return predictions
4.5 整合與調用
def model(X, Y, n_h, num_iterations, print_cost=False):
layer_size = init_layer_size(X, Y)
# 注意layer_size的參數的位置
n_x = layer_size[0]
n_y = layer_size[1]
parameters = initialize_parameters(n_x, n_y, n_h)
W1 = parameters['W1']
b2 = parameters['b2']
W1 = parameters['W1']
b2 = parameters['b2']
for i in range(num_iterations):
A2, res_4_forward_propagation = forward_propagation(X, parameters)
costs = compute_cost(A2, Y)
res_4_background_propagation = background_propagation(parameters, res_4_forward_propagation, X, Y)
parameters = update_parameters(parameters, res_4_background_propagation, learning_rate=0.5)
if print_cost:
if i % 1000 == 0:
print('第', i, '次循環,成本爲:' + str(costs))
return parameters
parameters = model(X, Y, n_h=4, num_iterations=10000, print_cost=True)
4.6 繪製結果
#繪製邊界
planar_utils.plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y)
plt.title("Decision Boundary for hidden layer size " + str(4))
predictions = predict(parameters, X)
print('準確率: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%')
plt.show()
X, Y = planar_utils.load_planar_dataset()
plt.scatter(X[0, :], X[1, :], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral) #繪製散點圖
plt.show()
輸出:
第 0 次循環,成本爲:0.6931125167719424
第 1000 次循環,成本爲:0.3018260619349989
第 2000 次循環,成本爲:0.28671239842926227
第 3000 次循環,成本爲:0.27867697737583497
第 4000 次循環,成本爲:0.2733112974222824
第 5000 次循環,成本爲:0.26926236471810167
第 6000 次循環,成本爲:0.2659462203243697
第 7000 次循環,成本爲:0.26305193251429543
第 8000 次循環,成本爲:0.2603753013304441
第 9000 次循環,成本爲:0.25760866918830294
準確率: 90%