毫不是心血來潮:嘗試用python本身寫一個神經網絡

首先,神經網絡是什麼?人腦由幾千億由突觸相互鏈接的細胞(神經元)組成。突觸傳入足夠的興奮就會引發神經元的興奮。這個過程被稱爲「思考」。python

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

咱們能夠在計算機上寫一個神經網絡來模擬這個過程。不須要在生物分子水平模擬人腦,只需模擬更高層級的規則。咱們使用矩陣(二維數據表格)這一數學工具,而且爲了簡單明瞭,只模擬一個有3個輸入和一個輸出的神經元。網絡

咱們將訓練神經元解決下面的問題。前四個例子被稱做訓練集。你可能發現了,輸出老是等於輸入中最左列的值。因此‘?’應該是1。app

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

訓練過程

可是如何使咱們的神經元回答正確呢?賦予每一個輸入一個權重,能夠是一個正的或負的數字。擁有較大正(或負)權重的輸入將決定神經元的輸出。首先設置每一個權重的初始值爲一個隨機數字,而後開始訓練過程:dom

  1. 取一個訓練樣本的輸入,使用權重調整它們,經過一個特殊的公式計算神經元的輸出。
  2. 計算偏差,即神經元的輸出與訓練樣本中的期待輸出之間的差值。
  3. 根據偏差略微地調整權重。
  4. 重複這個過程10萬次。

 

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

最終權重將會變爲符合訓練集的一個最優解。若是使用神經元考慮這種規律的一個新情形,它將會給出一個很棒的預測。函數

這個過程就是BP。工具

計算神經元輸出的公式

你可能會想,計算神經元輸出的公式是什麼?首先,計算神經元輸入的加權和,即測試

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

接着使之規範化,結果在0,1之間。爲此使用一個數學函數--Sigmoid函數:spa

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

Sigmoid函數的圖形是一條「S」狀的曲線。3d

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

把第一個方程代入第二個,計算神經元輸出的最終公式爲:code

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

調整權重的公式

咱們在訓練時不斷調整權重。可是怎麼調整呢?可使用「Error Weighted Derivative」公式:

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

爲何使用這個公式?首先,咱們想使調整和偏差的大小成比例。其次,乘以輸入(0或1),若是輸入是0,權重就不會調整。最後,乘以Sigmoid曲線的斜率(圖4)。

Sigmoid曲線的斜率能夠經過求導獲得:

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

把第二個等式代入第一個等式裏,獲得調整權重的最終公式:

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

構造Python代碼

雖然咱們沒有使用神經網絡庫,可是將導入Python數學庫numpy裏的4個方法。分別是:

  • exp--天然指數
  • array--建立矩陣
  • dot--進行矩陣乘法
  • random--產生隨機數

 

「.T」方法用於矩陣轉置(行變列)。因此,計算機這樣存儲數字:

用9行Python代碼編寫一個簡易神經網絡?你敢信?看起來超簡單

 

我對每一行源代碼都添加了註釋來解釋全部內容。注意在每次迭代時,咱們同時處理全部訓練集數據。因此變量都是矩陣(二維數據表格)。下面是一個用Python寫地完整的示例代碼。

#numpy導入天然指數,建立矩陣,產生隨機數,矩陣乘法的方法 from numpy import exp,array,random,dot class NeuralNetwork(object):     def __init__(self):         #指定隨機數發生器種子,保證每次得到相同結果的隨機數         random.seed(1)         #對含有3個輸入一個輸出的單個神經元建模         #即3*1矩陣(樹突)賦予隨機權重值。範圍(-1,1)         #即(a,b)範圍的c*d矩陣隨機數爲(b-a)*random.random((c,d))+a         self.dendritic_weights = 2*random.random((3,1))-1     #Sigmoid函數,s形曲線,用於對輸入的加權總和x作(0,1)正規化     #它能夠將一個實數映射到(0,1)的區間     def __sigmoid(self,x):         return 1/(1+exp(-x))     #Sigmoid函數的導數(梯度)(當前權重的置信程度,越小表明越可信)     #這裏的x指的是1/(1+exp(-x)),即output輸出     def __sigmoid_derivative(self,x):         return x*(1-x)     #訓練該神經網絡,並調整樹突的權重     def train(self,training_inputs,training_outputs,number_of_training_iterations):         '''         training_inputs:訓練集樣本的輸入         training_outputs:訓練集樣本的輸出         number_of_training_iterations:訓練次數         1.咱們使用Sigmoid曲線計算(輸入的加權和映射到0至1之間)做爲神經元的輸出         2.若是輸出是一個大的正(或負)數,這意味着神經元採用這種(或另外一種)方式,         3.從Sigmoid曲線能夠看出,在較大數值處,Sigmoid曲線斜率(導數)小,即認爲當前權重是正確的,就不會對它進行很大調整。         4.因此,乘以Sigmoid曲線斜率即可以進行調整         '''         for iteration in range(number_of_training_iterations):             #訓練集導入神經網絡             output = self.think(training_inputs)             #計算偏差(實際值與指望值的差)             error = training_outputs - output             #將偏差乘以輸入,再乘以S形曲線的梯度             adjustment = dot(training_inputs.T,error*self.__sigmoid_derivative(output))             #對樹突權重進行調整             self.dendritic_weights += adjustment         #神經網絡     def think(self,inputs):         #輸入與權重相乘並正規化         return self.__sigmoid(dot(inputs,self.dendritic_weights)) if __name__ == '__main__':     #初始化神經網絡nn     nn = NeuralNetwork()     #初始權重     print("初始樹突權重:{}".format(nn.dendritic_weights))     #訓練集,四個樣本,每一個樣本有3個輸入,1個輸出     #訓練樣本的輸入     training_inputs_sample = array([[0,0,1],                                     [1,1,1],                                     [1,0,1],                                     [0,1,1]])     #訓練樣本的輸出     training_outputs_sample = array([[0,1,1,0]]).T     #用訓練集訓練nn,重複一萬次,每次作微小的調整     nn.train(training_inputs_sample,training_outputs_sample,100000)     #訓練後的樹突權重     print("訓練後樹突權重:{}".format(nn.dendritic_weights))     #用新數據進行測試     test_result = nn.think(array([1,0,0]))     print('測試結果:{}'.format(test_result))

 

 

結語

運行後你應該看到這樣的結果:

 

 

咱們作到了!咱們用Python構建了一個簡單的神經網絡!

首先神經網絡對本身賦予隨機權重,而後使用訓練集訓練本身。接着,它考慮一種新的情形[1, 0, 0]而且預測了0.99993704。正確答案是1。很是接近!

相關文章
相關標籤/搜索