BP神经网络-- C语言实现
? ? ? 在上一篇文章中,介紹了BP神經網絡的基本模型、模型中的一些術語并對模型進行了數學上的分析,對它的原理有了初步的認識。那么如何用程序語言來具體的實現它,將是我們下一步需要討論的問題。本文選取的是C語言來實現一個簡單的單隱藏層的BP神經網絡(默認大家了解了BP神經網絡的基本概念,本文中涉及到些術語參見上一篇 ?基本模型?),因此對于其他C類語言(C#、JAVA等)只需對本文中的代碼稍作修改即可移植。
?
一些數據的定義
?? 首先,我們介紹些下文中描述的程序里面的一些重要數據的定義。
#define Data 820 #define In 2 #define Out 1 #define Neuron 45 #define TrainC 5500? ? ? Data 用來表示已經知道的數據樣本的數量,也就是訓練樣本的數量。In 表示對于每個樣本有多少個輸入變量; Out 表示對于每個樣本有多少個輸出變量。Neuron 表示神經元的數量,TrainC 來表示訓練的次數。再來我們看對神經網絡描述的數據定義,來看下面這張圖里面的數據類型都是 double 型。
?
圖1
? ? ? d_in[Data][In] 存儲 Data 個樣本,每個樣本的 In 個輸入。d_out[Data][Out] 存儲 Data 個樣本,每個樣本的 Out 個輸出。我們用鄰接表法來表示 圖1 中的網絡,w[Neuron][In] ?表示某個輸入對某個神經元的權重,v[Out][Neuron] 來表示某個神經元對某個輸出的權重;與之對應的保存它們兩個修正量的數組 dw[Neuron][In] 和 dv[Out][Neuron]。數組 o[Neuron] 記錄的是神經元通過激活函數對外的輸出,OutputData[Out] ?存儲BP神經網絡的輸出。
?
程序的執行過程
???????? 在這里,先不考慮具體函數的執行細節,從大體上來介紹程序的執行過程。用偽代碼來表示,具體的內容后面一步步介紹,如下:
主函數main{讀取樣本數據 readData();初始化BP神經網絡 initBPNework(){包括數據的歸一,神經元的初始化 w[Neuron][In]、v[Out][Neuron]等;}BP神經網絡訓練 trainNetwork(){do{for(i 小于 樣本容量 Data){計算按照第 i 個樣本輸入,產生的BP神經網絡的輸出 computO(i);累記誤差精度;反饋調節BP神經網絡中的神經元,完成第 i 個樣本的學習 backUpdate(i);}}while(達到訓練次數 或者 符合誤差精度);}存儲訓練好的神經元信息 writeNeuron();用一些數據來測試,訓練出來的BP神經網絡的結果;return 0; }? ? ? ?以上是處理的流程,對于讀取數據、保存數據之類的處理本文將略去這方面內容,突出主干部分。
?
初始化BP神經網絡
? ? ? 初始化主要是涉及兩個方面的功能,一方面是對讀取的訓練樣本數據進行歸一化處理,歸一化處理就是指的就是將數據轉換成0~1之間。在BP神經網絡理論里面,并沒有對這個進行要求,不過實際實踐過程中,歸一化處理是不可或缺的。因為理論模型沒考慮到,BP神經網絡收斂的速率問題,一般來說神經元的輸出對于0~1之間的數據非常敏感,歸一化能夠顯著提高訓練效率。可以用以下公式來對其進行歸一化,其中 加個常數A 是為了防止出現 0 的情況(0不能為分母)。
? ? ? ?y=(x-MinValue+A)/(MaxValue-MinValue+A)
? ? ? 另一方面,就是對神經元的權重進行初始化了,數據歸一到了(0~1)之間,那么權重初始化為(-1~1)之間的數據,另外對修正量賦值為0。實現參考代碼如下:
void initBPNework(){int i,j;/*找到數據最小、最大值*/for(i=0; i<In; i++){Minin[i]=Maxin[i]=d_in[0][i];for(j=0; j<Data; j++){Maxin[i]=Maxin[i]>d_in[j][i]?Maxin[i]:d_in[j][i];Minin[i]=Minin[i]<d_in[j][i]?Minin[i]:d_in[j][i];}}for(i=0; i<Out; i++){Minout[i]=Maxout[i]=d_out[0][i];for(j=0; j<Data; j++){Maxout[i]=Maxout[i]>d_out[j][i]?Maxout[i]:d_out[j][i];Minout[i]=Minout[i]<d_out[j][i]?Minout[i]:d_out[j][i];}}/*歸一化處理*/for (i = 0; i < In; i++)for(j = 0; j < Data; j++)d_in[j][i]=(d_in[j][i]-Minin[i]+1)/(Maxin[i]-Minin[i]+1);for (i = 0; i < Out; i++)for(j = 0; j < Data; j++)d_out[j][i]=(d_out[j][i]-Minout[i]+1)/(Maxout[i]-Minout[i]+1);/*初始化神經元*/for (i = 0; i < Neuron; ++i) for (j = 0; j < In; ++j){ w[i][j]=(rand()*2.0/RAND_MAX-1)/2;dw[i][j]=0;}for (i = 0; i < Neuron; ++i) for (j = 0; j < Out; ++j){v[j][i]=(rand()*2.0/RAND_MAX-1)/2;dv[j][i]=0;} }?
BP神經網絡訓練
? ? ? 這部分應當說是整個BP神經網絡形成的引擎,驅動著樣本訓練過程的執行。由BP神經網絡的基本模型知道,反饋學習機制包括兩大部分,一是BP神經網絡產生預測的結果,二是通過預測的結果和樣本的準確結果進行比對,然后對神經元進行誤差量的修正。因此,我們用兩個函數來表示這樣的兩個過程,訓練過程中還對平均誤差 e 進行監控,如果達到了設定的精度即可完成訓練。由于不一定能夠到達預期設定的精度要求,我們添加一個訓練次數的參數,如果次數達到也退出訓練。實現參考代碼如下:
?
void trainNetwork(){int i,c=0;do{e=0;for (i = 0; i < Data; ++i){computO(i);e+=fabs((OutputData[0]-d_out[i][0])/d_out[i][0]);backUpdate(i);}//printf("%d %lf\n",c,e/Data);c++;}while(c<TrainC && e/Data>0.01); }?
??????? 其中的函數,computO(i) (O是output縮寫)計算BP神經網絡預測第 i 個樣本的輸出也就是第一個過程。backUpdate(i) 是根據預測的第 i 個樣本輸出對神經網絡的權重進行更新,e用來監控誤差。
?到這里,我們整體回顧來看,BP神經網絡程序實現的骨架已經介紹完了,訓練過程中核心的兩個函數computO(i) 和 backUpdate(i) 的實現在下一篇再來分析,晚安。
C語言實現上?中介紹了程序實現時定義的一些數據結構、程序執行的流程以及 程序的基本骨架(詳情見 C語言實現上)。留下了兩個關鍵函數computO(i) 和 backUpdate(i) 沒有分析實現,參數 i 代表的是第 i 個樣本,本篇我們一起來分析下這兩個函數的實現。
BP神經網絡輸出
? ? ? 函數 computO(i) 負責的是通過BP神經網絡的機制對樣本 i 的輸入,預測其輸出。回想BP神經網絡的基本模型(詳情見 基本模型)對應的公式(1)還有 激活函數對應的公式(2):
? ??
??????
? ? ? 在前篇設計的BP神經網絡中,輸入層與隱藏層權重對應的數據結構是w[Neuron][In],隱藏層與輸出層權重對應的數據結構是v[Out][Neuron],并且數組 o[Neuron] 記錄的是神經元通過激活函數對外的輸出,BP神經網絡預測的樣本結果保存在OutputData[Out]中。由此,就可以得到以下實現的參考代碼:
void computO(int var){int i,j;double sum,y;/*神經元輸出*/for (i = 0; i < Neuron; ++i){sum=0;for (j = 0; j < In; ++j)sum+=w[i][j]*d_in[var][j];o[i]=1/(1+exp(-1*sum));}/* 隱藏層到輸出層輸出 */for (i = 0; i < Out; ++i){sum=0;for (j = 0; j < Neuron; ++j)sum+=v[i][j]*o[j];OutputData[i]=sum;} }?
BP神經網絡的反饋學習
???????? 函數 backUpdate(i) 負責的是將預測輸出的結果與樣本真實的結果進行比對,然后對神經網絡中涉及到的權重進行修正,也這是BP神經網絡實現的關鍵所在。如何求到對于 w[Neuron][In] 和 v[Out][Neuron] 進行修正的誤差量便是關鍵所在!誤差修正量的求法在基本模型一文中數學分析部分有解答,具體問題具體分析,落實到我們設計的這個BP神經網絡上來說,需要得到的是對w[Neuron][In] 和 v[Out][Neuron] 兩個數據進行修正誤差,誤差量用數據結構 dw[Neuron][In] ?和 ?dv[Out][Neuron]? 來進行存儲。那么來分析下這兩個修正誤差量是什么樣的?推導的思路與基本模型中推導誤差量的一致,這里僅列出對具體對于我們設計的BP神經網絡中的數學推導過程:
???
? ? ? 如果你不想知道推導過程,那么只需要看上面中的兩個 所以(有三個點的地方) 的內容,就可以知道所需要的誤差量是什么樣的了;如果想要想弄明白的話,或許需要自己在稿子上畫畫看推導推導。到這里完成了數學推導,實現的代碼就很容易寫了。在具體實現對誤差修改中,我們再加上學習率,并且對先前學習到的修正誤差量進行繼承,直白的說就是都乘上一個0到1之間的數,具體的見如下實現參考代碼:
#define A 0.2 #define B 0.4 #define a 0.2 #define b 0.3 void backUpdate(int var) {int i,j;double t;for (i = 0; i < Neuron; ++i){t=0;for (j = 0; j < Out; ++j){t+=(OutputData[j]-d_out[var][j])*v[j][i];dv[j][i]=A*dv[j][i]+B*(OutputData[j]-d_out[var][j])*o[i];v[j][i]-=dv[j][i];}for (j = 0; j < In; ++j){dw[i][j]=a*dw[i][j]+b*t*o[i]*(1-o[i])*d_in[var][j];w[i][j]-=dw[i][j];}} }
? ? ? ?好了,至此BP神經網絡的C語言實現就全部完成了。最后,我們可以測試下BP神經網絡的運行。我這里是這樣給出數據的,兩個輸入a、b(10以內的數),一個輸出 c,c=a+b。換句話說就是教BP神經網絡加法運算。在 45個神經元,820個訓練樣例,樣本平均誤差小于0.01時完成訓練(學習率等見參考代碼)的條件下,最后預測 (6,8),(2.1,7),(4.3,8)實際輸出結果如下:
? ?最后附上參考實現代碼,以及實驗訓練時的數據、和神經元信息。(本示例 僅為BP神經網絡實現的 簡單DEMO,若實際使用還需多加考慮!!!)
參考代碼下載
總結
以上是生活随笔為你收集整理的BP神经网络-- C语言实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Neuroph studio max n
- 下一篇: 用rapid-framework开源工具