您的位置:首页 > 编程语言 > C语言/C++

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的运行结果,运算次数减少,误差变大。



#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐