神經網絡初步學習總結:(對神經網絡的模型有一定的了解,如果從未接觸有點看不懂)
第一點:以下是最簡單的神經網絡模型了
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,參考了網上程序,但是基本都是有漏洞,可能沒下載到好的程序吧,結合了部分網上歷程還有一本書《神經網絡在應用科學和工程中的應用-----從基本原理到復雜的模式識別》。我弄了一個星期,就是由於公式編寫成代碼出現很多問題,多細心一點可以減少很多未知的錯誤!!!
注意:看了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 }