⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hw_02.cpp

📁 神经网络BP算法C程序
💻 CPP
字号:
#include "iostream.h"
#include "iomanip.h"
#include "stdlib.h"
#include "math.h"
#include "stdio.h"
#include "time.h"
#include "fstream.h"
#define N 128           //学习样本总数
#define L 2           //神经网络层数,包括隐层和输出层,但不包括输入层
#define IN 8          //样本维数(即输入层神经元个数--虚拟)
#define ON 1          //输出层神经元个数
int *N_L;             //用来存储各层神经元个数
double *w[L];         //存储各层的权值
double *mx[L];        //存储各层神经元的门限值
double *s[L];         //存储各层神经元的输入值
double *y[L];         //存储各层神经元的输出值
double err[N];        //N个样本的总误差
double P[IN];         //单个样本输入数据
double T[ON];         //单个样本教师数据
double *T_w[L];       //中间变量,用来存储各层权值惯性增量
double *T_mx[L];      //中间变量,用来存储各层神经元门限值的惯性增量
double *d_err[L];     //存储各层的一般化误差
double step;          //用来存储各层的学习步长
double T_step;        //惯性系数


//////////////////////////////////////////
////定义一个放学习样本及期望输出的结构////
//////////////////////////////////////////
struct Study_Data
{
	double input[IN];      //输入在上面定义是一个
	double teach[ON];      //输出在上面定义也是一个
}Study_Data[N];            //学习样本


////////////////////////////////////
////////输入各层神经元的个数////////
////////////////////////////////////
void input_n_w()
{
	int *p=new int[L];
	int i,t;
	cout<<"此神经网络共有 "<<L<<" 层---不包括输入层"<<endl;
	for(i=0;i<L-1;i++)
	{
		t=i+1;
		cout<<"输入第 "<<t<<" 隐层神经元个数:";
		cin>>p[i];
	}
	p[L-1]=ON;
	N_L=p;
}


////////////////////////////////////
////初始化各层的权值及阈值子程序////
////////////////////////////////////
void initial()
{
    int i,j,k;
	double *p;
	srand((unsigned)time(NULL));
	cout<<"初始化权值及门限值......"<<endl;
	p=new double[N_L[0]*IN];
    //初始化输入层到第一层之间的权值
	for(j=0;j<N_L[0];j++)
		for(i=0;i<IN;i++)
			//p[j*IN+i]=(double)((rand()/32767.0)*2-1)/4;
			p[j*IN+i]=(double)(rand()/32767.0);


    w[0]=p;
	//初始化第一层到输出层之间的权值
    for(k=1;k<L;k++)
	{
		p=new double[N_L[k]*N_L[k-1]];
		for(j=0;j<N_L[k];j++)
			for(i=0;i<N_L[k-1];i++)
				p[j*N_L[k-1]+i]=(double)((rand()/32767.0)*2-1)/4; 
		w[k]=p;
	}
	//初始化各层神经元的门限值
	for(i=0;i<L;i++)
	{
        p=new double[N_L[i]];
		for(j=0;j<N_L[i];j++)
			//p[j]=(double)((rand()/32767.0)*2-1)/4;
			p[j]=(double)(rand()/32767.0);
		mx[i]=p;
	}
	//为权值及门限值增量分配存储空间,并且初始化为零
	p=new double[N_L[0]*IN];
	for(j=0;j<N_L[0];j++)
		for(i=0;i<IN;i++)
			p[j*IN+i]=0;
    T_w[0]=p;
    for(k=1;k<L;k++)
	{
		p=new double[N_L[k]*N_L[k-1]];
		for(j=0;j<N_L[k];j++)
			for(i=0;i<N_L[k-1];i++)
				p[j*N_L[k-1]+i]=0; 
		T_w[k]=p;
	}
	for(i=0;i<L;i++)
	{
        p=new double[N_L[i]];
		for(j=0;j<N_L[i];j++)
			p[j]=0;
		T_mx[i]=p;
	}
	cout<<"初始化完毕"<<endl<<endl;
}//子程序initial()结束


////////////////////////////////
////第m个学习样本输入子程序/////
////////////////////////////////
void input_P(int m)
{
	int i;
	for (i=0;i<IN;i++)
		P[i]=Study_Data[m].input[i]; //获得第m个样本的数据
}//子程序input_P(m)结束


/////////////////////////////
////第m个样本教师信号子程序//
/////////////////////////////
void input_T(int m)
{
	int i;
	for (i=0;i<ON;i++)
		T[i]=Study_Data[m].teach[i];
}//子程序input_T(m)结束


//////////////////////////////////////
/////为用到的中间变量分配存储空间/////
//////////////////////////////////////
void allocate_space()
{
	int k;
	double *p,*p1,*p2;
	//分配存储各层神经元的输入和输出所需的空间
	for(k=0;k<L;k++)
	{
		p1=new double[N_L[k]];
		p2=new double[N_L[k]];
		s[k]=p1;
		y[k]=p2;
	}
	//分配存储各层神经元一般化误差所需的空间
	for(k=L-1;k>=0;k--)
	{
		p=new double[N_L[k]];
		d_err[k]=p;
	}
}//allocate_space()结束


/////////////////////////////////////
////求取各层神经元输入输出值子程序///
/////////////////////////////////////
void H_I_O()
{

	int i,j,k;
	double sigma;
	for (j=0;j<N_L[0];j++)
	{
		sigma=0.0;
		for (i=0;i<IN;i++)
			sigma+=(*(w[0]+j*IN+i))*P[i];        //求内积
        s[0][j]=sigma+(*(mx[0]+j));              //求输入
		y[0][j]=1.0/(1.0+exp(-s[0][j]));         //求输出siglon算法
	}
	//求取后续各层神经元的输入及输出值
	for(k=1;k<L;k++)
	{
		for (j=0;j<N_L[k];j++)
		{		
			sigma=0.0;
			for (i=0;i<N_L[k-1];i++)
				sigma+=(*(w[k]+j*N_L[k-1]+i))*(*(y[k-1]+i));         //求内积
			s[k][j]=sigma+(*(mx[k]+j));                              //求输入
			y[k][j]=1.0/(1.0+exp(-s[k][j]));                         //求输出siglon算法
		}
	}	
}//子程序H_I_O()结束


//////////////////////////////////////////
/////第一层至输出层的一般化误差子程序/////
//////////////////////////////////////////
void err_det(int m)                      //计算第m个样本的一般化误差
{
	double abs_err;                      //每个样本的绝对误差都是从0开始的
	double sqr_err=0;                    //每个样本的平方误差计算都是从0开始的
	int i,j,k;
	double sigma;
	//求取输出层的一般化误差
	for (k=0;k<N_L[L-1];k++)
	{
		abs_err=T[k]-(*(y[L-1]+k));      //求第m个样本下的第k个神经元的绝对误差
		sqr_err+=(abs_err)*(abs_err);    //求第m个样本下输出层的平方误差
		d_err[L-1][k]=abs_err*(*(y[L-1]+k))*(1.0-(*(y[L-1]+k)));  
		                                 //d_err[k]输出层各神经元的一般化误差
		//d_err[k]=abs_err[k]; //此处输出层用线性函数
	}
	err[m]=sqr_err/2;                    //第m个样本下输出层的平方误差/2=第m个样本的均方误差
	//求取输出层前一层到第一层的一般化误差
    for(i=L-2;i>=0;i--)
	{
		for (k=0;k<N_L[i];k++)
		{
			sigma=0.0;
			for(j=0;j<N_L[i+1];j++) 
			{
				sigma+=(*(d_err[i+1]+j))*(*(w[i+1]+j*N_L[i]+k)); 
			}
			d_err[i][k]=sigma*(*(y[i]+k))*(1-(*(y[i]+k)));//隐层各神经元的一般化误差
		}
	}
}//err_det(int m)结束


//////////////////////////////////////////////////////
/////输出层至第一层的权值调整、阈值调整计算子程序/////
//////////////////////////////////////////////////////
void W_New(int m)
{
	int i,j,k;
	//输出层的权值及门限值调整
	for(k=L-1;k>=1;k--)
	{
		for(j=0;j<N_L[k];j++)
		{
			for(i=0;i<N_L[k-1];i++)
			{
				(*(w[k]+j*N_L[k-1]+i))+=(step*(*(d_err[k]+j))*(*(y[k-1]+i))+(*(T_w[k]+j*N_L[k-1]+i)));
				*(T_w[k]+j*N_L[k-1]+i)=T_step*step*(*(d_err[k]+j))*(*(y[k-1]+i));      //惯性量
			}
			(*(mx[k]+j))+=(step*(*(d_err[k]+j))+(*(T_mx[k]+j)));
			*(T_mx[k]+j)=T_step*step*(*(d_err[k]+j));                                  //惯性量

		}
	}
	//第一层到输入层的权值及门限值调整
	for (j=0;j<N_L[0];j++)
	{
		for (i=0;i<IN;i++)
		{
			(*(w[0]+j*IN+i))+=(step*(*(d_err[0]+j))*P[i]+(*(T_w[0]+j*IN+i)));
			*(T_w[0]+j*IN+i)=step*(*(d_err[0]+j))*P[i];

		}
		(*(mx[0]+j))+=(step*(*(d_err[0]+j))+(*(T_mx[0]+j)));
		*(T_mx[0]+j)=step*(*(d_err[0]+j));

	}
}//子程序W_New()结束


/////////////////////////////////
//N个样本的全局误差计算子程序////
/////////////////////////////////
double Err_Sum()
{
	int m;
	double total_err=0;
	for (m=0;m<N;m++)
	{
		total_err+=err[m];         //每个样本的均方误差加起来就成了全局误差
	}
	return total_err;
}//子程序Err_sum()结束


///////////////////////////////////
///////////获取训练数据////////////
///////////////////////////////////
void GetTrainingData()
{
	int m;
	ifstream GetTrainingData ( "训练样本.txt", ios::in );
	cout<<endl<<"读取训练样本数据"<<endl;
	for(m=0;m<N;m++)
	{
		for(int i=0;i<IN;i++)
		{
			GetTrainingData>>Study_Data[m].input[i];     //取得输入数据
			cout<<Study_Data[m].input[i]<<" ";
		}
		for(int j=0;j<ON;j++)
		{
			GetTrainingData>>Study_Data[m].teach[j];     //取得输出数据
			cout<<Study_Data[m].teach[j]<<" ";
		}
		cout<<endl;
	}

	GetTrainingData.close();
}


///////////////////////////////////////
/////////保存训练后得到的权值//////////
///////////////////////////////////////
void save_w_mx()
{
	int i,j,k;
	ofstream outQuanFile( "权值.txt", ios::out );
	ofstream outMxFile( "门限值.txt", ios::out );
	int tt;
	//将从输出层到第一层的权值及门限值保存到文件中
	for(k=L-1;k>=1;k--)
	{
		tt=k+1;
		outQuanFile<<"第 "<<tt<<" 层的权值是:"<<endl;
		for(j=0;j<N_L[k];j++)
		{
			for(i=0;i<N_L[k-1];i++)
			{
				outQuanFile<<(*(w[k]+j*N_L[k-1]+i))<<"   ";
			}
			outQuanFile<<"\n";
		}
		outMxFile<<"第 "<<k+1<<" 层的门限值是:"<<endl;
		for(j=0;j<N_L[k];j++)
		{
			outMxFile<<-(*(mx[k]+j))<<"   ";
		}
		outMxFile<<"\n";
	}
	//将从第一层到输入层的权值及门限值保存到文件中
	outQuanFile<<"第 1"<<" 层的权值是:"<<endl;
	for(j=0;j<N_L[0];j++)
	{
		for(i=0;i<IN;i++)
		{
			outQuanFile<<(*(w[0]+j*IN+i))<<"   ";
		}
		outQuanFile<<"\n";
	}
	outMxFile<<"第 1"<<" 层的门限值是:"<<endl;
	for(j=0;j<N_L[0];j++)
	{
		outMxFile<<-(*(mx[0]+j))<<"   ";
	}
	outMxFile<<"\n";
}


//测试函数
void test()
{
	int i,j,k;
	double sigma;
	int m;
	//求取第一层神经元的输入及输出值
        cout<<"测试结果为:"<<endl;
	for(m=0;m<N;m++)
	{
		for (j=0;j<N_L[0];j++)
		{
			sigma=0.0;
			for(i=0;i<IN;i++)
				sigma+=(*(w[0]+j*IN+i))*Study_Data[m].input[i];//求内积
			(*(s[0]+j))=sigma+(*(mx[0]+j));      //求输入
			(*(y[0]+j))=1.0/(1.0+exp(-(*(s[0]+j))));  //求输出siglon算法
		}
		for(i=0;i<IN;i++)
			cout<<Study_Data[m].input[i]<<" ";

		//求取后续各层神经元的输入及输出值
		for(k=1;k<L;k++)
		{
			for (j=0;j<N_L[k];j++)
			{		
				sigma=0.0;
				for (i=0;i<N_L[k-1];i++)
				{
					sigma+=(*(w[k]+j*N_L[k-1]+i))*(*(y[k-1]+i));     //求内积
				}
				(*(s[k]+j))=sigma+(*(mx[k]+j));      //求输入
				(*(y[k]+j))=1.0/(1.0+exp(-(*(s[k]+j))));   //求输出siglon算法
			}
		}
		for(i=0;i<N_L[L-1];i++)
		{
			if((*(y[L-1]+i))<0.5)
				(*(y[L-1]+i))=0;
			else
				(*(y[L-1]+i))=1;
			cout<<"实际输出:"<<(*(y[L-1]+i))<<" "<<"理想输出:"<<Study_Data[m].teach[i]<<" ";
		}
		cout<<endl;
	}
}


///////////////////////////////////////////////////////////////////////
////////释放存储各层权值、门限值、输入、输出值及中间变量的空间/////////
///////////////////////////////////////////////////////////////////////
void space_delete()
{
	int i;
	for(i=0;i<L;i++)
	{
		delete [](w[i]);       //存储各层的权值
		delete [](mx[i]);      //存储各层神经元的门限值
		delete [](s[i]);       //存储各层神经元的输入值
		delete [](y[i]);       //存储各层神经元的输出值
		delete [](d_err[i]);   //存储各层的一般化误差
		delete [](T_w[i]);     //中间变量,用来存储各层权值的增量
		delete [](T_mx[i]);    //中间变量,用来存储各层神经元门限值的增量
	}
}//space_delete()结束

/**********************/
/**程序入口,即主程序**/
/**********************/
void main()
{
	double sum_err;
	int study;                 //训练次数
	int m;                     //代表样本次序
	step=0.4;                  //迭代步长
	T_step=0.4;                //惯性系数
	study=0;                   //学习次数
	double Pre_error ;         //预定误差
	Pre_error = 0.01;
	input_n_w();
	GetTrainingData();
	cout<<"训练数据读取完毕\n"<<endl;
	initial();                 //隐层、输出层权、阈值初始化
	allocate_space();          //分配内存空间
	do
	{
		++study; 
		for (m=0;m<N;m++)
		{
			input_P(m);        //输入第m个学习样本
			input_T(m);        //输入第m个样本的教师信号				
			H_I_O();			
            err_det(m);			
            W_New(m);						
		}                      //全部样本训练完毕
		sum_err=Err_Sum();     //全部样本全局误差计算
		if(study%1000==0)
		cout<<"第"<<study<<"次学习的均方误差为"<<sum_err<<endl;	
	}//while (sum_err > Pre_error);
	while (study<=50000); 
	cout<<"网络已经学习了"<<study<<"次,学习的均方误差为"<<sum_err<<endl;
	save_w_mx();
	cout<<"迭代学习步长为:"<<step<<endl;
	cout<<"惯性系数为:"<<T_step<<endl;
	test();                    //进行测试
	space_delete();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -