BP神經網路-- C語言實現 上
一些資料的定義
首先,我們介紹些下文中描述的程式裡面的一些重要資料的定義。
#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) 的實現在下一篇再來分析,晚安。