學一招 教你用 Python 從零搭建神經網路

2021-09-11 12:44:39 字數 3208 閱讀 3966

原創: james loy 優達學城udacity

文/ james loy

翻譯/ kevin

眾所周知,我們有許多著名的深度學習庫,如 tensorflow。so,為什麼還需要自己重複造輪子,用原生 python 來搭神經網路呢?因為我的個人學習經驗表明,通過親手來搭建乙個神經網路,能更好地理解神經網路的的運算原理,這對有志成為資料科學家的小夥伴而言非常重要。

本文是個人學習的心得體會,希望也對各位讀者有所啟發。

許多介紹神經網路的文章都喜歡把它模擬成大腦神經元。但我發現,把神經網路理解為乙個把輸入向量對映成輸出向量的函式更易於初學者理解。

乙個神經網路包含了以下元素:

下圖是乙個2層深度的神經網路(注意在計算神經網路層數時,通常不包括輸入層):

用原生的python來模擬這個神經網路其實很簡單:

import numpy as npclass 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)複製**
對於以上這個簡單的2層神經網路,它的輸出層 $\hat y$ 可以表示為: $$\hat y = \sigma (w2 \sigma (w1x + b1) + b2)$$

也許你已經留意到,在以上等式中,權重 $w$ 與 偏移量 $b$ ,是影響輸出層 $\hat y$ 的唯二因素。

因此,等式右邊的權重與偏移量,決定了估算值 $\hat y$ 的準確度。而通過微調權重與偏移量、使得估算值越來越準確的過程,稱為訓練神經網路

每個迭代的訓練過程都包含了以下步驟:

以下流程圖展示了前向傳播與反向傳播的全過程:

正如上圖所示,所謂的前向傳播,實質上就是在進行兩次啟用函式代入計算的過程:$$\hat y = \sigma (w2 \sigma (w1x + b1) + b2)$$ 讓我們把這個前向傳播的計算加入之前的python**。注意,為了簡化問題,我們假設所有的偏移量都等於零。

import numpy as npclass 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))複製**
然而,我們還需要乙個衡量估算值的準確度的指標(比如可以量化估算值與真實值之間的差距大小)。

這時,損失函式(loss function)就是我們想要的指標。

事實上,損失函式可以有很多種計算方式。而具體使用哪一種,則視具體的問題而定。在本例的問題,我們會使用方差作為我們的損失函式:$$mean square error = \frac \sum_^n$$ 方差就是指所有的估算值與真實值的偏差的平方和均值。對偏差取平方,使我們無需考慮符號(偏差方向)問題。需要說明的是,該公式有時候為了簡化計算,可以把其中的常部分 $\frac$ 替換為任意常數值。

我們的目標是,訓練網路、找到使損失函式的值最小的那組權重與偏移量。

現在我們已經有方法衡量估算值的偏差,那麼我們只需要找到乙個方法來把這些誤差傳播回去,從而可以更新我們的權重與偏移量。

為了得到合適的權重與偏移量的更新值,我們需要求得損失函式對於權重與偏移量的偏導數。

回顧微積分可知,乙個函式的導數可以看作是該函式曲線上某個點的斜率。

梯度下降演算法(圖例說明)

如果我們獲得了損失函式某個點的導數,我們就能用它來增加/減少原有的權重及偏移量(參考上圖)。這就是梯度下降。

然而,我們無法直接算出損失函式對於權重與偏移量的偏導數。因為在等式中沒有包括權重與偏移量。於是,我們需要用到鏈式法則來輔助計算。

看公式看得有點頭大是吧。不想看推導過程的小夥伴只需要看公式最後一行就可以,這就是損失函式對於權重的偏導數(別忘了,我們之前假設了偏移量為零,所以暫且忽略它),有了這個函式梯度,我們就能更新權重了。

現在,我們把反向傳播函式也加到我們的神經網路**中去:

複製**

現在我們有了前向傳播與反向傳播的全部**,讓我們試試用它來解決一些實際問題,看看效果如何吧。

上圖是乙個從三維向量x到一維向量y的對映。我們的神經網路理論上應該能夠學習一組理想的權重來表達這個對映函式。

我們把神經網路訓練1500個迭代,看看會發生什麼。我們可以從下面的訓練圖表可以看到,誤差隨著訓練的迭代數增加而呈單調遞減的趨勢,最終會收斂在某個最小值。這與我們前面提到的梯度下降演算法是一致的。

我們再來看看經過1500個迭代訓練後,神經網路的**結果:

成功了!通過正向傳播與反向傳播演算法,我們成功地訓練了神經網路並且使預估值收斂於真實值附近。

需要注意的是,我們看到預估值與真實值之間有一定的差距,這是符合期望的。因為這樣能避免過擬合,可以使神經網路能更好地泛化於一些沒見過的資料樣本。

儘管我們已經用python搭建出了乙個神經網路,並且成功訓練它使其能得出乙個非常接近真實值的對映結果。但對於入門神經網路與深度學習領域,我們還有許多需要去研究的細節。例如:

在以上這個「重新造輪子」的過程中,我從中更深刻地了解了神經網路的運算原理。儘管坊間有許多現成的深度學習庫,比如tensorflow、keras等,使神經網路的搭建與計算更容易更高效,即便你對神經網路的內部原理不是太清楚也能無礙於使用;但我發現對於有志成為資料科學家的小夥伴而言,更深入地了解神經網路的內部原理是相當有幫助的。

以上這個小實踐對我而言是相當受益的,希望對各位也有所啟發吧!

從零教你用vue cli建立專案

安裝 vue cli npm install vue cli g安裝在全域性比較方便 install 可以簡寫為 i vue cli 安裝好之後就能使用vue 命令 建立專案 vue init webpack my vue 是 vue cli 的命令 webpack 是一種模板,my 就是所建立的專...

教你一招用 IDE 程式設計提公升效率的騷操作!

idea 有個很牛逼的功能,那就是字尾補全 不是自動補全 很多人竟然不知道這個操作,還在手動敲 這個功能可以使用 補全來模板式地補全語句,如遍歷迴圈語句 for foreach 使用 string.format 包裹乙個字串 使用型別轉化包裹乙個表示式 根據判 非 空或者其它判別語句生成 if 語句...

教你用Python畫了一棵聖誕樹

如何用python畫乙個聖誕樹呢?最簡單 height 5 stars 1for i in range height print height i stars stars 2 print height 效果 哈哈哈哈,總有一種騙了大家的感覺。其實本文是想介紹turtle庫來畫聖誕樹。import t...