代碼詳解:基於Python創建任意層數的深度神經網絡

全文共6359字,預計學習時長20分鐘或更長python

圖片來源:pexels.com/@divinetechygirweb

在這篇指南中,咱們將創建起一個任意層數的深度神經網絡。這個神經網絡能夠應用於二元分類的監督學習問題。算法

圖1 神經網絡構造的例子(符號說明:上標[l]表示與第l層;上標(i)表示第i個例子;下標i表示矢量第i項)數據庫

單層神經網絡編程

 

圖2 單層神經網絡示例數組

神經元模型是先計算一個線性函數(z=Wx+b),接着再計算一個激活函數。通常來講,神經元模型的輸出值是a=g(Wx+b),其中g是激活函數(sigmoid,tanh, ReLU, …)。微信

數據集網絡

假設有一個很大的數據庫,裏面記錄了不少天氣數據,例如,氣溫、溼度、氣壓和降雨率。架構

問題陳述:app

一組訓練數據m_train,下雨標記爲(1),不下雨標記爲(0)。

一個測試數據組m_test,標記是否下雨。

每個天氣數據包含x1=氣溫,x2=溼度,x3=氣壓。

機器學習中一個常見的預處理步驟是將數據集居中並標準化,這意味着從每一個示例中減去整個numpy數組的平均值,而後將每一個示例除以整個numpy數組的標準誤差。

 

通用方法(創建部分算法

使用深度學習來建造模型

1. 定義模型構造(例如,數據的輸入特徵)

2. 初始化參數並定義超參數

迭代次數

在神經網絡中的L層的層數

隱藏層大小

學習率α

3. 迭代循環

正向傳播(計算電流損耗)

計算成本函數

反向傳播(計算電流損耗)

升級參數(使用背景參數和梯度)

4. 使用訓練參數來預測標籤

初始化

更深層次的L-層神經網絡的初始化更爲複雜,由於有更多的權重矩陣和偏置向量。下表展現了不一樣結構的各類層級。

表1 L層的權重矩陣w、偏置向量b和激活函數z

表2 示例架構中的神經網絡權重矩陣w、偏置向量b和激活函數z

表2幫助咱們爲圖1中的示例神經網絡架構的矩陣準備了正確的維度。

import numpy as np
import matplotlib.pyplot as plt

nn_architecture = [
{"layer_size": 4,"activation": "none"}, # input
 layer
{"layer_size": 5,"activation": "relu"},
{"layer_size": 4,"activation": "relu"},
{"layer_size": 3,"activation": "relu"},
{"layer_size": 1,"activation": "sigmoid"}
]
def initialize_parameters(nn_architecture, seed = 
3):
np.random.seed(seed)
# python dictionary containingour parameters
 "W1", "b1", ..., "WL","bL"
parameters = {}
number_of_layers = len(nn_architecture)

for l in range(1,number_of_layers):
parameters['W' + str(l)] =np.random.randn(
nn_architecture[l]["layer_size"],nn_architecture[l-1]["layer_size"]
) * 0.01
parameters['b' + str(l)]
 =np.zeros((nn_architecture[l]["layer_size"], 1))
return parameters

代碼段1 參數初始化

使用小隨機數初始化參數是一種簡單的方法,但同時也保證算法的起始值足夠好。

記住:

· 不一樣的初始化工具,例如Zero,Random, He or Xavier,都會致使不一樣的結果。

· 隨機初始化可以確保不一樣的隱藏單元能夠學習不一樣的東西(初始化全部權重爲零會致使,全部層次的全部感知機都將學習相同的東西)。

· 不要初始化爲太大的值。

激活函數

激活函數的做用是爲了增長神經網絡的非線性。下例將使用sigmoid and ReLU。

Sigmoid輸出一個介於0和1之間的值,這使得它成爲二進制分類的一個很好的選擇。若是輸出小於0.5,能夠將其分類爲0;若是輸出大於0.5,能夠將其分類爲1。

def sigmoid(Z):
S = 1 / (1 + np.exp(-Z))
return S

def relu(Z):
R = np.maximum(0, Z)
return R

def sigmoid_backward(dA, Z):
S = sigmoid(Z)
dS = S* (1 - S)
return dA * dS

def relu_backward(dA, Z):
dZ = np.array(dA, copy = True)
dZ[Z <= 0] = 0
return dZ

代碼段2 Sigmoid和ReLU激活函數,及其衍生物

在代碼段2中,能夠看到激活函數及其派生的矢量化編程實現。該代碼將用於進一步的計算。

正向傳播

在正向傳播中,在層l的正向函數中,須要知道該層中的激活函數是哪種(sigmoid、tanh、ReLU等)。前一層的輸出值爲這一層的輸入值,先計算z,再用選定的激活函數計算。

圖3 神經網絡的正向傳播

線性正向模塊(對全部示例進行矢量化)計算如下方程式:

 

方程式1 線性正向函數

def L_model_forward(X, parameters,
 nn_architecture):
forward_cache = {}
A = X
number_of_layers =len(nn_architecture)

for l in range(1,number_of_layers):
A_prev = A
W = parameters['W' + str(l)]
b = parameters['b' + str(l)]
activation =nn_architecture[l]
["activation"]Z, A =linear_activation_forward(A_prev, W, b,
 activation)
forward_cache['Z' + str(l)] =Zforward_cache['A' + str(l)] =A

AL = A

return AL, forward_cache

def linear_activation_forward(A_prev, W, b, 
activation):
if activation =="sigmoid":
Z = linear_forward(A_prev, W,b)
A = sigmoid(Z)
elif activation =="relu":
Z = linear_forward(A_prev, W,b)
A = relu(Z)

return Z, A
def linear_forward(A, W, b):
Z = np.dot(W, A) + b
return Z

代碼段3 正向傳播模型

使用「cache」(python字典包含爲特定層所計算的a和z值)以在正向傳播至相應的反向傳播期間傳遞變量。它包含用於反向傳播計算導數的有用值。

損失函數

爲了管程學習過程,須要計算代價函數的值。下面的公式用於計算成本。

 

方程式2 交叉熵成本

 

def compute_cost(AL, Y):
m = Y.shape[1]

# Compute loss from AL and y
logprobs =np.multiply(np.log(AL),Y) + 
np.multiply(1 - Y, np.log(1 - AL))
# cross-entropy cost
cost = - np.sum(logprobs) / m

cost = np.squeeze(cost)

return cost

代碼段4 代價函數的計算

反向傳播

反向傳播用於計算參數的損失函數梯度。該算法是由微分學中已知的「鏈規則」遞歸使用的。

反向傳播計算中使用的公式:

方程式3 反向傳播計算公式

鏈式法則是計算複合函數導數的公式。複合函數就是函數套函數。

 

方程式4 鏈規則示例

「鏈規則」在計算損失時十分重要(以方程式5爲例)。

 

方程式5 損失函數(含替換數據)及其相對於第一權重的導數

神經網絡模型反向傳播的第一步是計算最後一層損失函數相對於z的導數。方程式6由兩部分組成:方程式2損失函數的導數(關於激活函數)和激活函數「sigmoid」關於最後一層Z的導數。

方程式6 從4層對z的損失函數導數

方程式6的結果可用於計算方程式3的導數。

 

方程式7 損失函數相對於3層的導數

在進一步計算中,使用了與第三層激活函數有關的損失函數的導數(方程式7)。

 

方程式8 第三層的導數

方程式7的結果和第三層活化函數「relu」的導數用於計算方程式8的導數(損失函數相對於z的導數)。而後,咱們對方程式3進行了計算。

咱們對方程9和10作了相似的計算。

 

方程式9 第二層的導數

 

方程式10 第一層的導數

整體思路

從第一層層對z的損失函數導數有助於計算(L-1)層(上一層)對損失函數的導數。結果將用於計算激活函數的導數。

圖4 神經網絡的反向傳播

 

def L_model_backward(AL, Y, parameters,
 forward_cache, nn_architecture):
grads = {}number_of_layers =len(nn_architecture)
m = AL.shape[1]
Y = Y.reshape(AL.shape) # afterthis line, Y is
 the same shape as AL

# Initializing thebackpropagation
dAL = - (np.divide(Y, AL) -np.divide(1 - Y, 1 - 
AL))
dA_prev = dAL

for l in reversed(range(1,number_of_layers)):
dA_curr = dA_prev

activation =nn_architecture[l]["activation"]
W_curr = parameters['W' +str(l)]
Z_curr = forward_cache['Z' +str(l)]
A_prev = forward_cache['A' +str(l-1)]

dA_prev, dW_curr, db_curr
 =linear_activation_backward(dA_curr, Z_curr,

 A_prev, W_curr, activation)

grads["dW" +str(l)] = dW_curr
grads["db" +str(l)] = db_curr
return grads
def linear_activation_backward(dA, Z, A_prev, W, 
activation):
if activation =="relu":
dZ = relu_backward(dA, Z)
dA_prev, dW, db =linear_backward(dZ, A_prev, W)
elif activation =="sigmoid":
dZ = sigmoid_backward(dA, Z)
dA_prev, dW, db =linear_backward(dZ, A_prev, W)

return dA_prev, dW, db
def linear_backward(dZ, A_prev, W):
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)

return dA_prev, dW, db

代碼段5 反向傳播模塊

更新參數

該函數的目標是經過梯度優化來更新模型的參數。

def update_parameters(parameters, grads,
 learning_rate):
L = len(parameters)

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

代碼段6 使用梯度降低更新參數值

全模型

神經網絡模型的完整實現包括在片斷中提供的方法。

def L_layer_model(X, Y, nn_architecture, 
learning_rate = 0.0075,num_iterations = 3000,
 print_cost=False):
np.random.seed(1)
# keep track of cost
costs = []

# Parameters initialization.
parameters 
=initialize_parameters(nn_architecture)

# Loop (gradient descent)
for i in range(0,num_iterations):

# Forward propagation:[LINEAR -> RELU]*(L-1) -> 
LINEAR -> SIGMOID.
AL, forward_cache =L_model_forward(X, parameters, 
nn_architecture)

# Compute cost.
cost = compute_cost(AL, Y)

# Backward propagation.
grads = L_model_backward(AL,Y, parameters, 
forward_cache, nn_architecture)

# Update parameters.
parameters =update_parameters(parameters, grads, 
learning_rate)

# Print the cost every 100training example
if print_cost and i % 100 ==0:
print("Cost afteriteration %i: %f" %(i, cost))

costs.append(cost)

# plot the cost
plt.plot(np.squeeze(costs))
plt.ylabel('cost')
plt.xlabel('iterations (pertens)')
plt.title("Learning rate=" + str(learning_rate))
plt.show()
return parameters

代碼段7 整個神經網絡模型

只須要將已知的權重和系列測試數據,應用於正向傳播模型,就能預測結果。

能夠修改snippet1中的nn_架構,以構建具備不一樣層數和隱藏層大小的神經網絡。此外,準備正確實現激活函數及其派生函數(代碼段2)。所實現的函數可用於修改代碼段3中的線性正向激活方法和代碼段5中的線性反向激活方法。

進一步改進

若是訓練數據集不夠大,則可能面臨「過分擬合」問題。這意味着所學的網絡不會歸納爲它從未見過的新例子。可使用正則化方法,如L2規範化(它包括適當地修改爲本函數)或退出(它在每次迭代中隨機關閉一些感知機)。

咱們使用梯度降低來更新參數和最小化成本。你能夠學習更多高級優化方法,這些方法能夠加快學習速度,甚至能夠爲成本函數提供更好的最終價值,例如:

· 小批量梯度降低

· 動力

· Adam優化器

留言 點贊 關注

咱們一塊兒分享AI學習與發展的乾貨
歡迎關注全平臺AI垂類自媒體 「讀芯術」

(添加小編微信:dxsxbb,加入讀者圈,一塊兒討論最新鮮的人工智能科技哦~)

相關文章
相關標籤/搜索