#include<iostream>
#include<cmath>
#include<fstream>
using namespace std;
#define innode 9 //输入结点数
#define hidenode 10//隐含结点数
#define sample 8//BP样本数
double allow_e=0.001;//允许误差
class BpNet
{
public:
void train(double p[sample][innode ],double t[sample]);//Bp训练
double p[sample][innode]; //输入的样本
double t[sample]; //样本要输出的
double test(double *p);//Bp识别
BpNet();
virtual ~BpNet();
public:
void init();
double w1[innode][hidenode];//隐含结点权值
double w2[hidenode];//输出结点权值
double rate_w1; //权值学习率(输入层-隐含层)
double rate_w2;//权值学习率 (隐含层-输出层)
double e;//单个样本误差计算
double error;//误差均值
double result;// Bp输出
};
BpNet::BpNet()
{
error=0.1;
e=0.0;
rate_w1=0.6; //权值学习率(输入层--隐含层)
rate_w2=0.6; //权值学习率 (隐含层--输出层)
}
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*)w1,innode*hidenode);
winit((double*)w2,hidenode);
}
void BpNet::train(double p[sample][innode],double t[sample])
{
double pp[hidenode];//隐含结点的校正误差
double qq;//希望输出值与实际输出值的偏差
double yd;//希望输出值
double x[innode]; //输入向量
double x1[hidenode];//隐含结点状态值
double x2;//输出结点状态值
double o1[hidenode];//隐含层激活值
double o2;//输出层激活值
for(int isamp=0;isamp<sample;isamp++)//循环训练一次样品
{
for(int i=0;i<innode;i++)
x[i]=p[isamp][i]; //输入的样本
yd=t[isamp]; //期望输出的样本
//构造每个样品的输入和输出标准
///输入层到隐层
for(int j=0;j<hidenode;j++)
{
o1[j]=0.0;
for(int i=0;i<innode;i++)
o1[j]=o1[j]+w1[i][j]*x[i];//隐含层各单元输入激活值
x1[j]=1.0/(1+exp(-o1[j]));//隐含层各单元的输出
}
///隐层到输出层
o2=0.0;
for(int j=0;j<hidenode;j++)
o2=o2+w2[j]*x1[j];
x2=1.0/(1.0+exp(-o2)); //输出层各单元输出
/计算偏差并调整权值
qq=(yd-x2)*x2*(1-x2); //希望输出与实际输出的偏差
for(int j=0;j<hidenode;j++)
w2[j]+=rate_w2*qq*x1[j]; //下一次的隐含层和输出层之间的新连接权
for(int j=0;j<hidenode;j++)
{
pp[j]=0.0;
pp[j]=pp[j]+qq*w2[j];
pp[j]=pp[j]*x1[j]*(1-x1[j]); //隐含层的校正误差
for(int i=0;i<innode;i++)
w1[i][j]+=rate_w1*pp[j]*x[i]; //下一次的输入层和隐含层之间的新连接权
}
e+=fabs(yd-x2)*fabs(yd-x2)/2;
}
error=double(e/double(sample));//计算误差均值
}
double BpNet::test(double *p)
{
double x[innode]; //输入向量
double x1[hidenode]; //隐含结点状态值
double x2; //输出结点状态值
double o1[hidenode]; //隐含层激活值
double o2; //输出层激活值
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]+w1[i][j]*x[i]; //隐含层各单元激活值
x1[j]=1.0/(1+exp(-o1[j]));//x1[j]=1.0/(1.0+exp(-o1[j]-b1[j])); //隐含层各单元输出
}
o2=0.0;
for(int j=0;j<hidenode;j++)
o2=o2+w2[j]*x1[j];//输出层各单元激活值
x2=1.0/(1.0+exp(-o2)); // x2[k]=1.0/(1.0+exp(-o2[k]-b2[k]));//输出层各单元输出
result=x2;
return result;
}
//输入样本 可改变,以实现不同函数的模拟
double X[sample][innode]= {
{1,1,1,-1,1,-1,-1,1,-1},
{1,-1,-1,1,1,1,1,-1,-1},
{-1,1,-1,-1,1,-1,1,1,1},
{-1,-1,1,1,1,1,-1,-1,1},
{1,-1,-1,1,-1,-1,1,1,1},
{-1,-1,1,-1,-1,1,1,1,1},
{1,1,1,-1,-1,1,-1,-1,1},
{1,1,1,1,-1,-1,1,-1,-1}
};
//期望输出样本
double Y[sample]={1,1,1,1,0,0,0,0};
int main()
{
BpNet bp;
bp.init();
int times=0;
ofstream out("error.txt");
ofstream Result("result.txt");
进行训练,直到误差小于等于allow_e
while(bp.error>allow_e)
{
bp.e=0.0;
times++;
bp.train(X,Y);
cout<<"Times="<<times<<" error="<<bp.error<<endl;
out << bp.error<< endl;
}
out.close( );
cout<<"trainning complete..."<<endl;
进行验证
for(int k=0;k<sample;k++)
{
double r=bp.test(X[k]);
for(int i=0;i<innode;++i)
{
if(X[k][i]==1)
cout<<"* ";
if(X[k][i]==-1)
cout<<" ";
if((i+1)%3==0)
cout<<endl;
}
cout<<"的训练结果为";
cout<<bp.result<<" ";
Result<<bp.result<<endl;
double cha[sample];
double mi=100;
double index;
for(int i=0;i<sample;i++)
{
//找差值最小的那个样本
cha[i]=(double)(fabs(Y[i]-bp.result));
if(cha[i]<mi)
{
mi=cha[i];
index=Y[i]; //得到对应的期望输出
}
}
cout<<" 期望输出为 "<<index<<endl;
cout<<"-------------------------------------"<<endl;
}
return 0;
}
C++实现BP 神经网络两类图形分辨出来
最新推荐文章于 2024-01-09 16:36:28 发布