BP神經網路及其C語言實現

BP神經網路是目前為止最為成功的神經網路模型之一,本文首先介紹BP神經網路的基本概念和理論推導,最後給出具有訓練、模擬及實際擬合功能的C語言實現。

本文的理論部分全部來源於周志華《機器學習》,P97-P106,如需詳細了解,請查閱本書。

1. 基本概念

  • 神經網路:由簡單的神經元組成的廣泛互聯的網路,其具有適應性,可以模擬生物神經系統對真實世界所做出的交互反應。

  • 神經元模型:神經元模型是神經網路中的基本模型,單個神經元可以接收網路中其他神經元的信息,如果接收的信息超過閾值,則此神經元被激活,接著向其他神經元發送信息。

  • M-P神經元模型:M-P神經元模型是典型的神經元模型,其基本結構如圖1所示。

圖1 M-P神經元模型

在這個模型中,神經元接收來自n個其他神經元傳遞過來的輸入信號,這些輸入信號通過帶權重的連接進行傳遞,神經元接收到的總輸入值將與神經元的閾值進行比較,然後通過「激活函數」處理產生神經元的輸出。

  • Sigmoid函數:sigmoid是最常用的激活函數,如圖2所示。

圖2 sigmoid函數

其函數表達式為sigmoid(x) = frac{1}{1+e^{-x} }

  • 多層前饋神經網路(multi-layer feedforward neural networks):基本結構如圖3所示,此種結構的聖經網路,每層神經元與下一層神經元全連接,神經元之間不存在同層連接,也不存在跨層連接。其網路層次包含3層,其中輸入層神經元用於接收外界輸入,隱層與輸出層神經元對信號進行加工,最終結果由輸出層神經元輸出。

圖3 多層前饋神經網路

  • 神經網路的學習過程:根據訓練數據來調整神經元之間的連接權以及每個功能神經元的閾值,換言之,神經網路學習到的東西蘊含在連接權與閾值中。

2. BP神經網路理論推導

2.1 BP神經網路結構

BP神經網路是目前為止最為成功的神經網路演算法之一,其學習方式採用標準梯度下降的誤差逆傳播(error BackPropagation)的方式,以下介紹的基本BP神經網路為3層前饋神經網路。

圖4 BP神經網路模型

對於BP神經網路,我們需要使用訓練數據集對其進行參數訓練,然後使用測試機檢驗訓練結果,如果訓練效果達標,則可使用訓練出的數據應用於實際使用場景,對於神經網路其訓練過程最為主要,以下我們主要闡述其訓練方法。

對於圖4中的神經網路模型,我們做如下定義:

  • 給定訓練集D = left{ (x_1,y_1),(x_2,y_2),...,(x_m,y_m) right} ,x_iepsilon R^{d},y_iepsilon R^{l} ,即輸入數據維度為d,輸出數據維度為l

  • 圖4中,假設神經網路是輸入節點為d個,輸出節點為l個,隱層有q個的多層前向反饋神經網路,輸出層第j個神經元閾值為theta_j,第h個隱層神經元閾值為gamma _h.輸入層第i個節點與隱層第h個節點之間的權重為nu _{ih},隱層第h個節點與輸出層第j個節點的權重為w_{hj}.

根據以上假設可以有如下公式:

  1. 激活函數為f(x) = sigmoid(x)
  2. 隱層第h個神經元接收到的輸入為alpha _h=sum_{i=1}^{d}{v_{ih}x_i}
  3. 隱層第h個神經元的輸出為b_h=f(alpha _h-gamma _h)
  4. 輸出層第j個神經元接收到的輸入為beta _j=sum_{h=1}^{q}{w_{hj}b_h}
  5. 輸出層第j個神經元的輸出為y_j=f(beta _j-theta _j)

由以上5個公式可知,神經網路之中只要以下(d+l+1)q+l個參數確定,則就可以由輸入計算出輸出,這些參數分別為

  1. 輸入層到隱層權重dq個,隱層到輸出層權重ql
  2. 隱層神經元閾值q個,輸出層神經元閾值l

那麼我們如何得到這麼多個參數呢?BP神經網路演算法使用誤差逆向傳播進行訓練。

2.2 BP神經網路的訓練

神經網路的初始參數為[0,1]內隨機數,假設某次訓練過程中神經網路的輸入的某個訓練數據為(x,y),經過神經網路的輸出為tilde{y} =left{ tilde{y_1}, tilde{y_2},..., tilde{y_l} right} ,其中tilde{y_j} = f( beta _j-theta _j)

6. 對於訓練數據集中的單個數據其誤差E_k=frac{1}{2} sum_{j=1}^{l}{(tilde{y_j}-y_j)^2 }

我們採用梯度下降法根據誤差對神經網路中的參數進行反饋學習,神經網路中參數更新的公式為p leftarrow p + Delta p,

此處以隱層到輸出層權重w_{hj}為例對神經網路參數更新公式進行推導:

我們以誤差的負梯度方向對參數進行更新,eta 為學習率,有如下公式:

7. 參數更新公式w_{hj}leftarrow w_{hj}+Delta w_{hj}

8. 參數調整力度Delta w_{hj}=-eta frac{partial E_k}{partial w_{hj}}

9. 注意到,w_{hj}先影響到第j個輸出神經元的輸入值beta _j,再影響到其輸出值tilde{y_j}, 根據偏導數的鏈式法則有frac{partial E_k}{partial w_{hj}}=frac{partial E_k}{partial tilde{y_j} } cdot frac{partial tilde{y_j}}{partial {beta _j}} cdot frac{partial {beta _j}}{partial w_{hj}}

10. 根據beta _j的定義顯然有frac{partial beta_j}{partial w_{hj}}=b_h

11. 由於sigmoid函數的導數具有特殊性質f(x) = f(x)(1-f(x))

12. 則g_j = - frac{partial E_k}{partial tilde{y_j}} cdot frac{partial tilde{y_j}}{partial beta_j}=-(tilde{y_j}-y_j)f(beta_j-theta_j)=tilde{y_j}(1-tilde{y_j})(y_j-tilde{y_j})

按照以上推導方法有

13. Delta w_{hj} = eta g_j b_h

14. Delta theta_j = -eta g_j

15. 同理,Delta v_{ih} = eta e_h x_i

16. Delta gamma _h = -eta e_h

17. 在15.16式中e_h = - frac{partial E_k}{partial b_h} cdot frac{partial b_h}{partial alpha_h},而b_h影響lbeta _j,beta _j又影響E,所以有

e_h = -(sum_{j=1}^{l}{frac{partial E_k}{partial beta_j} cdot frac{partial beta_j}{partial b_h}} ) cdot f(alpha_h - gamma_h)=-sum_{j=1}^{l}{w_{hj}g_j} cdot f(alpha_h - gamma_h) = b_n(1-b_n) sum_{j=1}^{l}{w_{hj} g_j}

注意在公式13.14.15.16中eta控制著每一輪迭代中的更新步長,若太大,則容易振蕩,太小則學習過程收斂很慢,為了細微調節,13.14中的學習率可以和15.16中的不一樣。

18. 使用訓練集上的累積誤差衡量訓練質量E = frac{1}{m} sum_{k=1}^{m}{E_k}

2.3 BP神經網路的訓練過程

  • (0,1)內隨機初始化神經網路中的連接權重和閾值;

  • repeat

  • for 遍歷訓練集中的每一個樣本

  • 根據當前參數按照公式1.2.3.4.5計算樣本的b_h y_j.

  • 根據公式12.17計算g_j e_h.

  • 根據公式13.14.15.16更新w_{hj}, v_{ih}, theta_j, gamma _h.

  • end for

  • until (迭代若干次或者累積誤差E小於特定值)
  • 得到BP神經網路的參數

3. C語言實現

C語言的實現就很簡單了,BP神經網路分為兩個部分:

1. 訓練模塊,包含訓練以及驗證過程,注意此神經網路的輸入輸出都需要預先進行歸一化處理。

/**n * To fetch test_set.n * The length of in is IN_N, the length of out is OUT_N.n */ntypedef bool (*test_set_get_t)(double *in, double *out);nn/**n * Reset test_set fetch process.n */ntypedef bool (*test_set_init_t)(void);nn/**n * Init bpnn module.n */nvoid bpnn_init(void);nn/**n * Train bpnn module and produce parameter file.n * @param f_get To get test data in stream.n */nvoid bpnn_train(test_set_get_t f_get, test_set_init_t f_init);nn/**n * Test result of bpnn train parameter.n * @param f_getn */nvoid bpnn_sim(test_set_get_t f_get);n

2. 擬合模塊;

#define T bpnn_tntypedef struct T *T;nn/**n * Init bpnn module.n * @returnn */nT bpnn_fit_new(void);nn/**n * Using bpnn fit in to out.n * @param bpnnn * @param inn * @param outn */nvoid bpnn_fit(T bpnn, double *in, double *out);nn/**n * Uninit bpnn.n * @param bpnnn */nvoid bpnn_fit_free(T *bpnn);n

詳細的實現請訪問github:ThreeClassMrWang/c-bpnn

實現里教會了神經網路進行(a+b+c)/3的計算,詳細請見github,謝謝!


推薦閱讀:

深度學習(Deep Learning)基礎概念2:深度學習測試題及詳解1
KL散度不對稱。如果分布P和Q,KL(P||Q)很大而KL(Q||P)很小表示什麼現象?
刷頁還是刷專題:ACM競賽做題之道

TAG:神经网络 | 机器学习 |