BP神經網絡加法運算

GitHub

1. 詳細理論過程見下: 
        - https://www.cnblogs.com/jzhlin/archive/2012/07/28/bp.html
        - https://www.cnblogs.com/jzhlin/archive/2012/07/30/bp_c.html
        - https://www.cnblogs.com/jzhlin/archive/2012/08/01/bp_c2.html

2. 個人推導如下:

 

3. 代碼如下[個人添加了詳細的解釋]: 

 

// neuron.cpp : 定義控制檯應用程序的入口點。
//

//#include "stdafx.h"
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>

#define Data  1000  	// 訓練樣本的數量
#define In 2			// 對於每個樣本有多少個輸入變量 
#define Out 1			// 對於每個樣本有多少個輸出變量
#define Neuron 5		// 神經元的數量 
#define TrainC 20000 	// 表示訓練的次數 
#define A  0.2			
#define B  0.4
#define a  0.2
#define b  0.3

// d_in[Data][In] 存儲 Data 個樣本,每個樣本的 In 個輸入
// d_out[Data][Out] 存儲 Data 個樣本,每個樣本的 Out 個輸出
double d_in[Data][In],d_out[Data][Out]; 
	
// w[Neuron][In]  表示某個輸入對某個神經元的權重 
// v[Out][Neuron] 來表示某個神經元對某個輸出的權重 
// 數組 o[Neuron] 記錄的是神經元通過激活函數對外的輸出 
// 與之對應的保存它們兩個修正量的數組 dw[Neuron][In] 和 dv[Out][Neuron] 
double w[Neuron][In],v[Out][Neuron],o[Neuron];
double dv[Out][Neuron],dw[Neuron][In];

// Data個數據中 加數、被加數、和 的最大,最小值 
double Maxin[In],Minin[In],Maxout[Out],Minout[Out];

// OutputData[Out]  存儲BP神經網絡的輸出 
double OutputData[Out];

// e用來監控誤差 
double e;

//生成實驗數據並存入相應文件中
void writeTest(){      
	FILE *fp1,*fp2;
	double r1,r2;
	int i;

	if((fp1=fopen("E:\\neuron\\in.txt","w"))==NULL){
		printf("can not open the in file\n");
		exit(0);
	}
	if((fp2=fopen("E:\\neuron\\out.txt","w"))==NULL){
		printf("can not open the out file\n");
		exit(0);
	}

	for(i=0;i<Data;i++){
		// 生成0~10的隨機小數 
		r1=rand()%1000/100.0;
		r2=rand()%1000/100.0; 
		// 寫入文件 
		fprintf(fp1,"%lf  %lf\n",r1,r2);
		fprintf(fp2,"%lf \n",r1+r2);
	}
	fclose(fp1);
	fclose(fp2);
}

// 讀入訓練數據 
void readData(){

	FILE *fp1,*fp2;
	int i,j;
	if((fp1=fopen("E:\\neuron\\in.txt","r"))==NULL){
		printf("can not open the in file\n");
		exit(0);
	}
	// 讀入數據到 d_in[Data][In] 
	for(i=0;i<Data;i++)
		for(j=0; j<In; j++)
			fscanf(fp1,"%lf",&d_in[i][j]);
	fclose(fp1);
	
	if((fp2=fopen("E:\\neuron\\out.txt","r"))==NULL){
		printf("can not open the out file\n");
		exit(0);
	}
	// 讀入數據到 d_in[Data][Out] 
	for(i=0;i<Data;i++)
		for(j=0; j<Out; j++)
			fscanf(fp1,"%lf",&d_out[i][j]);
	fclose(fp2);
}

/*
一方面是對讀取的訓練樣本數據進行歸一化處理,
歸一化處理就是指的就是將數據轉換成0~1之間; 
在BP神經網絡理論裏面,並沒有對這個進行要求,
不過實際實踐過程中,歸一化處理是不可或缺的。
因爲理論模型沒考慮到,BP神經網絡收斂的速率問題,
一般來說神經元的輸出對於0~1之間的數據非常敏感,歸一化能夠顯著提高訓練效率。
可以用以下公式來對其進行歸一化,
其中 加個常數A 是爲了防止出現 0 的情況(0不能爲分母)。
另一方面,就是對神經元的權重進行初始化了,
數據歸一到了(0~1)之間,
那麼權重初始化爲(-1~1)之間的數據,
另外對修正量賦值爲0 
*/ 
void initBPNework(){

	int i,j;

	for(i=0; i<In; i++){   //求Data個數據中 加數和被加數的最大、最小值。
		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++){     //求Data個數據中和的最大、最小值。
		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){	
			// rand()不需要參數,它會返回一個從0到最大隨機數的任意整數 
			// rand()/RAND_MAX 爲 (0, 1) 
			w[i][j]=rand()*2.0/RAND_MAX-1; // 權值初始化 
			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; // 權值初始化 
				dv[j][i]=0;
			}
}

void computO(int var){   //第var組數據在隱藏層和輸出層的輸出結果o[]和outputdata[]。

	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];
		//Sigmoid 函數---激活函數 
		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;
	}	
}

//從後向前更新權值;
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];
			
			/*
			 在具體實現對誤差修改中,我們再加上學習率,
			 並且對先前學習到的修正誤差量進行繼承,
			 直白的說就是都乘上一個0到1之間的數
			*/ 
			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];
		}
	}
}

double result(double var1,double var2)
{
	int i,j;
	double sum,y;

	var1=(var1-Minin[0]+1)/(Maxin[0]-Minin[0]+1);
	var2=(var2-Minin[1]+1)/(Maxin[1]-Minin[1]+1);

	for (i = 0; i < Neuron; ++i){
		sum=0;
		sum=w[i][0]*var1+w[i][1]*var2;
		o[i]=1/(1+exp(-1*sum));
	}
	sum=0;
	for (j = 0; j < Neuron; ++j)
		sum+=v[0][j]*o[j];

	return sum*(Maxout[0]-Minout[0]+1)+Minout[0]-1;  //返歸一化
}

void writeNeuron()
{
	FILE *fp1;
	int i,j;
	if((fp1=fopen("E:\\neuron\\neuron.txt","w"))==NULL)
	{
		printf("can not open the neuron file\n");
		exit(0);
	}
	for (i = 0; i < Neuron; ++i)	
		for (j = 0; j < In; ++j){
			fprintf(fp1,"%lf ",w[i][j]);
		}
	fprintf(fp1,"\n\n\n\n");

	for (i = 0; i < Neuron; ++i)	
		for (j = 0; j < Out; ++j){
			fprintf(fp1,"%lf ",v[j][i]);
		}

	fclose(fp1);
}


/*兩個輸入a、b(10以內的數),一個輸出 c,c=a+b。
換句話說就是教BP神經網絡加法運算 */
void  trainNetwork(){

	int i,c=0,j;
	do{
		e=0;
		for (i = 0; i < Data; ++i){
			computO(i);//計算隱藏層和輸出層所有神經元的輸出。
			
			for (j = 0; j < Out; ++j)
				e+=fabs((OutputData[j]-d_out[i][j])/d_out[i][j]);//fabs()對float,double求絕對值 
				
			backUpdate(i);//反向修改權值
		}
		printf("%d  %lf\n",c,e/Data);
		c++;
	}while(c<TrainC && e/Data>0.01);//一直訓練到規定次數或平均誤差小於0.01時結束。
}

//int _tmain(int argc, _TCHAR* argv[])
int main(int argc, char* argv[])
{
	writeTest();//隨機生成Data個數據,每個數據包括兩個個位數以及這兩個數之和。
	readData();//準備輸入,輸出訓練數據。
	initBPNework();//輸入、輸出數據歸一化,以及網絡權值初始化。
	trainNetwork();//訓練網絡。
	printf("%lf \n",result(6,8) );
	printf("%lf \n",result(2.1,7) );
	printf("%lf \n",result(4.3,8) );
	writeNeuron();//保存權值。
	getchar();
	return 0;

}

4. 運行結果:

0  0.173932
1  0.035688
2  0.032719
3  0.030155
4  0.028081
5  0.026383
6  0.024991
7  0.023832
8  0.022865
9  0.022047
10  0.021344
11  0.020732
12  0.020197
13  0.019727
14  0.019310
15  0.018938
16  0.018602
17  0.018296
18  0.018017
19  0.017761
20  0.017524
21  0.017303
22  0.017097
23  0.016904
24  0.016723
25  0.016553
26  0.016392
27  0.016240
28  0.016095
29  0.015957
30  0.015826
31  0.015700
32  0.015580
33  0.015464
34  0.015353
35  0.015245
36  0.015142
37  0.015041
38  0.014944
39  0.014850
40  0.014758
41  0.014669
42  0.014583
43  0.014499
44  0.014417
45  0.014337
46  0.014259
47  0.014182
48  0.014108
49  0.014035
50  0.013963
51  0.013893
52  0.013825
53  0.013757
54  0.013691
55  0.013627
56  0.013563
57  0.013501
58  0.013439
59  0.013379
60  0.013320
61  0.013261
62  0.013204
63  0.013148
64  0.013092
65  0.013037
66  0.012984
67  0.012931
68  0.012878
69  0.012827
70  0.012776
71  0.012726
72  0.012677
73  0.012628
74  0.012580
75  0.012533
76  0.012486
77  0.012440
78  0.012394
79  0.012350
80  0.012305
81  0.012261
82  0.012218
83  0.012176
84  0.012133
85  0.012092
86  0.012051
87  0.012010
88  0.011970
89  0.011930
90  0.011891
91  0.011852
92  0.011814
93  0.011776
94  0.011739
95  0.011702
96  0.011665
97  0.011629
98  0.011593
99  0.011558
100  0.011522
101  0.011488
102  0.011453
103  0.011419
104  0.011386
105  0.011353
106  0.011320
107  0.011287
108  0.011255
109  0.011223
110  0.011191
111  0.011160
112  0.011129
113  0.011098
114  0.011067
115  0.011037
116  0.011007
117  0.010978
118  0.010949
119  0.010920
120  0.010891
121  0.010862
122  0.010834
123  0.010806
124  0.010778
125  0.010751
126  0.010724
127  0.010697
128  0.010670
129  0.010644
130  0.010617
131  0.010591
132  0.010566
133  0.010540
134  0.010515
135  0.010489
136  0.010464
137  0.010440
138  0.010415
139  0.010391
140  0.010367
141  0.010343
142  0.010319
143  0.010296
144  0.010273
145  0.010249
146  0.010227
147  0.010204
148  0.010181
149  0.010159
150  0.010137
151  0.010115
152  0.010093
153  0.010071
154  0.010049
155  0.010028
156  0.010007
157  0.009986
14.033821
9.143061
12.349715
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章