深度學(xué)習(xí)之神經(jīng)網(wǎng)絡(luò)(反向傳播算法)(三)

神經(jīng)網(wǎng)絡(luò)

神經(jīng)網(wǎng)絡(luò)最開始是受生物神經(jīng)系統(tǒng)的啟發(fā),為了模擬生物神經(jīng)系統(tǒng)而出現(xiàn)的。大腦最基本的計算單元是神經(jīng)元,人類的神經(jīng)系統(tǒng)中大概有86億的神經(jīng)元,它們之間通過1014-1015的突觸相連接。每個神經(jīng)元從它的樹突(dendrites)接受輸入信號,沿著唯一的軸突(axon)產(chǎn)生輸出信號,而軸突通過分支(branches of axon),通過突觸(synapses)連接到其他神經(jīng)元的樹突,神經(jīng)元之間就這通過這樣的連接,進行傳遞。如下圖。

image.png

鏈式法則

先來回顧一下鏈式法則,這是反向傳播算法的推導(dǎo)基礎(chǔ)。


image.png

人工神經(jīng)網(wǎng)絡(luò)

image.png

人工神經(jīng)網(wǎng)絡(luò)其實就是按照一定規(guī)則模擬生物神經(jīng)網(wǎng)絡(luò)連接起來的多個神經(jīng)元,也就是感知機。
上圖展示了一個全連接(full connected, FC)神經(jīng)網(wǎng)絡(luò),一個全連接的網(wǎng)絡(luò)要按照層來進行布局。

1.最左邊的層叫做輸入層,負責接收輸入數(shù)據(jù)。
2.最右邊的層叫輸出層,我們可以從這層獲取神經(jīng)網(wǎng)絡(luò)輸出數(shù)據(jù)。
3.輸入層和輸出層之間的層叫做隱藏層,因為它們對于外部來說是不可見的。
4.同一層的神經(jīng)元之間沒有連接。

上圖中,第N層的每個神經(jīng)元和第N-1層的所有神經(jīng)元相連(這就是full connected的含義),第N-1層神經(jīng)元的輸出就是第N層神經(jīng)元的輸入。并且每個連接都有一個權(quán)值。

這也就是全連接神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)。

事實上還存在很多其它結(jié)構(gòu)的神經(jīng)網(wǎng)絡(luò),比如卷積神經(jīng)網(wǎng)絡(luò)(CNN)、循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN),他們都具有不同的連接規(guī)則。

神經(jīng)元

神經(jīng)網(wǎng)絡(luò)上的激活函數(shù)為(并不是全部,還有其他的激活函數(shù)):


image.png

sigmoid函數(shù)的定義如下:


image.png

即:
image.png

圖像表達為:


image.png

可以看出函數(shù)的取值范圍為(0,1)。
當然為了計算方便,我們還要關(guān)注一下它的導(dǎo)數(shù):



可以看出它的導(dǎo)數(shù)和它本身的數(shù)值相關(guān)。

工作原理

image.png

神經(jīng)網(wǎng)絡(luò)的作用就是簡單的說,就是將輸入的x,轉(zhuǎn)化成輸出的y。當然其中還要包括許多的處理。包括先從前往后,求取值,再從后往前更新權(quán)值。
下面以監(jiān)督學(xué)習(xí)為例:


image.png

已知輸入向量X,獲取輸 出向量Y。當然對于監(jiān)督學(xué)習(xí)來說,我們會有許多的樣本(X,Y),這里面的Y值是已知的,但是我們還要求得實際的Y值,來算取得本次樣本數(shù)據(jù)的誤差。
這就需要向前傳播。

向前傳播

從輸入層到隱藏層:
對隱藏層的節(jié)點4來說,它的輸出值a4為:


image.png

同理求得節(jié)點5,6,7的輸出值a5,a6,a7。


image.png

從隱藏層到輸出層:
對于節(jié)點8來說,其輸出值y1為:
image.png

同理y2:

image.png

所以對于實際輸出向量Y來說,它和輸入向量X的關(guān)系就是:


image.png
image.png

向后傳播

獲得實際的輸出值后,我們就要來計算誤差。
誤差的計算方式:


image.png

將一次樣本期望輸出的向量值T(因為是神經(jīng)網(wǎng)絡(luò),所以輸出值為向量),減去實際輸出的向量Y。其中d代表樣本編號。

當然此時涉及到兩層的權(quán)值向量的更改,就不能僅僅是向線性單元那樣計算了,不過大致的思想是一直的,都是采用梯度下降的思想,不過這時候還要使用鏈式法則。


image.png

其中的i和j表示,從i節(jié)點指向j節(jié)點。
根據(jù)這種方式來求取對每個節(jié)點的權(quán)值的更新,當然這也有個問題,就是因為網(wǎng)絡(luò)是多層的,無法直接的求得每一層的對權(quán)重的改變。


image.png

這就需要使用鏈式法則:


image.png

(來自零基礎(chǔ)入門深度學(xué)習(xí)(3) - 神經(jīng)網(wǎng)絡(luò)和反向傳播算法)
對輸出層來說:


image.png

其中j代表第j個節(jié)點。
所以根據(jù)鏈式法則:


image.png

只考慮第一項:


image.png

只考慮第二項:
image.png

這里設(shè)定一個betal值:

及:


image.png

所以最后得到輸出層的權(quán)重改變公式:


image.png

再考慮隱藏層:
對隱藏層來說,它對結(jié)果的改變主要是通過影響輸出層的輸入值來響應(yīng)最后的輸出結(jié)果。
這個就需要分開來考慮。
比如節(jié)點4,它的輸出值可以分別影響到y(tǒng)1和y2.
所以對誤差E來說,節(jié)點4的輸出值a4對其的影響,可以寫成:


image.png

擴展開來,也就是鏈式法則的全導(dǎo)數(shù):


image.png

其中Downstream(j)代表所有j的下游節(jié)點的集合(比如節(jié)點4,它的下游節(jié)點為8,9),netk就表示下游節(jié)點的輸入數(shù)據(jù)。
最后求得:
image.png

大功告成,根據(jù)以上的公式就可以來推斷一下權(quán)值的更新了,下面舉個例子來實踐一下。(知行合一才是硬道理O(∩_∩)O哈哈~)

同時也感謝大神@hanbingtao的文章,讓我這個小白理解了神經(jīng)網(wǎng)絡(luò)。感謝。

神經(jīng)網(wǎng)絡(luò)解決異或

異或問題在感知器的時候已經(jīng)知道,因為它是非線性的所以無法用感知器來解決。不過可以使用神經(jīng)網(wǎng)絡(luò)嘗試一下。


image.png

首先先構(gòu)建神經(jīng)網(wǎng)絡(luò),本次的網(wǎng)絡(luò)構(gòu)建如圖所示。

代碼

# coding=utf-8
# numpy 支持高級大量的維度數(shù)組與矩陣運算
import numpy  as np


#定義坐標,設(shè)定5組輸入數(shù)據(jù),每組為(x0,x1,x2)
X=np.array([[1,0,0],
            [1,0,1],
            [1,1,0],
            [1,1,1]]);

#設(shè)定輸入向量的期待輸出值
Y=np.array([0,1,1,0]);

#設(shè)定權(quán)值向量(V,W)
#輸入層和隱藏層之間的權(quán)值
V = np.array([[0,0.1,0.7],
             [0.5,0.2,0.1],
             [0.1,0.1,0.3]]);
#隱藏層和輸出層之間的權(quán)值
W = np.array([[0.2,0.1,0.3]]);

#設(shè)定學(xué)習(xí)率
lr = 0.5;

#sigmoid函數(shù)
def sigmoid(x):
    return 1/(1+np.exp(-x));
#對sigmoid函數(shù)求導(dǎo)
def sigmoid_daoshu(x):
    return x*(1-x);

def  updateW():
    global  X,Y,V,W,lr,n;
    #權(quán)值向量修正記錄
    W_C = np.array([[0,0,0]]);
    V_C = np.array([[0,0,0],
                    [0,0,0],
                    [0,0,0]]);

    #4個樣本分別計算
    for i in range(0,4):
        ##第一層(矩陣3*1)
        layer_1_input = np.dot(V,np.array([X[i]]).T);  ## V*X
        layer_1_output = sigmoid(layer_1_input);  ## a=f(V*X)

        ##第二層(矩陣1*1)
        layer_2_input = np.dot(W,layer_1_output);  
        layer_2_output = sigmoid(layer_2_input);

        #第二層的誤差(矩陣1*1)
        E_2 = Y[i] - layer_2_output.T;
        ## 輸出層的detal(矩陣1*1)
        layer_2_detal = E_2*sigmoid_daoshu(layer_2_output);

        ##隱藏層的誤差(矩陣3*1)
        E_1 = np.dot(W.T,layer_2_detal);
        
        ## 隱藏層的detal(矩陣3*1)
        layer_1_detal = E_1*sigmoid_daoshu(layer_1_output);

        ##所有的W向量增加數(shù)值
        W_C = W_C + np.dot(layer_2_detal, layer_1_output.T);
        ##所有的V向量增加數(shù)值
        V_C = V_C + np.dot(layer_1_detal, np.array([X[i]]));

    #求出平均數(shù)
    W_d = W_C/4.0;
    V_d = V_C/4.0;
    #修改權(quán)值
    W = W + lr*W_d;
    V = V + lr*V_d;


if __name__ == '__main__':
    output = [0,0,0,0];
    #設(shè)置迭代次數(shù)
    for index in range (10000):
        updateW();
        if index==0 or index==(10000-1):
            #計算出結(jié)果
            for i in range(0,4):
                layer_1_input = np.dot(V,np.array([X[i]]).T); 
                layer_1_output = sigmoid(layer_1_input);  
                
                layer_2_input = np.dot(W,layer_1_output);  
                layer_2_output = sigmoid(layer_2_input);

                output[i] = layer_2_output[0][0];
            print output


運行結(jié)果

image.png

可以看出,經(jīng)過10000次迭代,結(jié)果已經(jīng)很接近了。
大功告成??!
回去吃大餐!

參考

神經(jīng)網(wǎng)絡(luò)基礎(chǔ)介紹
https://blog.csdn.net/wq2610115/article/details/68928368
一文搞懂反向傳播算法
http://www.itdecent.cn/p/964345dddb70
零基礎(chǔ)入門深度學(xué)習(xí)(3) - 神經(jīng)網(wǎng)絡(luò)和反向傳播算法
https://www.zybuluo.com/hanbingtao/note/476663

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容