神經網絡從基礎到改進+源程序


神經網絡初步學習總結:(對神經網絡的模型有一定的了解,如果從未接觸有點看不懂)

第一點:以下是最簡單的神經網絡模型了

x:  輸入參數

a0: 輸入偏置

a1: 輸入權重

b0: 隱藏層偏置

b1: 隱藏層輸入權重

y:  隱藏層輸入參數(經過激勵函數的輸出,下面會講解激勵函數)

Z:  隱藏層輸出(經過激勵的輸出)

 

各個參數的展開式如下:不用介紹了,都很簡單的函數,不懂得話去百度一些模型看看

 

 

 

 

激勵函數:經過sigmoid()函數之后的數值,這是常見的分類函數。

          如果是用於函數逼近,使用Y = X 作為激勵函數即可。

第二點:公式的相關介紹

首先明確梯度下降法:字面的理解是沿着切線的方向,可以更快更准確的找出最小值

                    我們使用這個規則只需要知道,梯度下降=偏導數,其中

                    偏導數=k*變化量  抓住這兩個點,這是BP神經網絡的核心之一

                    例如:  :比例系數,W:權值,E:誤差

明白Delta學習規則:有監督的學習,是利用誤差作為判斷的標准。

                   形式:  y:隱藏層的輸出

                                Z:實際輸出,t:期望輸出(實際值)

                   基於這個學習規則進行BP的反向調整權重,核心之二

結合上面兩個公式Delta規則的誤差作為標准,誤差利用整體的平方可以減少誤差波動的

                  影響下面為了計算方便多乘以一個1/2,求導之后消去,    

                 沒意義只是為了計算方便:BP神經網絡的權值和偏置調整就可以利用這

                 個公式,例如:  等等

 

神經網絡的權值和偏置計算

  因為誤差E和隱藏層偏置沒有直接關系,

所以需要鏈式求偏導,返回去看一下模型的參數定義就知道了。

‚  因為誤差E和輸入層的輸入數據沒有直接聯系,所以需要鏈式求偏導

很簡單的鏈式求導,看一下高數就知道的。

剩下的公式大家自己推導吧。。。。這是核心之三

第三點:BP神經網絡的改進

1.批量學習:顧名思義批量學習就是梯度成批量的計算, 總梯度的含義

          例如:批量數是10個樣本,那就是W1的梯度是十個樣本加起來。和一個一個        

          的計算是一樣的,這里不過是選幾個樣本加起來求平均數而已。

2.遍歷學習(在線):本文中使用的改進就是動量法,當前權值的更新需要上一次的和這一次   

          同時作用,達到平滑高效的作用。公式:,注意這

          里的是沒有疊加的,因為上面w存在。是有疊加的,因為是所有的w項。核心之四

第四點:BP神經網絡的程序

核心算法就是更新權值w和更新偏置b,參考了網上程序,但是基本都是有漏洞,可能沒下載到好的程序吧,結合了部分網上歷程還有一本書《神經網絡在應用科學和工程中的應用-----從基本原理到復雜的模式識別》。我弄了一個星期,就是由於公式編寫成代碼出現很多問題,多細心一點可以減少很多未知的錯誤!!!

       BP神經網絡下載

注意:看了Ng的視頻,Sigmoid函數<tanh函數<ReLu函數<Leak ReLu函數

 

 

CPP文件:

  1 #include "BP.h"
  2 
  3 BP_network::BP_network()
  4 {
  5     srand((unsigned)time(NULL));
  6     memset(w, 0, sizeof(w));
  7     memset(b, 0, sizeof(b));
  8     memset(Yout, 0, sizeof(Yout));
  9     memset(DataIn, 0, sizeof(DataIn));
 10     memset(DataOut, 0, sizeof(DataOut));
 11     memset(dv, 0, sizeof(dv));
 12     memset(dw, 0, sizeof(dw));
 13 }
 14 
 15 BP_network::~BP_network()
 16 {
 17 
 18 }
 19 
 20 double BP_network::Random()
 21 {
 22     double Rand;
 23     Rand = (1.0*rand()) / (RAND_MAX + 1);
 24     return Rand;
 25 }
 26 //--------------寫入數據-------------------//
 27 void BP_network::FwriteData()
 28 {
 29     FILE *fp1, *fp2;
 30     double data1 = 0.0, data2;
 31     if ((fp1 = fopen("G:\\in.txt", "w")) == NULL) printf("can't open in.txt");
 32     if ((fp2 = fopen("G:\\out.txt", "w")) == NULL) printf("can't open out.txt");
 33     for (int i = 0; i < SampleCount; i++)
 34     {
 35         //data1 = Random() % 1000 / 100;
 36         data1 = double(int(Random() * 1000) % 1000) / 100;
 37         data2 = double(int(Random() * 1000) % 1000) / 100;
 38         fprintf(fp1,"%lf %lf\n", data1, data2);
 39         data1 = data1 * data2;
 40         fprintf(fp2,"%lf \n", data1);
 41     }
 42     fclose(fp1);
 43     fclose(fp2);
 44 }
 45 //--------------讀入數據-------------------//
 46 void BP_network::FreadData()
 47 {
 48     FILE *fp1, *fp2;
 49     if (((fp1 = fopen("G:\\in.txt", "r")) == NULL))
 50         printf("can't open in.txt");
 51     if((fp2 = fopen("G:\\out.txt", "r")) == NULL)
 52         printf("can't open in.txt");;
 53     for (int i = 0; i < SampleCount; i++)
 54     {
 55         for (int j = 0; j < InCount; j++)
 56         {
 57             fscanf(fp1, "%lf", &DataIn[i][j]);
 58         }
 59         fscanf(fp2, "%lf", &DataOut[i][0]);
 60     }
 61     fclose(fp1);
 62     fclose(fp2);
 63 }
 64 //---------歸一化輸入和輸出的數值,隨機化權值和偏置的值---------//
 65 //****************   對於隱藏層->輸出層=w[i][j][k]     *************//
 66 //------------------  i:層數,j:輸出層個數,k:隱藏層個數    ------//
 67 void BP_network::Init_network()
 68 {
 69     double InMax, InMin, OutMax, OutMin;
 70     InMax = DataIn[0][0];
 71     InMin = DataIn[0][0];
 72     OutMax = DataOut[0][0];
 73     OutMin = DataOut[0][0];
 74 
 75     for (int i = 0; i < SampleCount; i++)
 76     {
 77         for (int j = 0; j < InCount; j++)
 78         {
 79             InMax = InMax > DataIn[i][j] ? InMax : DataIn[i][j];
 80             InMin = InMin < DataIn[i][j] ? InMin : DataIn[i][j];
 81         }
 82         OutMax = OutMax > DataOut[i][0] ? OutMax : DataOut[i][0];
 83         OutMin = OutMin < DataOut[i][0] ? OutMin : DataOut[i][0];
 84     }
 85     for (int i = 0; i < SampleCount; i++)
 86     {
 87         for (int j = 0; j < InCount; j++)
 88         {
 89             DataIn[i][j] = (DataIn[i][j] - InMin + 1) / (InMax - InMin + 1);
 90         }
 91         DataOut[i][0] = (DataOut[i][0] - OutMin + 1) / (OutMax - OutMin + 1);
 92     }
 93     for (int j = 0; j < HiddenCount; j++)
 94     {
 95         //----------隨機化W和B的值------------//
 96         for (int i = 0; i < LayerCount - 1; i++)
 97         {
 98             if (i == 0)//第一層
 99             {
100                 for (int k = 0; k < InCount; k++)  w[i][k][j] = 2 * (0.5 - Random());
101             }
102             if (i == 1)//第二層
103             {
104                 w[i][j][0] = 2 * (0.5 - Random());
105             }
106         }
107         b[0][j] = 1;//由於數比較少,不需要做循環,直接賦值
108         b[1][0] = 1;
109     }    
110     inMax = InMax;
111     inMin = InMin;
112     outMax = OutMax;
113     outMin = OutMin;
114 }
115 //---------激勵函數輸出----------//
116 void BP_network::DrivingOut(int m)
117 {
118     Yout[1][0] = 0.0;//!!!!!!!!!!!!!注釋:未能清除數據,導致檢查兩天!!!!!!!!!!!!!!!!!!!!!
119     for (int j = 0; j < HiddenCount; j++)
120     {
121         Yout[0][j] = 0.0;
122         for (int k = 0; k < 2; k++)
123         {
124             Yout[0][j] += DataIn[m][k] * w[0][k][j];    
125         }
126         Yout[0][j] += b[0][j];
127         Yout[0][j] = Sigmoid(Yout[0][j]);
128         Yout[1][0] += Yout[0][j] * w[1][j][0];
129     }
130     Yout[1][0] += b[1][0];
131     Yout[1][0] = Sigmoid(Yout[1][0]);
132 }
133 //-----------對W和B進行調整---------------//
134 void BP_network::BackAdjust(int m)
135 {
136 #if 1//加動量法
137     double StudyRate = 0.0, f = 0.0;
138     double Sum = 0.0;
139     StudyRate = (Yout[1][0] - DataOut[m][0]) * Yout[1][0] * (1 - Yout[1][0]);
140     db0[1][0] = U1*db0[1][0] + (1 - U1)*B_Rate*StudyRate;
141     b[1][0] -= db0[1][0];
142     for (int i = 0; i < HiddenCount; i++)
143     {
144         dv[0][i] = U1*dv[0][i] + (1 - U1)*W_Rate * StudyRate * Yout[0][i];
145         w[1][i][0] -= dv[0][i];
146     }
147     for (int i = 0; i < HiddenCount; i++)
148     {
149         f = 0.0;
150         f = StudyRate * w[1][i][0] * Yout[0][i] * (1 - Yout[0][i]);//改正之后
151         for (int j = 0; j < InCount; j++)
152         {
153             dw[j][i] = U1*dw[j][i] + (1 - U1)*W_Rate * f * DataIn[m][j];
154             w[0][j][i] -= dw[j][i];
155         }
156         db1[0][i] = U1*db0[0][i] + (1 - U1)*B_Rate*f;
157         b[0][i] -= db1[0][i];
158     }
159 #endif
160 #if 0//網上找到的加了一點動量,但是程序不穩定
161     int i, j;
162     double t;
163     for (i = 0; i < HiddenCount; ++i)
164     {
165         t = 0;
166         for (j = 0; j < OutCount; ++j) {
167             t += (Yout[1][j] - DataOut[m][j])*w[1][i][j];
168             dv[i][j] = U1*dv[i][j] + (1-U1)*W_Rate*(Yout[1][j] - DataOut[m][j])*Yout[0][i];
169             w[1][i][j] -= dv[i][j];
170         }
171         for (j = 0; j < InCount; ++j) {
172             dw[j][i] = U1*dw[j][i] + (1 - U1)*W_Rate*t*Yout[0][i] * (1 - Yout[0][i])*DataIn[m][j];
173             w[0][j][i] -= dw[j][i];
174         }
175 }
176 #endif
177 #if 0//未加動量法
178     double StudyRate = 0.0, f = 0.0;
179     double Sum = 0.0;
180     StudyRate = ( Yout[1][0] - DataOut[m][0]) * Yout[1][0] * (1 - Yout[1][0]);
181     b[1][0] -= ETA_W*StudyRate;
182     for (int i = 0; i < HiddenCount; i++)  
183         w[1][i][0] -= W_Rate * StudyRate * Yout[0][i];
184     for (int i = 0; i < HiddenCount; i++)
185     {        
186         f = 0.0;
187         f = StudyRate * w[1][i][0] * Yout[0][i] * (1 - Yout[0][i]);//改正之后
188         for (int j = 0; j < InCount; j++)
189         {
190             w[0][j][i] -= W_Rate* f *DataIn[m][j];
191         }
192        b[0][i] -= ETA_B * f;
193     }
194 #endif
195 }
196 //-----------訓練神經網絡-----------------//
197 void BP_network::Train_network()
198 {
199     int Tcount = 0;
200     double e = 1.0;
201     while (Tcount<TrainCount && e>Accuracy)
202     {
203         e = 0;
204         for (int i = 0; i < SampleCount; i++)
205         {
206             DrivingOut(i);
207             e += fabs((Yout[1][0]-DataOut[i][0])/ DataOut[i][0]);
208             BackAdjust(i);
209         }
210         Tcount++;
211         e = e / SampleCount;
212         cout << "" << Tcount << "代精度為:" << e << endl;
213     }
214 }
215 
216 double BP_network::Calculate(double x, double y)
217 {
218     x = (x - inMin + 1) / (inMax - inMin + 1);
219     y = (y - inMin + 1) / (inMax - inMin + 1);
220 #if true
221     double sum = 0.0, Tout = 0.0;
222     for (int i = 0; i < HiddenCount; i++)
223     {
224         Yout[0][i] = w[0][0][i] * x + w[0][1][i] * y + b[0][i];
225         Yout[0][i] = Sigmoid(Yout[0][i]);
226         Tout += Yout[0][i] * w[1][i][0];
227     }
228     Tout += b[1][0];
229     Tout = Sigmoid(Tout);
230     return (Tout * (outMax - outMin + 1) + outMin - 1);
231 #endif
232 }
233 
234 double BP_network::Sigmoid(double t)
235 {
236     double sum;
237     sum = 1.0 / (1.0+exp(-t));
238     return sum;
239 }

 

H文件:

 1 #pragma once
 2 #define _CRT_SECURE_NO_WARNINGS
 3 
 4 #include <iostream>
 5 #include <vector>
 6 #include "time.h"
 7 #include "math.h"
 8 
 9 using namespace std;
10 
11 const int SampleCount = 820;//定義樣本個數
12 const int InCount = 2;//輸入神經元個數
13 const int OutCount = 1;//輸出神經元個數
14 const int HiddenCount = 45;//隱藏層神經元個數
15 const int TrainCount = 6000;//訓練次數
16 const int LayerCount = 3;//神經網絡層數
17 const int NeuronMax = 45;//每層最多的神經元個數(也可以直接定義個數)
18 
19 const double U0 = 0.15;
20 const double U1 = 0.0;//0.15
21 const double W_Rate = 0.8;//權值調整率//0.8
22 const double B_Rate = 0.8;//閾值調整率
23 const double Accuracy = 0.01;
24 
25 #define ETA_W 0.2
26 #define ETA_B 0.1
27 
28 class BP_network
29 {
30 public:
31     BP_network();
32     ~BP_network();    
33     void FwriteData();
34     void FreadData();
35     void Init_network();
36     void Train_network();
37     double Calculate(double x, double y);
38 private:
39     double DataIn[SampleCount][InCount];//輸入的數據
40     double DataOut[SampleCount][OutCount];//輸出的數據
41     double w[LayerCount-1][HiddenCount][HiddenCount];//權值(定義的是最大范圍,為了移植方便,用不完)
42     double b[LayerCount-1][NeuronMax];//偏置(第幾層,第幾個神經元,對應的下一的神經元)
43     double Yout[LayerCount-1][NeuronMax];//經過激勵函數的輸出
44     double inMax, outMax, inMin, outMin;
45     double dv[HiddenCount][HiddenCount], dw[HiddenCount][HiddenCount];
46     double db0[2][2], db1[HiddenCount][HiddenCount];
47 
48 
49     double Sigmoid(double t);
50     void DrivingOut(int i);
51     void BackAdjust(int t);
52     double Random();
53 };

main文件:

 1 #include "BP.h"
 2 
 3 int main(int argc, char*argv)
 4 {
 5     BP_network test;
 6     test.FwriteData();
 7     test.FreadData();
 8     test.Init_network();
 9     test.Train_network();
10     cout << test.Calculate(5,5);
11     while (1);return 0;
12 }

不訓練直接使用文件:

注:這是沒有經過測試,可能程序有點小Bug,主題思路是沒問題的!

 1 //----@InData:    輸入為一維的數據 
 2 //----@Weight:    權重
 3 //                []        :層數, 
 4 //                            [0]:      輸入層到隱藏層的權重
 5 //                            [1]:      隱藏層到輸出層的權重
 6 //                [][]    :每層個數
 7 //                            [0][i]:      輸入層的個數
 8 //                            [1][h]:      隱藏層個數
 9 //                [][][]    :每層個數        
10 //                            [0][i][h]:隱藏層個數        
11 //                            [1][h][o]:輸出層個數
12 //----@Bias:    偏置
13 //                [0][h]    :隱藏層偏置
14 //                [1][o]    :輸出層偏置
15 //----@OutData:    輸出為一維數據                        
16 void Calculate(double* InData,double*** Weight,double* Bias ,char* OutData)
17 {
18     double HidData[HiddenCount][OutCount],HidData_Temp=0;//HidData:存放臨時隱藏層到輸出層的數據,HidData_Temp:存放臨時輸入層到隱藏層的單個數據
19     unsigned char flag = 1;//加輸出層偏置
20     for (char h = 0; h < HiddenCount; h++)
21     {
22         for(unsigned char i=0; i<sizeof(InData)/sizeof(double); i++)//單個隱藏層的輸出
23         {
24             HidData_Temp += Weight[0][i][h] *InData[i];
25         }
26         HidData_Temp += Bias[0][h];
27         HidData_Temp = Sigmoid(HidData_Temp);
28         for(unsigned char o=0; o<sizeof(OutData)/sizeof(char); o++)//單個隱藏層對輸出層的輸出
29         {
30             HidData[h][o] = Weight[1][h][o]*HidData_Temp;
31             OutData[o] += HidData[h][o];
32             //OutData[o] = flag==1?(OutData[o]+Bias[1][o]):OutData[o];
33             if(flag) OutData[o]+=Bias[1][o];//只能加一次偏置,顧用標志位
34         }
35         flag=0;
36     }
37 }
38 //----@InData:    輸入為一維的數據 
39 //----@MinMax:    數據最值
40 //                [0] :Maximun data
41 //                [1]    :Minimun data
42 //----@OutData:    輸出為一維數據    
43 void Normlize(double* InDta,double* MinMax,double* OutData)
44 {
45     for(unsigned char i=0;i<sizeof(InData)/sizeof(double);i++)
46     {
47         OutData[i] = (InDta[i] - MinMax[0] + 1) / (MinMax[1] - MinMax[0] + 1);
48     }
49 }
50 //----Sigmoid函數
51 double Sigmoid(double t)
52 {
53     double sum;
54     sum = 1.0 / (1.0+exp(-t));
55     return sum;
56 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM