C++实现BP算法_单隐层_异或(可模拟各种函数并验证)_智能计算作业2.1
2014-12-13 20:05
489 查看
报告:
1、 题目:
建立一个含单隐层的双输入单输出网络,实现异或问题:
x1(1)=0 x2(1)=1 d(1)=1
x1(2)=1 x2(2)=0 d(2)=1
x1(3)=1 x2(3)=1 d(3)=0
x1(4)=0 x2(4)=0 d(4)=0
训练出相应的网络权值矩阵W。
2、 实现步骤:
①初始化:设定wji(0), wkj(0) ,函数采用Sigmoid()函数, y=1/(1+exp(-x)), y在(0,1)之间.设计一个“合理的网络结构”,隐层数为1 ,隐层节点为2;
②对每个输入样本进行如下计算:
a 前向信号传播
b 反向误差传播
③n=n+1, 转入下一个计算周期。
3、 核心代码及说明:
参数说明:
innode
//输入结点数
hidenode
//隐含结点数
outnode
//输出结点数
trainsample
//BP训练样本数
double w[innode][hidenode];//隐含结点权值
double w1[hidenode][outnode];//输出结点权值
double rate_w;
//权值学习率(输入层-隐含层)
double rate_w1;//权值学习率 (隐含层-输出层)
double e;//误差计算
double error;//允许的最大误差
double pp[hidenode];//隐含结点的校正误差
double qq[outnode];//希望输出值与实际输出值的偏差
double yd[outnode];//希望输出值
double x[innode];//输入向量
double x1[hidenode];//隐含结点状态值
double x2[outnode];//输出结点状态值
//输入样本
double X[trainsample][innode]= {
{-1,0,1},{-1,1,0},{-1,1,1},{-1,0,0} };
//期望输出样本
double Y[trainsample][outnode]={
{1},{1},{0},{0} };
训练部分:
for(int isamp=0;isamp<trainsample;isamp++)//循环训练一次样品
{
/////////输入层到隐层
for(int j=0;j<hidenode;j++)
{
o1[j]=0.0;
for(int i=0;i<innode;i++)
o1[j]=o1[j]+w[i][j]*x[i];//隐含层各单元输入激活值
x1[j]=1.0/(1+exp(-o1[j]));//x1[j]=1.0/(1+exp(-o1[j]-b1[j]));//隐含层各单元的输出
}
/////////////隐层到输出层
for(int k=0;k<outnode;k++)
{
o2[k]=0.0;
for(int j=0;j<hidenode;j++)
o2[k]=o2[k]+w1[j][k]*x1[j];
//输出层各单元输入激活值
x2[k]=1.0/(1.0+exp(-o2[k]));
//输出层各单元输出
}
//////////////////计算偏差并调整权值
for(int k=0;k<outnode;k++)
{
qq[k]=(yd[k]-x2[k])*x2[k]*(1-x2[k]);
//希望输出与实际输出的偏差
for(int j=0;j<hidenode;j++)
w1[j][k]+=rate_w1*qq[k]*x1[j];
//下一次的隐含层和输出层之间的权值
}
for(int j=0;j<hidenode;j++)
{
pp[j]=0.0;
for(int k=0;k<outnode;k++)
pp[j]=pp[j]+qq[k]*w1[j][k];
pp[j]=pp[j]*x1[j]*(1-x1[j]);
//隐含层的校正误差
for(int i=0;i<innode;i++)
w[i][j]+=rate_w*pp[j]*x[i];
//下一次的输入层和隐含层之间的新连接权值
}
for(int k=0;k<outnode;k++)
{
e+=fabs(yd[k]-x2[k])*fabs(yd[k]-x2[k]);
//计算均方差
}
error=e/2.0;
}
}
4、 运算结果:
(1)隐层节点数为2,满足允许误差0.01的运行结果,得到了矩阵w1和w,及迭代次数和误差,并经行验证,验证结果正确。运算次数较多,误差较小。
(2)隐层节点数为2,满足允许误差0.1的运行结果,运算次数减少,误差变大。
1、 题目:
建立一个含单隐层的双输入单输出网络,实现异或问题:
x1(1)=0 x2(1)=1 d(1)=1
x1(2)=1 x2(2)=0 d(2)=1
x1(3)=1 x2(3)=1 d(3)=0
x1(4)=0 x2(4)=0 d(4)=0
训练出相应的网络权值矩阵W。
2、 实现步骤:
①初始化:设定wji(0), wkj(0) ,函数采用Sigmoid()函数, y=1/(1+exp(-x)), y在(0,1)之间.设计一个“合理的网络结构”,隐层数为1 ,隐层节点为2;
②对每个输入样本进行如下计算:
a 前向信号传播
b 反向误差传播
③n=n+1, 转入下一个计算周期。
3、 核心代码及说明:
参数说明:
innode
//输入结点数
hidenode
//隐含结点数
outnode
//输出结点数
trainsample
//BP训练样本数
double w[innode][hidenode];//隐含结点权值
double w1[hidenode][outnode];//输出结点权值
double rate_w;
//权值学习率(输入层-隐含层)
double rate_w1;//权值学习率 (隐含层-输出层)
double e;//误差计算
double error;//允许的最大误差
double pp[hidenode];//隐含结点的校正误差
double qq[outnode];//希望输出值与实际输出值的偏差
double yd[outnode];//希望输出值
double x[innode];//输入向量
double x1[hidenode];//隐含结点状态值
double x2[outnode];//输出结点状态值
//输入样本
double X[trainsample][innode]= {
{-1,0,1},{-1,1,0},{-1,1,1},{-1,0,0} };
//期望输出样本
double Y[trainsample][outnode]={
{1},{1},{0},{0} };
训练部分:
for(int isamp=0;isamp<trainsample;isamp++)//循环训练一次样品
{
/////////输入层到隐层
for(int j=0;j<hidenode;j++)
{
o1[j]=0.0;
for(int i=0;i<innode;i++)
o1[j]=o1[j]+w[i][j]*x[i];//隐含层各单元输入激活值
x1[j]=1.0/(1+exp(-o1[j]));//x1[j]=1.0/(1+exp(-o1[j]-b1[j]));//隐含层各单元的输出
}
/////////////隐层到输出层
for(int k=0;k<outnode;k++)
{
o2[k]=0.0;
for(int j=0;j<hidenode;j++)
o2[k]=o2[k]+w1[j][k]*x1[j];
//输出层各单元输入激活值
x2[k]=1.0/(1.0+exp(-o2[k]));
//输出层各单元输出
}
//////////////////计算偏差并调整权值
for(int k=0;k<outnode;k++)
{
qq[k]=(yd[k]-x2[k])*x2[k]*(1-x2[k]);
//希望输出与实际输出的偏差
for(int j=0;j<hidenode;j++)
w1[j][k]+=rate_w1*qq[k]*x1[j];
//下一次的隐含层和输出层之间的权值
}
for(int j=0;j<hidenode;j++)
{
pp[j]=0.0;
for(int k=0;k<outnode;k++)
pp[j]=pp[j]+qq[k]*w1[j][k];
pp[j]=pp[j]*x1[j]*(1-x1[j]);
//隐含层的校正误差
for(int i=0;i<innode;i++)
w[i][j]+=rate_w*pp[j]*x[i];
//下一次的输入层和隐含层之间的新连接权值
}
for(int k=0;k<outnode;k++)
{
e+=fabs(yd[k]-x2[k])*fabs(yd[k]-x2[k]);
//计算均方差
}
error=e/2.0;
}
}
4、 运算结果:
(1)隐层节点数为2,满足允许误差0.01的运行结果,得到了矩阵w1和w,及迭代次数和误差,并经行验证,验证结果正确。运算次数较多,误差较小。
(2)隐层节点数为2,满足允许误差0.1的运行结果,运算次数减少,误差变大。
#include<iostream> #include<cmath> using namespace std; #define innode 2 //输入结点数 #define hidenode 3//隐含结点数 #define outnode 1 //输出结点数 #define trainsample 4//BP训练样本数 class BpNet { public: void train(double p[trainsample][innode ],double t[trainsample][outnode]);//Bp训练 double p[trainsample][innode]; //输入的样本 double t[trainsample][outnode]; //样本要输出的 double *recognize(double *p);//Bp识别 void writetrain(); //写训练完的权值 void readtrain(); //读训练好的权值,这使的不用每次去训练了,只要把训练最好的权值存下来就OK BpNet(); virtual ~BpNet(); public: void init(); double w[innode][hidenode];//隐含结点权值 double w1[hidenode][outnode];//输出结点权值 double rate_w; //权值学习率(输入层-隐含层) double rate_w1;//权值学习率 (隐含层-输出层) double e;//误差计算 double error;//允许的最大误差 double result[outnode];// Bp输出 }; BpNet::BpNet() { error=0.1; e=0.0; rate_w=0.9; //权值学习率(输入层--隐含层) rate_w1=0.9; //权值学习率 (隐含层--输出层) } BpNet::~BpNet() { } void winit(double w[],int n) //权值初始化 { for(int i=0;i<n;i++) w[i]= (rand()%10)*0.1-0.5; } void BpNet::init() { winit((double*)w,innode*hidenode); winit((double*)w1,hidenode*outnode); } void BpNet::train(double p[trainsample][innode],double t[trainsample][outnode]) { double pp[hidenode];//隐含结点的校正误差 double qq[outnode];//希望输出值与实际输出值的偏差 double yd[outnode];//希望输出值 double x[innode]; //输入向量 double x1[hidenode];//隐含结点状态值 double x2[outnode];//输出结点状态值 double o1[hidenode];//隐含层激活值 double o2[outnode];//输出层激活值 for(int isamp=0;isamp<trainsample;isamp++)//循环训练一次样品 { for(int i=0;i<innode;i++) x[i]=p[isamp][i]; //输入的样本 for(int i=0;i<outnode;i++) yd[i]=t[isamp][i]; //期望输出的样本 //构造每个样品的输入和输出标准 //输入层到隐层 for(int j=0;j<hidenode;j++) { o1[j]=0.0; for(int i=0;i<innode;i++) o1[j]=o1[j]+w[i][j]*x[i];//隐含层各单元输入激活值 x1[j]=1.0/(1+exp(-o1[j]));// x1[j]=1.0/(1+exp(-o1[j]-b1[j]));//隐含层各单元的输出 // if(o1[j]+b1[j]>0) x1[j]=1; //else x1[j]=0; } //隐层到输出层 for(int k=0;k<outnode;k++) { o2[k]=0.0; for(int j=0;j<hidenode;j++) o2[k]=o2[k]+w1[j][k]*x1[j]; //输出层各单元输入激活值 x2[k]=1.0/(1.0+exp(-o2[k])); //输出层各单元输出 } for(int k=0;k<outnode;k++) { qq[k]=(yd[k]-x2[k])*x2[k]*(1-x2[k]); //希望输出与实际输出的偏差 for(int j=0;j<hidenode;j++) w1[j][k]+=rate_w1*qq[k]*x1[j]; //下一次的隐含层和输出层之间的新连接权 } for(int j=0;j<hidenode;j++) { pp[j]=0.0; for(int k=0;k<outnode;k++) pp[j]=pp[j]+qq[k]*w1[j][k]; pp[j]=pp[j]*x1[j]*(1-x1[j]); //隐含层的校正误差 for(int i=0;i<innode;i++) w[i][j]+=rate_w*pp[j]*x[i]; //下一次的输入层和隐含层之间的新连接权 } for(int k=0;k<outnode;k++) { e+=fabs(yd[k]-x2[k])*fabs(yd[k]-x2[k]); //计算均方差 } error=e/2.0; } } double *BpNet::recognize(double *p) { double x[innode]; //输入向量 double x1[hidenode]; //隐含结点状态值 double x2[outnode]; //输出结点状态值 double o1[hidenode]; //隐含层激活值 double o2[hidenode]; //输出层激活值 for(int i=0;i<innode;i++) x[i]=p[i]; for(int j=0;j<hidenode;j++) { o1[j]=0.0; for(int i=0;i<innode;i++) o1[j]=o1[j]+w[i][j]*x[i]; //隐含层各单元激活值 x1[j]=1.0/(1+exp(-o1[j]));//x1[j]=1.0/(1.0+exp(-o1[j]-b1[j])); //隐含层各单元输出 } for(int k=0;k<outnode;k++) { o2[k]=0.0; for(int j=0;j<hidenode;j++) o2[k]=o2[k]+w1[j][k]*x1[j];//输出层各单元激活值 x2[k]=1.0/(1.0+exp(-o2[k])); // x2[k]=1.0/(1.0+exp(-o2[k]-b2[k]));//输出层各单元输出 } for(int k=0;k<outnode;k++) { result[k]=x2[k]; } return result; } void BpNet::writetrain() { FILE *stream0; FILE *stream1; int i,j; //隐含结点权值写入 if(( stream0 = fopen("w.txt", "w+" ))==NULL) { cout<<"创建文件失败!"; exit(1); } for(i=0;i<innode;i++) { for(j=0;j<hidenode;j++) { fprintf(stream0, "%f\n", w[i][j]); } } fclose(stream0); //输出结点权值写入 if(( stream1 = fopen("w1.txt", "w+" ))==NULL) { cout<<"创建文件失败!"; exit(1); } for(i=0;i<hidenode;i++) { for(j=0;j<outnode;j++) { fprintf(stream1, "%f\n",w1[i][j]); } } fclose(stream1); } void BpNet::readtrain() { FILE *stream0; FILE *stream1; int i,j; //隐含结点权值读出 if(( stream0 = fopen("w.txt", "r" ))==NULL) { cout<<"打开文件失败!"; exit(1); } float wx[innode][hidenode]; for(i=0;i<innode;i++) { for(j=0;j<hidenode;j++) { fscanf(stream0, "%f", &wx[i][j]); w[i][j]=wx[i][j]; } } fclose(stream0); //输出结点权值读出 if(( stream1 = fopen("w1.txt", "r" ))==NULL) { cout<<"打开文件失败!"; exit(1); } float wx1[hidenode][outnode]; for(i=0;i<hidenode;i++) { for(j=0;j<outnode;j++) { fscanf(stream1, "%f", &wx1[i][j]); w1[i][j]=wx1[i][j]; } } fclose(stream1); }
//输入样本 可改变,以实现不同函数的模拟 double X[trainsample][innode]= { {0,1},{1,0},{1,1,},{0,0} }; //期望输出样本 double Y[trainsample][outnode]={ {1},{1},{0},{0} }; int main() { BpNet bp; bp.init(); int times=0; while(bp.error>0.01) { bp.e=0.0; times++; bp.train(X,Y); cout<<"Times="<<times<<" error="<<bp.error<<endl; } cout<<"trainning complete..."<<endl; bp.writetrain(); bp.readtrain(); double m[innode]={1,1}; double *r=bp.recognize(m); for(int i=0;i<innode;++i) cout<<m[i]; cout<<"的训练结果为"; for(int i=0;i<outnode;++i) cout<<bp.result[i]<<" "; double cha[trainsample][outnode]; double mi=100; double index; for(int i=0;i<trainsample;i++) { for(int j=0;j<outnode;j++) { //找差值最小的那个样本 cha[i][j]=(double)(fabs(Y[i][j]-bp.result[j])); if(cha[i][j]<mi) { mi=cha[i][j]; index=Y[i][j]; //得到对应的期望输出 } } } cout<<" 期望输出为 "<<index<<endl; cout<<endl; return 0; }
相关文章推荐
- C++实现BP算法实现正弦函数模拟_智能计算作业2.2
- C++实现单层感知器网络_智能计算作业1
- C++实现基于离散Hopfield神经网络噪声数字的识别_智能计算作业三
- C++实现BP 神经网络模拟二维机械臂运动_智能计算期末2
- C++实现BP 神经网络两类图形分辨出来_智能计算期末1
- 第四次程序设计作业 C++计算器计算及命令行的使用 前缀表达式方法实现
- 用C++编写递归函数GetPower(int x,int y)计算x的y次幂,在同一程序里中针对整型和实型实现两个重载的函数;在主程序中实现输入输出
- Linux-C基础知识学习:C语言作业-将5个学生成绩保存在一个数组中,单独实现一个计算平均成绩的average函数, 在main函数中获取该函数返回的平均值,并打印。
- C++ 智能指针的模拟实现实例
- 第四次程序设计作业 C++计算器计算及命令行的使用 前缀表达式方法实现
- C/C++函数参数的入栈顺序,计算顺序和可变参数的实现
- C/C++函数参数的入栈顺序,计算顺序和可变参数的实现
- 价层电子对互斥理论的模拟验证(C++实现)
- c++第三次上机作业-计算分段函数
- c++使用sendinput函数实现模拟键盘按键操作
- C++智能指针(二)模拟实现三种智能指针
- C++智能指针(二):模拟实现三种智能指针
- 【C++】智能指针的作用,模拟实现auto_ptr,scoped_ptr,shared_ptr,scoped_array,shared_array
- C/C++函数参数的入栈顺序,计算顺序和可变参数的实现
- 简单模拟实现c++智能指针-指针移交控制权