神經網絡反向傳播梯度計算數學原理

[神經網絡]反向傳播梯度計算數學原理

1 文章概述

本文經過一段來自於Pytorch官方的warm-up的例子:使用numpy來實現一個簡單的神經網絡。使用基本的數學原理,對其計算過程進行理論推導,以揭示這幾句神奇的代碼後面所包含的原理。html

估計對大多數的同窗來講,看完這個文章,確定會是這樣的感受:字都認識,可是就是不知道講的是啥~!不過對於有心人來講,本文確實能起到點睛之筆,就是你研究好久後,還差一點火候就頓悟了,但願本文可以幫你頓悟。python

關鍵字:Numpy,神經網絡,矩陣分析,反射傳播,梯度降低算法

 

若是發現圖片裂了,請左轉至 其它平臺查看:網絡

https://zhuanlan.zhihu.com/p/32368246框架

 

2 實現代碼

numpy做爲一個科學計算庫,並不包含:計算圖,嘗試學習,梯度等等功能,可是咱們能夠簡單的經過numpy去擬合一個二層的網絡。dom

解決的問題:函數

  1. 隨機生成一組輸入數據,一組輸出數據。
  2. 定義一個神經網絡結構及其參數
  3. 根據輸入數據正向傳播,求出偏差
  4. 根據偏差反向傳播梯度,更新神經元的各個節點的參數

代碼以下:工具

# -*- coding: utf-8 -*-
import numpy as np

# N is batch size; D_in is input dimension;
# H is hidden dimension; D_out is output dimension.
N, D_in, H, D_out = 64, 1000, 100, 10

# Create random input and output data
x = np.random.randn(N, D_in)
y = np.random.randn(N, D_out)

# Randomly initialize weights
w1 = np.random.randn(D_in, H)
w2 = np.random.randn(H, D_out)

learning_rate = 1e-6
for t in range(500):
    # Forward pass: compute predicted y
    h = x.dot(w1)
    h_relu = np.maximum(h, 0)
    y_pred = h_relu.dot(w2)

    # Compute and print loss
    loss = np.square(y_pred - y).sum()
    print(t, loss)

    # Backprop to compute gradients of w1 and w2 with respect to loss
    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_relu.T.dot(grad_y_pred)
    grad_h_relu = grad_y_pred.dot(w2.T)
    grad_h = grad_h_relu.copy()
    grad_h[h < 0] = 0
    grad_w1 = x.T.dot(grad_h)

    # Update weights
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2
 

原文見:Learning PyTorch with Examples學習

 

3 網絡結構

將上面的代碼結構及相應的參數維度繪圖後以下所示:優化

而後本代碼使用的是一個大小爲64的batch,因此輸入的值實際的大小其實是(64,1000)。

把以上的代碼轉化成數學公式以下,括號裏面是相應的矩陣的形狀:

 

4 正向計算

數據流的正向傳播

最後計算出損失函數loss,是實際預測值和先驗數據矩陣的二範數,做爲兩組矩陣的距離測度。

正向傳播比較簡單,基本上大學的線性代數的基本知識看幾章,就能很好的理解。這也是後續若是在深度學習框架下面設計網絡的時候,注意設計神經元大小的時候,須要考慮矩陣乘法的可行性,即維度相容。

PS:關於矩陣的範數的定義,詳情見P32的《1.4.3矩陣的內積和範數》

5 反向傳播

 

5.1 實現代碼

 

下面是反射傳播的代碼實現:

 

5.2 數學基礎

 

關於反射傳播的數學原理,可能就不是那麼好理解了,由於這裏面須要用到矩陣的高級算法,通常的理工科數學的《線性代數》甚至《高等代數》裏面都沒有提到相關的內容,因此基本上已經超過了大多數高校學生的知識範圍了。在這個時候,就要祭出張賢達的《矩陣分析》了。

最開始我把本身大學時候的數學書《數學分析》,《高等代數》,《數值計算》都翻了一遍,可是都沒有找到相關的內容。感受對於矩陣的微分是一個「三無論」的地帶,可是這個內容又是深度學習神經網絡中用得最多的數學原理。而後到網上發現了《矩陣分析與應用》,想一想這麼厚的一本像百科全書的書,應該是無所不包吧,果真在裏面找到了想要的內容。

固然在看書以前,也看了無數的網絡文章,相對比較有價值的就下面兩篇:

《矩陣求導-上》

《矩陣求導-下》

 

固然,像數學工具這種內容,建議你們仍是去看書,由於書做爲幾十年的經典教材,其推導過程,內容的完整性,認證的嚴密性都是經得起推敲的。網絡文章只能幫你們啓蒙一下,學幾個術語,可是具體想深刻了解細節,建議仍是看書。

 

言歸正傳。

 

上述的不到10行的反向傳播梯度,更新參數的代碼,在外行人看來是比較神來之筆,徹底摸不着頭腦,這是很正常的。由於要理解上述的代碼,須要預先儲備以下知識(《矩陣分析與應用》):

  1. 矩陣的基本運算。頁面P4,章節編號1.1.2
  2. 矩陣的內積與範數。P32, 1.4.3
  3. 矩陣的跡。P49, 1.6.4
  4. 向量化和矩陣化。 P74, 1.11
  5. Jacobian矩陣和梯度矩陣。 P143, 3.1
  6. 一階實矩陣微分與Jacobian矩陣辨識。 P152, 3.2

 

注意事項:函數有不一樣的分類,因此請你們不要全用《線性代數》裏面變元全爲實數標量的眼光來看待矩陣的變元和矩陣函數的運算。由於它們是不一樣的,即便你勉強獲得符合代碼的結論,那極可能也是「瞎貓碰到死耗子」。關於函數的微分的討論,光實值函數的分類,就能夠分以下幾類(P143, 3.1):

矩陣和Jacobian矩陣在實值區間內是互爲轉置。在進行數學推導時,都是先根據Jacobian矩陣的辨識方法求出Jacobian矩陣,而後轉置後就是相應的梯度。

 

當定義一個標量函數關於變量的偏導數時:

Jacobian矩陣和梯度矩陣是關於偏導的不一樣定義方式,分別是行向量偏導和列向量偏導。只是Jacobian矩陣是一種研究思惟上更天然的選擇,可是梯度向量倒是優化和實際工程計算時更天然的選擇。

 

5.3 預測值梯度

 

grad_y_pred = 2.0 * (y_pred - y)

 

下面是推導過程,紅色筆跡是推導過程的依據,請查閱《矩陣分析與應用》

接着前面的公式,繼續求微分:

 

5.4 參數W2梯度

grad_w2 = h_relu.T.dot(grad_y_pred)

5.5 參數H_relu 梯度

grad_h_relu = grad_y_pred.dot(w2.T)

 

5.6 Relu梯度

 

grad_h = grad_h_relu.copy()

grad_h[h < 0] = 0

grad_w1 = x.T.dot(grad_h)

  

 

5.7 參數W1梯度

 

而後後面就是使用梯度和學習率去批量更新參數,實現整個訓練過程了。

 

6 參考資料

《矩陣分析與應用》(第2版) 張賢達 著,清華大學出版社,2011-11,第2版

本文中全部的引用註解,頁面標識都來自於本書。

相關文章
相關標籤/搜索