📄 hw_02.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 + -