目錄
1.3.淺層神經網絡
1.3.1 淺層神經網絡表示?
1.3.2 單個樣本的向量化表示
1.3.4 激活函數的選擇
1.3.5 修改激活函數
1.3.5 練習???????
1.3.淺層神經網絡
1.3.1 淺層神經網絡表示?
之前已經說過神經網絡的結構了,在這不重復敘述。假設我們有如下結構的網絡
對于這個網絡我們建立一個簡單的圖示?我們對第一個隱藏層記為[1],輸出層為[2]。如下圖
計算圖如下
- 每個神經元的計算分解步驟如下
- 第一層中的第一個神經元
- 第一層中的第二個神經元
得出第一層的計算:
1.3.2 單個樣本的向量化表示
那么現在把上面的第一層的計算過程過程用更簡單的形式表現出來就是這樣的計算
那么對于剛才我們所舉的例子,將所有層通過向量把整個前向過程表示出來,并且確定每一個組成部分的形狀
前向過程計算:?
那么如果有多個樣本,需要這樣去做
- 多個樣本的向量化表示
假設一樣含有M個樣本,那么上述過程變成
1.3.4 激活函數的選擇
涉及到網絡的優化時候,會有不同的激活函數選擇有一個問題是神經網絡的隱藏層和輸出單元用什么激活函數。之前我們都是選用 sigmoid 函數,但有時其他函數的效果會好得多,大多數通過實踐得來,沒有很好的解釋性。
可供選用的激活函數有:
- 1.tanh 函數(the hyperbolic tangent function,雙曲正切函數):
效果比 sigmoid 函數好,因為函數輸出介于 -1 和 1 之間。
注 :tanh 函數存在和 sigmoid 函數一樣的缺點:當 z 趨緊無窮大(或無窮小),導數的梯度(即函數的斜率)就趨緊于 0,這使得梯度算法的速度會減慢。
- 2.ReLU 函數(the rectified linear unit,修正線性單元)
當 z > 0 時,梯度始終為 1,從而提高神經網絡基于梯度算法的運算速度,收斂速度遠大于 sigmoid 和 tanh。然而當 z < 0 時,梯度一直為 0,但是實際的運用中,該缺陷的影響不是很大。
-
Leaky ReLU(帶泄漏的 ReLU):
Leaky ReLU 保證在 z < 0 的時候,梯度仍然不為 0。理論上來說,Leaky ReLU 有 ReLU 的所有優點,但在實際操作中沒有證明總是好于 ReLU,因此不常用。
1.3.4.1 為什么需要非線性的激活函數
使用線性激活函數和不使用激活函數、直接使用 Logistic 回歸沒有區別,那么無論神經網絡有多少層,輸出都是輸入的線性組合,與沒有隱藏層效果相當,就成了最原始的感知器了。
1.3.5 修改激活函數
將上述網絡的隱層激活函數修改為tanh,最后一層同樣還是二分類,所以激活函數選擇依然是sigmoid函數
- 前向傳播
- 反向傳播梯度下降
那么通過這個計算圖來理解這個過程,單個樣本的導數推導過程:
1.3.5 練習
import numpy as np
import matplotlib.pyplot as plt
import sklearn
import sklearn.datasets
import sklearn.linear_model
from load_dataset import load_planar_datasetX, Y = load_planar_dataset()print ('數據集特征值的形狀:', X.shape)
print ('數據集目標值的:', Y.shape)
print ('樣本數:', X.shape[1])def sigmoid(x):""""""s = 1/(1+np.exp(-x))return s* 步驟* 定義網絡結構* 初始化參數* 循環一下步驟* 前向傳播* 計算損失* 反向傳播獲得梯度* 梯度更新
#%% md
### 1、定義神經網絡結構
網絡輸入輸出以及隱藏層神經元個數
#%%
def layer_sizes(X, Y):""""""# 輸入層大小2n_x = X.shape[0]# 隱層大小n_h = 4# 輸出層大小n_y = Y.shape[0]### END CODE HERE ###return (n_x, n_h, n_y)
#%% md
### 2、 初始化模型參數
隨機初始化權重以及偏置為0
#%%
def initialize_parameters(n_x, n_h, n_y):"""輸入每層的神經元數量返回:隱層、輸出層的參數"""np.random.seed(2)### 開始# 創建隱層的兩個參數# 讓值小一些W1 = np.random.randn(n_h, n_x) * 0.01b1 = np.zeros((n_h, 1))# 創建輸出層前對應的參數W2 = np.random.randn(n_y, n_h) * 0.01b2 = np.zeros((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))parameters = {"W1": W1,"b1": b1,"W2": W2,"b2": b2}return parameters
#%% md
### 3、循環中的第一步:前向傳播
根據之前給的前向傳播公式,完成該函數使用的函數:np.dot,np.tanh, np.sigmoid
#%%
def forward_propagation(X, parameters):"""Argument:X:(n_feature, m)Returns:A2:最后一層的輸出cache:用于反向傳播計算的存儲中間計算結果的字典"""# 獲取參數### 開始# 取出每一層的參數W1 = parameters['W1']b1 = parameters['b1']W2 = parameters['W2']b2 = parameters['b2']# 進行一層一層的運算Z1 = np.matmul(W1, X) + b1A1 = np.tanh(Z1)# 第二層Z2 = np.dot(W2, A1) + b2A2 = sigmoid(Z2)### 結束assert(A2.shape == (1, X.shape[1]))cache = {"Z1": Z1,"A1": A1,"Z2": Z2,"A2": A2}return A2, cache
#%% md
### 3、循環中的二步:計算損失
完成損失計算的過程,根據損失公式設計多個維度,使用np.multiply進行乘法運算
#%%
def compute_cost(A2, Y, parameters):"""parameters:最后一層輸出,目標值,參數return:損失"""m = Y.shape[1]### 開始logpro = np.multiply(np.log(A2), Y) + np.multiply((1 - Y), (np.log(1 - A2)))cost = - 1 / m * np.sum(logpro)### 結束cost = np.squeeze(cost)assert(isinstance(cost, float))return cost
#%% md
### 3、循環中的第三步:反向傳播
反向傳播在這個網絡中分為兩步def backward_propagation(parameters, cache, X, Y):"""parameters:cache:存儲每層前向傳播計算結果X:數據特征Y:數據目標值return:每個參數的梯度"""# 得出訓練樣本數量m = X.shape[1]# 獲取參數和緩存中的輸出### 開始W1 = parameters['W1']W2 = parameters['W2']A1 = cache['A1']A2 = cache['A2']### 結束# 反向傳播計算梯度### 開始# 最后一層的參數梯度計算dZ2 = A2 - YdW2 = 1/m * np.dot(dZ2, A1.T)db2 = 1/m * np.sum(dZ2, axis=1, keepdims=True)# 隱藏層的參數梯度計算dZ1 = 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)### 結束grads = {"dW1": dW1,"db1": db1,"dW2": dW2,"db2": db2}return grads
#%% md
### 3、循環中的第四步:更新梯度
#%%
def update_parameters(parameters, grads, learning_rate = 0.005):"""參數:網絡參數,梯度,學習率返回更新之后的參數"""# 獲取參數以及梯度### 開始W1 = parameters['W1']b1 = parameters['b1']W2 = parameters['W2']b2 = parameters['b2']dW1 = grads['dW1']db1 = grads['db1']dW2 = grads['dW2']db2 = grads['db2']## 結束# 使用學習率更新參數### 開始W1 = W1 - learning_rate * dW1b1 = b1 - learning_rate * db1W2 = W2 - learning_rate * dW2b2 = b2 - learning_rate * db2### 結束parameters = {"W1": W1,"b1": b1,"W2": W2,"b2": b2}return parameters
#%% md
### 4、建立網絡模型訓練邏輯
#%%
def nn_model(X, Y, num_iterations = 10000, print_cost=False):""""""np.random.seed(3)n_x = layer_sizes(X, Y)[0]n_y = layer_sizes(X, Y)[2]# 初始化參數### 開始# 獲取網絡的層大小# 2, 4, 1n_x, n_h, n_y = layer_sizes(X, Y)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):### 開始# 前向傳播A2, cache = forward_propagation(X, parameters)# 計算損失cost = compute_cost(A2, Y, parameters)# 反向傳播計算梯度grads = backward_propagation(parameters, cache, X, Y)# 利用梯度更新參數parameters = update_parameters(parameters, grads)### 結束if i % 1000 == 0:print ("迭代次數 %i: %f" %(i, cost))return parameters
#%% md
### 5、預測結果
#%%
def predict(parameters, X):""""""# 計算概率值,以及判斷類別A2, cache = forward_propagation(X, parameters)predictions = np.array( [1 if x >0.5 else 0 for x in A2.reshape(-1,1)] ).reshape(A2.shape)return predictions
#%%
# 測試
parameters = nn_model(X, Y, num_iterations = 10000)predictions = predict(parameters, X)
?
?