BP神经网络算法基础学习知识原理.docx
《BP神经网络算法基础学习知识原理.docx》由会员分享,可在线阅读,更多相关《BP神经网络算法基础学习知识原理.docx(18页珍藏版)》请在冰豆网上搜索。
BP神经网络算法基础学习知识原理
BP网络模型处理信息的基本原理是:
输入信号Xi通过中间节点(隐层点)作用于输出节点,经过非线形变换,产生输出信号Yk,网络训练的每个样本包括输入向量X和期望输出量t,网络输出值Y与期望输出值t之间的偏差,通过调整输入节点与隐层节点的联接强度取值Wij和隐层节点与输出节点之间的联接强度Tjk以及阈值,使误差沿梯度方向下降,经过反复学习训练,确定与最小误差相对应的网络参数(权值和阈值),训练即告停止。
此时经过训练的神经网络即能对类似样本的输入信息,自行处理输出误差最小的经过非线形转换的信息。
一BP神经网络模型
BP网络模型包括其输入输出模型、作用函数模型、误差计算模型和自学习模型。
(1)节点输出模型
隐节点输出模型:
Oj=f(∑Wij×Xi-qj)
(1)
输出节点输出模型:
Yk=f(∑Tjk×Oj-qk)
(2)
f-非线形作用函数;q-神经单元阈值。
(2)作用函数模型
作用函数是反映下层输入对上层节点刺激脉冲强度的函数又称刺激函数,一般取为(0,1)内连续取值Sigmoid函数:
f(x)=1/(1+e-x) (3)
(3)误差计算模型
误差计算模型是反映神经网络期望输出与计算输出之间误差大小的函数:
Ep=1/2×∑(tpi-Opi)2 (4)
tpi-i节点的期望输出值;Opi-i节点计算输出值。
(4)自学习模型
神经网络的学习过程,即连接下层节点和上层节点之间的权重拒阵Wij的设定和误差修正过程。
BP网络有师学习方式-需要设定期望值和无师学习方式-只需输入模式之分。
自学习模型为
△Wij(n+1)=h×Фi×Oj+a×△Wij(n)(5)
h-学习因子;Фi-输出节点i的计算误差;Oj-输出节点j的计算输出;a-动量因子。
二BP网络模型的缺陷分析及优化策略
(1)学习因子h的优化
采用变步长法根据输出误差大小自动调整学习因子,来减少迭代次数和加快收敛速度。
h=h+a×(Ep(n)-Ep(n-1))/Ep(n)a为调整步长,0~1之间取值(6)
(2)隐层节点数的优化
隐节点数的多少对网络性能的影响较大,当隐节点数太多时,会导致网络学习时间过长,甚至不能收敛;而当隐节点数过小时,网络的容错能力差。
利用逐步回归分析法并进行参数的显著性检验来动态删除一些线形相关的隐节点,节点删除标准:
当由该节点出发指向下一层节点的所有权值和阈值均落于死区(通常取±0.1、±0.05等区间)之中,则该节点可删除。
最佳隐节点数L可参考下面公式计算:
L=(m+n)1/2+c(7)
m-输入节点数;n-输出节点数;c-介于1~10的常数。
(3)输入和输出神经元的确定
利用多元回归分析法对神经网络的输入参数进行处理,删除相关性强的输入参数,来减少输入节点数。
(4)算法优化
由于BP算法采用的是剃度下降法,因而易陷于局部最小并且训练时间较长。
用基于生物免疫机制地既能全局搜索又能避免未成熟收敛的免疫遗传算法IGA取代传统BP算法来克服此缺点。
该程序实现神经网络的BP算法,输入节点数,输出节点数,隐层数,隐层节点数任意,由用户决定。
其中隐层数指的是总共曾数包含输出层,比如说异或算法为2层,第一层节点数为2,第二层也即输出层节点数为1,输入点数为2。
但是该程序对异或算法实现并不理想,对多层多节点的神经网络有较好的结果。
#include"iostream.h"
#include
#include
#include
#include
#include"stdio.h"
#defineMAXCOUNT1e5//迭代训练次数上限
//精度0.001的随机浮点数,范围在-0.5——0.5
floatrandf()
{
return(float)((rand()%1001)*0.001f-0.5);
}
//高斯随机数产生函数
doublegaussrand()
{ staticdoubleV1,V2,S;
staticintphase=0;
doubleX;
if(phase==0){
do{
doubleU1=(double)rand()/RAND_MAX;
doubleU2=(double)rand()/RAND_MAX;
V1=2*U1-1;
V2=2*U2-1;
S=V1*V1+V2*V2;
}while(S>=1||S==0);
X=V1*sqrt(-2*log(S)/S);
}else
X=V2*sqrt(-2*log(S)/S);
phase=1-phase;
returnX;
}
//定义一个多层前向BP网络
classBP
{public:
double***p;//记录所有的权值
double***ddp;//记录所有的权值增量
int*pnode;//记录每一层的节点数
double**pnodey;//记录每组每一层的节点的输出值
double**ddlj;//记录每组每一层的节点的ddlj
double**pX;//记录输入样本
double**pY;//记录输入理想输出值
intSidenum;
intInputnodenum;
intoutputnodenum;
intyangbenzushu;
BP()
{Sidenum=0;
Inputnodenum=0;
outputnodenum=0;
yangbenzushu=0;}
~BP()
{
for(intm=0;m{
for(intn=0;n {delete[]p[m][n];
delete[]ddp[m][n];}
delete[]p[m];
delete[]ddp[m];
}
delete[]p;
delete[]ddp;
p=NULL;
ddp=NULL;
if(p==NULL)
delete[]pnode;
for(intM=0;M{delete[]pnodey[M];
delete[]ddlj[M];
}
delete[]pnodey;
delete[]ddlj;
pnodey=NULL;
ddlj=NULL;
}
//完成所有权值的初始化
voidgetW(intsidenum,intinputnodenum,intoutputnodenum1,intyangbenzu)
{ Sidenum=sidenum;
yangbenzushu=yangbenzu;
Inputnodenum=inputnodenum;
outputnodenum=outputnodenum1;
p=newdouble**[sidenum];
ddp=newdouble**[sidenum];
pnode=newint[sidenum+1];//包含输入层输出层每一层的节点数
for(inti=0;i{
intdata=0;
cout<<"请输入第"<
cin>>data;
pnode[i]=data;
}
for(intj=0;j{ p[j]=newdouble*[pnode[j+1]];
ddp[j]=newdouble*[pnode[j+1]];
for(intk=0;k { ddp[j][k]=newdouble[pnode[j]+1];
p[j][k]=newdouble[pnode[j]+1];
for(intt=0;t {ddp[j][k][t]=0;//每一层的权值初始化为0
if(t==0)p[j][k][t]=-fabs(randf());//每一层的阀值初始化
elsep[j][k][t]=randf();//每一层的权值初始化
}
}
}
//为记录每一层的节点的输出值和ddlj的指针开辟内存
pnodey=newdouble*[Sidenum];
ddlj=newdouble*[Sidenum];
for(intp=0;p{
pnodey[p]=newdouble[pnode[p+1]+1];
ddlj[p]=newdouble[pnode[p+1]];
pnodey[p][0]=1;//每组每层的首值为1
}
}
/**********************/
//每个节点输出函数
doublefas(doubles)
{doublet;
t=1.0/(exp(-s)+1);
returnt;
}
/************************************************/
//该函数用来记录样本值和理想输出值
voidINPUT(intyangbenzushu1)
{ pY=newdouble*[yangbenzushu1];
pX=newdouble*[yangbenzushu1];
for(intyu=0;yu{pX[yu]=newdouble[Inputnodenum+1];
pY[yu]=newdouble[outputnodenum+1];
}
//每组样本的首值赋为1
for(intyu1=0;yu1 {pX[yu1][0]=1;
pY[yu1][0]=1;
}
cout<<"请输出样本输入值"<for(intyuy=0;yuyfor(intyy=1;yy<=Inputnodenum;yy++)
{if(yy==Inputnodenum)cout< cout<<"X["< cin>>pX[yuy][yy];
}
cout<<"请输出样本理想输出值"<for(intyuy1=0;yuy1for(intyy1=1;yy1<=outputnodenum;yy1++)
{//if(yy==Inputnodenum)cout< cout<<"Y["< cin>>pY[yuy1][yy1];
}
}
/****************************************************************************/
//计算每个节点的输出值函数
doublecomputeYl(intKK)//KK代表第几组组号
{doublesum1=0;
//把所有的层的每一个节点的输出值算出来并记录在pnodey里,不包含输入点值
for(inty=0;y {
for(intr=1;r {doublesum=0;
for(intz=0;z
{if(y==0)sum+=pX[KK][z]*p[y][r-1][z];
else
sum+=pnodey[y-1][z]*p[y][r-1][z];
}
pnodey[y][r]=fas(sum);
}
}
for(intj=1;j<=outputnodenum;j++)
sum1+=pow(pY[KK][j]-pnodey[Sidenum-1][j],2);
returnsum1;
}
/**********************************************************/
//ComputeBack-Propagation-Errors
voidComputeBackPropagationErrors(intgf)//gf代表组号
{//计算所有的ddlj[][]
//for(intgf=0;gffor(intq=Sidenum-1;q>=0;q--)//从最后一层开始
{
if(q==Sidenum-1)//如果是最外一层的话
{ for(intrt=0;rt ddlj[q][rt]=pnodey[q][rt+1]*(1-pnodey[q][rt+1])*(pY[gf][rt+1]-pnodey[q][rt+1]);
}
else
{
for(intry=0;ry { doublesumtemp=0;
for(intfg=0;fg sumtemp+=ddlj[q+1][fg]*p[q+1][fg][ry+1];
ddlj[q][ry]=pnodey[q][ry+1]*(1-pnodey[q][ry+1])*sumtemp;
}
}
}
//计算所有的ddp[][]
//for(intgf1=0;gf1 for(intl=0;l for(intJJ=0;JJ for(inti=0;i {if(l==0)//如果是第一层的话,y值为输入的X值
ddp[l][JJ][i]=ddlj[l][JJ]*pX[gf][i];
else
ddp[l][JJ][i]=ddlj[l][JJ]*pnodey[l-1][i];
}
}
/*************************************************************************/
voidUpdatetheWeightsusingBPAlgorithm()
{for(intcent=0;cent for(intJ=0;J for(inti=0;i p[cent][J][i]+=0.2*ddp[cent][J][i];
}
/***************************************************************************/
doublexunlianErrors()//定义训练误差函数
{doubleerror=0;
doublesum=0;
doubletemp=0;
doubletemp1=0;
for(intgf1=0;gf1{temp=computeYl(gf1);
//temp1=zhengquelv(gf1);
//sum+=temp1;
for(intjj=1;jj<=outputnodenum;jj++)
cout< error+=temp;
}
//sum=sum/yangbenzushu;
cout<<"用训练集所得到的正确率:
"<returnerror/yangbenzushu;
}
/****************************************************************************/
doublejiaoyanErrors(intyangbenzushu1)//定义校验误差函数
{doubleerror=0;
doublesum=0;
doubletemp=0;
doubletemp1=0;
for(intgf1=0;gf1{temp=computeYl(gf1);
for(intjj=1;jj<=outputnodenum;jj++)
cout< //temp1=zhengquelv(gf1);
//sum+=temp1;
error+=temp;
}
//sum=sum/yangbenzushu1;
//cout<<"用校验集所得到的正确率:
"<returnerror/yangbenzushu1;
}
/********************************************************************/
doublezhengquelv(intKK)
{intcount=0;
doubleav=0;
//for(intgf1=0;gf1for(intjj=1;jj<=outputnodenum;jj++)
{if(pnodey[Sidenum-1][jj]>0)pnodey[Sidenum-1][jj]=1;
elsepnodey[Sidenum-1][jj]=0;
if(pY[KK][jj]==pnodey[Sidenum-1][jj])count++;
}
av=(double)count/outputnodenum;
returnav;
}
/***********************************************************************/
voidfreeINput()
{
if(pX!
=NULL)
{for(intu=0;u
delete[]pX[u];
delete[]pX;
pX=NULL;
}
if(pY!
=NULL)
{for(intu1=0;u1 delete[]pY[u1];
delete[]pY;
pY=NULL;
}
}
/***************************************************************/
//输出所有的权值
voidwputout()
{ for(intj=0;j { cout<<"第["<"< for(intk=0;k {//if(k==pnode[j+1]-1)cout< for(intt=0;t {
cout<
if(t==pnode[j])cout< }
}
}
}
/**********************************************************/
};
voidmain()
{
BPbp;
intcount=0;//用来统计所用的迭代次数
//FILE*fp;
intinputnodenum,outnodenum,sidenum,yangbenzunum;
doubleerror;
cout<<"请输入输入点数,输出点数,隐层数"<cin>>inputnodenum>>outnodenum>>sidenum;
cout<<"请输入样本组数"<cin>>yangbenzunum;
//第一步初始化所有的权值
bp.getW(sidenum,inputnodenum,outnodenum,yangbenzunum);
//第二步输入样本组
bp.INPUT(yangbenzunum);
for(;;count++)
{
doublesum=0;
doubletemp=0;
for(intfuzu=0;fuzu{
//第三步计算所有y值
temp=puteYl(fuzu);
//第四步ComputeBack-Propagation-Errors
bp.ComputeBackPropagationErrors(fuzu);
//第五步Up