尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️
摘要:手把手教你用(Python)零起步數學+神經網路入門!
在這篇文章中,我們將在Python中從頭開始了解用於構建具有各種層神經網路(完全連接,卷積等)的小型庫中的機器學習和代碼。最終,我們將能夠寫出如下內容:
假設你對神經網路已經有一定的了解,這篇文章的目的不是解釋為什麼構建這些模型,而是要說明如何正確做到。
逐層
我們這里需要牢記整個框架:
1.將數據輸入神經網路
2.在得出輸出之前,數據從一層流向下一層
3.一旦得到輸出,就可以計算出一個標量誤差。
4.最後,可以通過相對於參數本身減去誤差的導數來調整給定參數(權重或偏差)。
5.遍歷整個過程。
最重要的一步是第四步。 我們希望能夠擁有任意數量的層,以及任何類型的層。 但是如果修改/添加/刪除網路中的一個層,網路的輸出將會改變,誤差也將改變,誤差相對於參數的導數也將改變。無論網路架構如何、激活函數如何、損失如何,都必須要能夠計算導數。
為了做到這一點,我們必須分別做到每一層。
每個層應該做到什麼
我們可能構建的每一層(完全連接,卷積,最大化,丟失等)至少有兩個共同點:輸入和輸出數據。
現在重要的一部分
假設給出一個層相對於其輸出(∂E/∂Y)誤差的導數,那麼它必須能夠提供相對於其輸入(∂E/∂X)誤差的導數。
我們可以使用鏈規則輕鬆計算∂E/∂X的元素:
為什麼是∂E/∂X?
對於每一層,我們需要相對於其輸入的誤差導數,因為它將是相對於前一層輸出的誤差導數。這非常重要,這是理解反向傳播的關鍵!在這之後,我們將能夠立即從頭開始編寫深度卷積神經網路!
花樣圖解
基本上,對於前向傳播,我們將輸入數據提供給第一層,然後每層的輸出成為下一層的輸入,直到到達網路的末端。
對於反向傳播,我們只是簡單使用鏈規則來獲得需要的導數。這就是為什麼每一層必須提供其輸出相對於其輸入的導數。
這可能看起來很抽象,但是當我們將其應用於特定類型的層時,它將變得非常清楚。現在是編寫第一個python類的好時機。
抽象基類:Layer
所有其它層將繼承的抽象類Layer會處理簡單屬性,這些屬性是輸入,輸出以及前向和反向方法。
正如你所看到的,在back_propagation函數中,有一個我沒有提到的參數,它是learning_rate。 此參數應該類似於更新策略或者在Keras中調用它的優化器,為了簡單起見,我們只是通過學習率並使用梯度下降更新我們的參數。
全連接層
現在先定義並做到第一種類型的網路層:全連接層或FC層。FC層是最基本的網路層,因為每個輸入神經元都連接到每個輸出神經元。
前向傳播
每個輸出神經元的值由下式計算:
使用矩陣,可以使用點積來計算每一個輸出神經元的值:
當完成前向傳播之後,現在開始做反向傳播。
反向傳播
正如我們所說,假設我們有一個矩陣,其中包含與該層輸出相關的誤差導數(∂E/∂Y)。 我們需要 :
1.關於參數的誤差導數(∂E/∂W,∂E/∂B)
2.關於輸入的誤差導數(∂E/∂X)
首先計算∂E/∂W,該矩陣應與W本身的大小相同:對於ixj,其中i是輸入神經元的數量,j是輸出神經元的數量。每個權重都需要一個梯度:
使用前面提到的鏈規則,可以寫出:
那麼:
這就是更新權重的第一個公式!現在開始計算∂E/∂B:
同樣,∂E/∂B需要與B本身具有相同的大小,每個偏差一個梯度。 我們可以再次使用鏈規則:
得出結論:
現在已經得到∂E/∂W和∂E/∂B,我們留下∂E/∂X這是非常重要的,因為它將「作用」為之前層的∂E/∂Y。
再次使用鏈規則:
最後,我們可以寫出整個矩陣:
編碼全連接層
現在我們可以用Python編寫做到:
激活層
到目前為止所做的計算都完全是線性的。用這種模型學習是沒有希望的,需要通過將非線性函數應用於某些層的輸出來為模型添加非線性。
現在我們需要為這種新類型的層(激活層)重做整個過程!
不用擔心,因為此時沒有可學習的參數,過程會快點,只需要計算∂E/∂X。
前向傳播
正如將看到的,它非常簡單。對於給定的輸入X,輸出是關於每個X元素的激活函數,這意味著輸入和輸出具有相同的大小。
反向傳播
給出∂E/∂Y,需要計算∂E/∂X
注意,這里我們使用兩個矩陣之間的每個元素乘法(而在上面的公式中,它是一個點積)
編碼做到激活層
激活層的代碼非常簡單:
可以在單獨的文件中編寫一些激活函數以及它們的導數,稍後將使用它們構建ActivationLayer:
損失函數
到目前為止,對於給定的層,我們假設給出了∂E/∂Y(由下一層給出)。但是最後一層怎麼得到∂E/∂Y?我們通過簡單地手動給出最後一層的∂E/∂Y,它取決於我們如何定義誤差。
網路的誤差由自己定義,該誤差衡量網路對給定輸入數據的好壞程度。有許多方法可以定義誤差,其中一種最常見的叫做MSE – Mean Squared Error:
其中y *和y分別表示期望的輸出和實際輸出。你可以將損失視為最後一層,它將所有輸出神經元吸收並將它們壓成一個神經元。與其他每一層一樣,需要定義∂E/∂Y。除了現在,我們終於得到E!
以下是兩個python函數,可以將它們放在一個單獨的文件中,將在構建網路時使用。
網路類
到現在幾乎完成了!我們將構建一個Network類來創建神經網路,非常容易,類似於第一張圖片!
我註釋了代碼的每一部分,如果你掌握了前面的步驟,那麼理解它應該不會太複雜。
構建一個神經網路
最後!我們可以使用我們的類來創建一個包含任意數量層的神經網路!為了簡單起見,我將向你展示如何構建……一個XOR。
同樣,我認為不需要強調很多事情,只需要仔細訓練數據,應該能夠先獲得樣本維度。例如,對於xor問題,樣式應為(4,1,2)。
結果
卷積層
這篇文章開始很長,所以我不會描述做到卷積層的所有步驟。但是,這是我做的一個做到:
它背後的數學實際上並不複雜!這是一篇很好的文章,你可以找到∂E/∂W,∂E/∂B和∂E/∂X的解釋和計算。
如果你想驗證你的理解是否正確,請嘗試自己做到一些網路層,如MaxPooling,Flatten或Dropout
GitHub庫
https://github.com/OmarAflak/Medium-Python-Neural-Network
你可以在GitHub庫中找到用於該文章的完整代碼。
本文由阿里雲雲棲社區組織翻譯。
文章原標題《math-neural-network-from-scratch-in-python》
作者:Omar Aflak譯者:虎說八道,審校:袁虎。
end
Alibaba Cluster Data 開源:270GB 數據揭秘你不知道的阿里巴巴數據中心
如何去設計前端框架能力?星巴克消息開放項目從0到1,從點到面的思考
更多精彩