神经网络初步学习总结:(对神经网络的模型有一定的了解,如果从未接触有点看不懂)
第一点:以下是最简单的神经网络模型了
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 }