這是一份用于理解深度學(xué)習(xí)內(nèi)部運(yùn)作方式的初學(xué)者指南。作者根據(jù)自己從零開始學(xué)習(xí)用 Python 構(gòu)建神經(jīng)網(wǎng)絡(luò)的經(jīng)驗,編寫了一份攻略。內(nèi)容涵蓋神經(jīng)網(wǎng)絡(luò)定義、損失函數(shù)、前向傳播、反向傳播、梯度下降算法,對于想要了解深度學(xué)習(xí)運(yùn)作原理的各位來說,內(nèi)容精彩不可錯過。
動機(jī):為了深入了解深度學(xué)習(xí),我決定從零開始構(gòu)建神經(jīng)網(wǎng)絡(luò),并且不使用類似 Tensorflow 的深度學(xué)習(xí)庫。我相信,對于任何有理想的數(shù)據(jù)科學(xué)家而言,理解神經(jīng)網(wǎng)絡(luò)內(nèi)部的運(yùn)作方式都非常重要。
本文涵蓋了我學(xué)到的所有東西,希望你也能從中獲益!
什么是神經(jīng)網(wǎng)絡(luò)?
許多有關(guān)神經(jīng)網(wǎng)絡(luò)的介紹資料會將神經(jīng)網(wǎng)絡(luò)與大腦進(jìn)行類比。但我發(fā)現(xiàn),將神經(jīng)網(wǎng)絡(luò)簡單地描述為一個從輸入映射到輸出的數(shù)學(xué)函數(shù)理解起來更容易。
神經(jīng)網(wǎng)絡(luò)由以下部分組成:
一個輸入層,x
任意數(shù)量的隱藏層
一個輸出層,?
每兩層之間都有一組權(quán)重和偏置,W 和 b
每個隱藏層都要選擇一個激活函數(shù) σ。在本文中,我們選用 Sigmoid 激活函數(shù)。
下圖展示了 2 層神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)(請注意,在計算神經(jīng)網(wǎng)絡(luò)層數(shù)的時候,通常不計入輸入層)。

二層神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)
利用 Python 建立神經(jīng)網(wǎng)絡(luò)非常容易。
class NeuralNetwork: def __init__(self, x, y): self.input = x self.weights1 = np.random.rand(self.input.shape[1],4) self.weights2 = np.random.rand(4,1) self.y = y self.output = np.zeros(y.shape)
訓(xùn)練神經(jīng)網(wǎng)絡(luò)
一個簡單 2 層神經(jīng)網(wǎng)絡(luò)的輸出 ? 可以表示為:

你可能注意到,在上面的等式當(dāng)中,權(quán)重 W 和偏置 b 是影響輸出 ? 的唯一變量。
自然,權(quán)重和偏差的正確值決定了預(yù)測的強(qiáng)度。根據(jù)輸入數(shù)據(jù)微調(diào)權(quán)重和偏置的過程稱為神經(jīng)網(wǎng)絡(luò)訓(xùn)練。
訓(xùn)練過程的每一次迭代包含以下步驟:
計算預(yù)測的輸出 ?,稱為前向傳播
更新權(quán)重和偏置,稱為反向傳播
以下流程圖說明了這個過程:

前向傳播
正如我們在上圖中所看到的,前向傳播只是一個簡單的計算。對于一個基本的 2 層神經(jīng)網(wǎng)絡(luò),神經(jīng)網(wǎng)絡(luò)的輸出計算如下:

我們可以在 Python 代碼中添加一個前向傳播函數(shù)來做到這一點。簡單起見,我們假設(shè)偏置為 0。
class NeuralNetwork: def __init__(self, x, y): self.input = x self.weights1 = np.random.rand(self.input.shape[1],4) self.weights2 = np.random.rand(4,1) self.y = y self.output = np.zeros(self.y.shape) def feedforward(self): self.layer1 = sigmoid(np.dot(self.input, self.weights1)) self.output = sigmoid(np.dot(self.layer1, self.weights2))
然而,我們?nèi)匀恍枰环N方法來評估我們的預(yù)測的「優(yōu)秀程度」(即,我們的預(yù)測與真實值相差多少?)這就需要用到損失函數(shù)了。
損失函數(shù)
損失函數(shù)有很多種,而我們問題的性質(zhì)會決定我們使用哪種損失函數(shù)。在本文中,我們將采用簡單的誤差平方和。

誤差平方和,即每個預(yù)測值和真實值之間差值的平均值。這個差值是取了平方項的,所以我們測量的是差值的絕對值。
在訓(xùn)練過程中,我們的目標(biāo)是找到一組最佳的權(quán)重和偏置,使損失函數(shù)最小化。
反向傳播
現(xiàn)在,我們已經(jīng)找到了預(yù)測誤差的方法(損失函數(shù)),那么我們需要一種方法將錯誤「傳播」回去,從而更新權(quán)重和偏置。
為了確定權(quán)重和偏置調(diào)整的適當(dāng)值,我們需要知道損失函數(shù)對權(quán)重和偏置的偏導(dǎo)數(shù)。
從微積分的角度來看,函數(shù)的偏導(dǎo)數(shù)也就是函數(shù)的斜率。

梯度下降算法
如果我們知道了偏導(dǎo)數(shù),我們可以通過簡單增加或減少偏導(dǎo)數(shù)(如上圖所示)的方式來更新權(quán)重和偏置。這就是所謂的梯度下降。
然而,由于損失函數(shù)的方程不包含權(quán)重和偏置,所以我們不能直接計算損失函數(shù)對權(quán)重和偏置的偏導(dǎo)數(shù)。因此,我們需要鏈?zhǔn)椒▌t來幫助計算。

以上是用于計算損失函數(shù)對權(quán)重偏導(dǎo)數(shù)的鏈?zhǔn)椒▌t。簡單起見,我們只展示了一層神經(jīng)網(wǎng)絡(luò)的偏導(dǎo)數(shù)。
唷!這看起來不大好看,但這能讓我們獲得所需——損失函數(shù)對權(quán)重的偏導(dǎo)數(shù)(斜率),以便相應(yīng)調(diào)整權(quán)重。
既然我們已經(jīng)有了鏈?zhǔn)椒▌t公式,接下來我們把反向傳播函數(shù)添加到 Python 代碼中。
class NeuralNetwork: def __init__(self, x, y): self.input = x self.weights1 = np.random.rand(self.input.shape[1],4) self.weights2 = np.random.rand(4,1) self.y = y self.output = np.zeros(self.y.shape) def feedforward(self): self.layer1 = sigmoid(np.dot(self.input, self.weights1)) self.output = sigmoid(np.dot(self.layer1, self.weights2)) def backprop(self): # application of the chain rule to find derivative of the loss function with respect to weights2 and weights1 d_weights2 = np.dot(self.layer1.T, (2*(self.y - self.output) * sigmoid_derivative(self.output))) d_weights1 = np.dot(self.input.T, (np.dot(2*(self.y - self.output) * sigmoid_derivative(self.output), self.weights2.T) * sigmoid_derivative(self.layer1))) # update the weights with the derivative (slope) of the loss function self.weights1 += d_weights1 self.weights2 += d_weights2
整合
既然我們已經(jīng)有了做前向傳播和反向傳播的完整 Python 代碼,我們可以將神經(jīng)網(wǎng)絡(luò)應(yīng)用到一個示例中,看看它的效果。

我們的神經(jīng)網(wǎng)絡(luò)應(yīng)該能夠習(xí)得理想的權(quán)重集合以表示這個函數(shù)。請注意,對于我們來說,僅通過檢查來計算權(quán)重并非一件小事。
如果我們將神經(jīng)網(wǎng)絡(luò)進(jìn)行 1500 次迭代,看看會發(fā)生什么。下圖展示了每次迭代的損失函數(shù)值,我們可以清晰地發(fā)現(xiàn)損失函數(shù)單調(diào)下降到最小值。這與我們前面討論的梯度下降算法是一致的。

讓我們看看神經(jīng)網(wǎng)絡(luò)在進(jìn)行 1500 次迭代后的最終預(yù)測(輸出):

進(jìn)行 1500 次迭代后的預(yù)測值
我們成功了!我們的前向傳播和反向傳播算法成功訓(xùn)練了神經(jīng)網(wǎng)絡(luò),且預(yù)測值收斂到了真實值。
請注意,預(yù)測值和真實值之間還是有一些輕微差異的。這是可取的,因為它防止了過度擬合,并且使得神經(jīng)網(wǎng)絡(luò)具有更強(qiáng)的泛化能力。
下一步
幸運(yùn)的是,我們的探索還沒有結(jié)束。關(guān)于神經(jīng)網(wǎng)絡(luò)和深度學(xué)習(xí)還有很多需要學(xué)習(xí)的地方。例如:
除了 Sigmoid 函數(shù)之外,我們還可以使用哪些激活函數(shù)?
在訓(xùn)練神經(jīng)網(wǎng)絡(luò)時使用學(xué)習(xí)率
使用卷積進(jìn)行圖像分類任務(wù)
最后一點想法
在撰寫此文的過程中,我已經(jīng)學(xué)到了很多,希望本文也能對你有所幫助。
在沒有完全了解神經(jīng)網(wǎng)絡(luò)內(nèi)部工作原理的情況下,雖然使用諸如 TensorFlow 和 Keras 之類的深度學(xué)習(xí)庫可以讓我們很容易地建立深度網(wǎng)絡(luò),但我認(rèn)為對于有抱負(fù)的數(shù)據(jù)科學(xué)家而言,深入理解神經(jīng)網(wǎng)絡(luò)還是大有裨益的。
-
python
+關(guān)注
關(guān)注
58文章
4877瀏覽量
90126 -
深度學(xué)習(xí)
+關(guān)注
關(guān)注
73文章
5599瀏覽量
124448
原文標(biāo)題:無需深度學(xué)習(xí)框架,如何從零開始用Python構(gòu)建神經(jīng)網(wǎng)絡(luò)
文章出處:【微信號:gh_ecbcc3b6eabf,微信公眾號:人工智能和機(jī)器人研究院】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
神經(jīng)網(wǎng)絡(luò)的初步認(rèn)識
京東拍立淘API開發(fā)指南:從零開始構(gòu)建圖像搜索應(yīng)用
CNN卷積神經(jīng)網(wǎng)絡(luò)設(shè)計原理及在MCU200T上仿真測試
NMSIS神經(jīng)網(wǎng)絡(luò)庫使用介紹
構(gòu)建CNN網(wǎng)絡(luò)模型并優(yōu)化的一般化建議
從零開始利用NMSIS庫搭建神經(jīng)網(wǎng)絡(luò)(一)
在Ubuntu20.04系統(tǒng)中訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型的一些經(jīng)驗
液態(tài)神經(jīng)網(wǎng)絡(luò)(LNN):時間連續(xù)性與動態(tài)適應(yīng)性的神經(jīng)網(wǎng)絡(luò)
神經(jīng)網(wǎng)絡(luò)的并行計算與加速技術(shù)
如何在機(jī)器視覺中部署深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)
無刷電機(jī)小波神經(jīng)網(wǎng)絡(luò)轉(zhuǎn)子位置檢測方法的研究
低功耗+AI識別:基于樹莓派的 LoRa 神經(jīng)網(wǎng)絡(luò)安防系統(tǒng)!
神經(jīng)網(wǎng)絡(luò)專家系統(tǒng)在電機(jī)故障診斷中的應(yīng)用
基于FPGA搭建神經(jīng)網(wǎng)絡(luò)的步驟解析
從零開始學(xué)習(xí)用Python構(gòu)建神經(jīng)網(wǎng)絡(luò)
評論