【零基礎】淺層神經網絡解析

回顧:html

【零基礎】AI神經元解析(含實例代碼)網絡

 

1、序言dom

  前兩天寫了關於單神經元的解析,這裏再接再礪繼續淺層神經網絡的解析。淺層神經網絡便是「層次較少」的神經網絡,雖然層次少但其性能相對單神經元強大了不僅一點。ide

  注:本文內容主要是對「牀長」的系列教程進行總結,強烈推薦「牀長」的人工智能系列教程(https://www.captainbed.net/)函數

2、淺層神經網絡的構成post

  回顧前面單神經元的構成,咱們知道神經元包含4個關鍵函數:性能

  1)傳播函數,由輸入x、偏置w、閾值b計算出a學習

  2)激活函數,將a映射到0~1之間的結果y,可理解爲(是、否)的機率優化

  3)反向傳播函數,經過y、答案label計算出dw、db(用以更新w和b)人工智能

  4)損失函數,計算y與label間的偏差

 

   直觀上咱們知道淺層神經網絡天然是由數個神經元構成的,對於一個簡單的兩層神經網絡其結構以下圖所示:

 

  它包含了輸入層(即X)、隱藏層、輸出層,其中輸入層不是神經元,因此說這是一個兩層的神經網絡。

  在實際實現時咱們並非挨個計算每個經元的結果,最後再計算輸出的結果。咱們是一次計算出一層全部的神經元結果,再將每一層的結果做爲輸入計算下一層。並且第一層的傳播函數並不與第二層傳播函數分離,神經網絡的傳播函數包含了全部層的傳播計算,反向傳播函數也是包含了全部層的反向計算,因此從單神經元到神經網絡代碼的結構其實變化不大。

  下面咱們直接上代碼來解析,若是你看明白了前面單神經元的解析,那這裏是很是好理解的。

  (文末附完整代碼下載方式)

3、準備工做

  1)要處理的問題

  以前咱們用單神經元要處理的問題是「從圖片中識別出數字9」,即便使用單神經元也有93%的正確率,因此這裏咱們要增長問題的難度。將問題改成「從圖片中識別出奇數」,代碼上只須要很小的修改,將下面代碼

  #將label不是9的數據所有轉爲0,將9轉爲1
  train_label = np.where(train_label==9,1,0)
  test_label = np.where(test_label==9,1,0)

  修改成:

  #找出圖片中的奇數將label中13579置爲一、02468置爲0
  train_label = np.where((train_label%2)!=0,1,0)
  test_label = np.where((test_label%2)!=0,1,0)

  使用以前的單神經元代碼執行後的結果爲下圖所示,能夠看到預測效果大幅降低。

  2)要使用的網絡結構

  首先要明確神經網絡的層數,這裏咱們是一個簡單的網絡,因此只須要兩層。其次是每一層神經元的個數,這裏咱們網絡第一層設置4個神經元,第二層是輸出層因此只要一個神經元。輸入層跟之前同樣,是784個輸入(一張28x28圖片的全部像素),網絡結構以下圖:

4、隨機初始化參數

#初始化參數w和b
def initialize_parameters(input_num, hide_num, out_num):
  #input_num 輸入層神經元個數
  #hide_num 隱藏層神經元個數
  #out_num 輸出層神經元個數
  np.random.seed(2)
  #隨機初始化第一層相關參數w、b
  W1 = np.random.rand(hide_num, input_num) * 0.01
  b1 = np.zeros(shape=(hide_num, 1))

  #隨機初始化第二層相關參數w、b
  W2 = np.random.randn(out_num, hide_num) * 0.01
  b2 = np.zeros(shape=(out_num, 1))

  return W1,b1,W2,b2

   淺層神經網絡與單神經元在初始化參數w、b的區別有如下幾點:

  1)每一層神經元使用不一樣的w和b,因此有w一、w二、b一、b2,若是是三層網絡則相應會有w三、b3.

  2)不一樣層神經元的w、b的數據形狀是不同的。好比咱們輸入的圖片有784個像素,且第二層有4個神經元,因此第一層w的形狀是(4,784)、b的形狀是(4,1)。第二層神經元只有一個,來自第一層的輸入只有4個參數,因此第二層w的形狀是(1,4)、b的形狀是(1,1)。

  3)w1和w2是隨機生成的,以前單神經元結構中,w初始值爲0,若是這裏還使用全0的話,最終結果可能與單神經元同樣,並且還乘以0.01確保初始值足夠小。

5、傳播函數

#向前傳播函數
def forward(img, W1,b1,W2,b2):

  #第一層
  A1 = np.dot(W1, img) + b1
  Y1 = np.tanh(A1)#第一層和第二層使用不一樣的激活函數

  #第二層
  A2 = np.dot(W2, Y1) + b2
  Y2 = sigmoid(A2)
  return Y1,Y2

  傳播函數與單神經元結構相似,不過須要注意的是,這裏第一層使用的激活函數爲tanh、第二層依舊使用的是sigmoid。他們的區別在於,sigmoid是將輸出映射到0~1而tanh是將輸出映射到-1~1。具體緣由和區別之後再說(由於我也沒搞清楚呢),這裏只要知道有區別就好了。

 

 6、反向傳播函數

#反向傳播函數
def backward(img, label, W1,b1,W2,b2, Y1,Y2):
  m = img.shape[1]
  #第二層
  dZ2 = Y2 - label
  dW2 = np.dot(dZ2, Y1.T)/m
  db2 = np.sum(dZ2, axis=1, keepdims=True)/m
  #第一層
  dZ1 = np.multiply(np.dot(W2.T, dZ2), 1-np.power(Y1, 2))
  dW1 = np.dot(dZ1, img.T)/m
  db1 = np.sum(dZ1, axis=1, keepdims=True)/m

  return dW1,db1,dW2,db2

  與傳播函數方向相反,這裏是先計算第二層的反向傳播再計算第一層的反向傳播。須要注意的是,因爲第一層使用的激活函數是tanh,因此其反向計算公式與第一層的公式不同,由於使用不一樣激活函數其反向求導也就不同了。

  另外np.sum中的兩個參數axis=一、keepdims=True是爲了確保db1的數據形式爲(1,4),其中axis=1的意思是按行求和、keepdims=True的意思是保留矩陣的形狀,不一樣參數的np.sum計算示意以下:

  np.sum(dZ1)/m                 0.0016664927232987162

  np.sum(dZ1, axis=1)/m            [0.00026393,0.00077922,0.0003274 ,0.00029595]

  np.sum(dZ1, axis=1, keepdims=True)/m   

                        [[0.00026393]
                        [0.00077922]
                        [0.0003274 ]
                        [0.00029595]]

7、梯度降低

#梯度降低 更新w、b參數
def update(W1,b1,W2,b2, dW1,db1,dW2,db2, learning_rate=1.2):
  W1 = W1 - learning_rate*dW1
  b1 = b1 - learning_rate*db1
  W2 = W2 - learning_rate*dW2
  b2 = b2 - learning_rate*db2

  return W1,b1,W2,b2

  梯度降低與單神經元的狀況差很少。

8、損失函數

#損失函數
def costCal(Y2, label):
  m = label.shape[1]
  logprobs = np.multiply(np.log(Y2), label) + np.multiply((1-label), np.log(1-Y2))
  cost = -np.sum(logprobs)/m
  return cost

  損失函數與單神經元的狀況也差很少,須要注意的是np.multiply就是將兩個矩陣作對應元素的乘。

9、預測函數

#預測函數
def predict(W1,b1,W2,b2, img):
  Y1,Y2 = forward(img, W1,b1,W2,b2)
  predictions = np.round(Y2)#對結果四捨五入
  return predictions

  與單神經元的狀況相似,預測函數其實就是作一次「向前傳播」。

10、訓練模型並預測

#訓練模型
def model(img, label, hide_num, num_iterations = 1000, learning_rate=0.1, print_cost = False):
  np.random.seed(3)
  input_num = img.shape[0]
  out_num = label.shape[0]

  #初始化參數
  W1,b1,W2,b2 = initialize_parameters(input_num,hide_num,out_num)
  #循環若干次完成訓練
  for i in range(0, num_iterations):
    #向前傳播
    Y1,Y2 = forward(img, W1,b1,W2,b2)
    #計算本次成本
    cost = costCal(Y2, label)
    #反向傳播,獲得梯度
    dW1,db1,dW2,db2 = backward(img, label, W1,b1,W2,b2, Y1,Y2)
    #參數優化
    W1,b1,W2,b2 = update(W1,b1,W2,b2, dW1,db1,dW2,db2, learning_rate)
    # 將本次訓練的成本打印出來
    if print_cost and i % 100 == 0:
    print ("在訓練%i次後,成本是: %f" % (i, cost))

  return W1,b1,W2,b2

#調用訓練模型

W1,b1,W2,b2 = model(train_img, train_label, 4, num_iterations=2000, learning_rate=1, print_cost=True)

#調用預測函數

predictions = predict(W1,b1,W2,b2, test_img)
print ('預測準確率是: %d' % float((np.dot(test_label, predictions.T) + np.dot(1 - test_label, 1 - predictions.T)) / float(test_label.size) * 100) + '%')

  須要注意的是這裏的learning_rate=1,而單神經元時的learning_rate爲0.005。

11、總結回顧

  經過實現一個簡單的二層神經網絡咱們發現,其實代碼並無修改不少,總體的結構也變化不大,其中最主要的變化在於第一層使用的激活函數變爲tanh,由此致使反向傳播的計算也有了較大的變化。

  運行後咱們能夠發現,預測的準確度較單神經元有了較大幅度的提高:

在訓練0次後,成本是: 0.693817
在訓練100次後,成本是: 0.251725
在訓練200次後,成本是: 0.176756
在訓練300次後,成本是: 0.110538
在訓練400次後,成本是: 0.372297
在訓練500次後,成本是: 0.128188
在訓練600次後,成本是: 0.091792
在訓練700次後,成本是: 0.075769
在訓練800次後,成本是: 0.064764
在訓練900次後,成本是: 0.055826
在訓練1000次後,成本是: 0.132452
在訓練1100次後,成本是: 0.102556
在訓練1200次後,成本是: 0.131425
在訓練1300次後,成本是: 0.086445
在訓練1400次後,成本是: 0.178343
在訓練1500次後,成本是: 0.077496
在訓練1600次後,成本是: 0.093846
在訓練1700次後,成本是: 0.071567
在訓練1800次後,成本是: 0.070109
在訓練1900次後,成本是: 0.060202
預測準確率是: 94%

  關注公衆號「零基礎愛學習」回覆"AI5"可得到完整代碼。後面咱們還會繼續更新「如何構建深度神經網絡」,以及對目前還未明晰的問題解析。

相關文章
相關標籤/搜索