📄 bpnn_simulate.cpp
字号:
}
//==================================================//
//功能:计算训练单个样本后的网络误差
//=================================================//
void CBPNN_Simulate::ComputeErr(double dTarget)
{
double dSum=0;
int j;
for(j=0;j<m_lOutNodes;j++)
dSum+=(dTarget-m_pOutNode[j].dOut)*(dTarget-m_pOutNode[j].dOut);
m_dError=0.5*dSum;
}
//===================================================//
//功能:误差方向传播,计算各层节点的局部误差
//===================================================//
void CBPNN_Simulate::BPErr(double dTarget)
{
double dError,dOut;
int i,j,k;
//输出层节点局部误差
for(j=0;j<m_lOutNodes;j++)
{
dOut=m_pOutNode[j].dOut*(1-m_pOutNode[j].dOut);
dError=dTarget-m_pOutNode[j].dOut;//目标输出与实际输出的误差
m_pOutNode[j].dErr=dError*dOut;
}
//各隐层节点的局部误差
if(m_lHideLayers>0)
{
//最后隐层节点的局部误差
for(j=0;j<m_lpHideNodes[m_lHideLayers-1];j++)
{
dOut=m_ppHideNode[m_lHideLayers-1][j].dOut*
(1.0-m_ppHideNode[m_lHideLayers-1][j].dOut);
//输出层节点的局部误差反向加权和
dError=0.0;
for(k=0;k<m_lOutNodes;k++)
dError+=m_pOutNode[k].dErr*m_pOutNode[k].pLink[j];
m_ppHideNode[m_lHideLayers-1][j].dErr=dOut*dError;
}
//其余隐层节点的局部误差
for(i=m_lHideLayers-2;i>=0;i--)
for(j=0;j<m_lpHideNodes[i];j++)
{
dOut=m_ppHideNode[i][j].dOut*(1-m_ppHideNode[i][j].dOut);
//后1隐层各节点的局部误差的反向加权和
dError=0.0;
for(k=0;k<m_lpHideNodes[i+1];k++)
dError+=m_ppHideNode[i+1][k].dErr*m_ppHideNode[i+1][k].pLink[j];
m_ppHideNode[i][j].dErr=dOut*dError;
}
}
}
//===================================================//
//功能:调节网络的权值、偏移值
//===================================================//
void CBPNN_Simulate::Adjust(double dStudyRate,double dMomentRate)
{
double dGrient;//梯度变化量
double dMoment;//动量变化量
double dOffStudy,dOffMoment;//偏移值学习率、偏移值动量率、
double dLinkStudy,dLinkMoment;//权值学习率、权值动量率
int i,j,k;
//把学习率分别赋给偏移值学习率、连接权值学习率
dOffStudy=dStudyRate;
dLinkStudy=dStudyRate;
//把动量率分别赋给偏移值动量率、连接权值动量率
dOffMoment=dMomentRate;
dLinkMoment=dMomentRate;
//调节输出层节点的偏移值、连接权值
for(j=0;j<m_lOutNodes;j++)
{
//调节偏移值
dGrient=dOffStudy*(1.0-dOffMoment)*m_pOutNode[j].dErr;
dMoment=dOffMoment*(m_pOutNode[j].dOff-m_pOutNode[j].dPreOff);
m_pOutNode[j].dPreOff=m_pOutNode[j].dOff;//把当前时刻偏移值赋给前一时刻偏移值
m_pOutNode[j].dOff+=(dGrient+dMoment);
//调节连接权值
for(k=0;k<m_lpHideNodes[m_lHideLayers-1];k++)
{
dGrient=dLinkStudy*(1.0-dLinkMoment)*m_pOutNode[j].dErr*m_ppHideNode[m_lHideLayers-1][k].dOut;
dMoment=dLinkMoment*(m_pOutNode[j].pLink[k]-m_pOutNode[j].pPreLink[k]);
m_pOutNode[j].pPreLink[k]=m_pOutNode[j].pLink[k];//把当前时刻连接值赋给前一时刻连接值
m_pOutNode[j].pLink[k]+=(dGrient+dMoment);
}
}
//根据m_lHideLayers的大小,计算各隐层的偏移值、连接权值
if(m_lHideLayers==1)
{
//第1隐层偏移值、连接权值
for(j=0;j<m_lpHideNodes[0];j++)
{
//调节偏移值
dGrient=dOffStudy*(1.0-dOffMoment)*m_ppHideNode[0][j].dErr;
dMoment=dOffMoment*(m_ppHideNode[0][j].dOff-m_ppHideNode[0][j].dPreOff);
m_ppHideNode[0][j].dPreOff=m_ppHideNode[0][j].dOff;
m_ppHideNode[0][j].dOff+=(dGrient+dMoment);
//调节连接权值
for(k=0;k<m_lInNodes;k++)
{
dGrient=dLinkStudy*(1.0-dLinkMoment)*m_ppHideNode[0][j].dErr*m_dpInput[k];
dMoment=dLinkMoment*(m_ppHideNode[0][j].pLink[k]-m_ppHideNode[0][j].pPreLink[k]);
m_ppHideNode[0][j].pPreLink[k]=m_ppHideNode[0][j].pLink[k];
m_ppHideNode[0][j].pLink[k]+=(dGrient+dMoment);
}
}
}
else if(m_lHideLayers==2)
{
//第2隐层偏移值、连接权值
for(j=0;j<m_lpHideNodes[1];j++)
{
//调节偏移值
dGrient=dOffStudy*(1.0-dOffMoment)*m_ppHideNode[1][j].dErr;
dMoment=dOffMoment*(m_ppHideNode[1][j].dOff-m_ppHideNode[1][j].dPreOff);
m_ppHideNode[1][j].dPreOff=m_ppHideNode[1][j].dOff;
m_ppHideNode[1][j].dOff+=(dGrient+dMoment);
//调节连接权值
for(k=0;k<m_lpHideNodes[0];k++)
{
dGrient=dLinkStudy*(1.0-dLinkMoment)*m_ppHideNode[1][j].dErr*m_ppHideNode[0][k].dOut;
dMoment=dLinkMoment*(m_ppHideNode[1][j].pLink[k]-m_ppHideNode[1][j].pPreLink[k]);
m_ppHideNode[1][j].pPreLink[k]=m_ppHideNode[1][j].pLink[k];
m_ppHideNode[1][j].pLink[k]+=(dGrient+dMoment);
}
}
//第1隐层的偏移值、连接权值
for(j=0;j<m_lpHideNodes[0];j++)
{
//调节偏移值
dGrient=dOffStudy*(1.0-dOffMoment)*m_ppHideNode[0][j].dErr;
dMoment=dOffMoment*(m_ppHideNode[0][j].dOff-m_ppHideNode[0][j].dPreOff);
m_ppHideNode[0][j].dPreOff=m_ppHideNode[0][j].dOff;
m_ppHideNode[0][j].dOff+=(dGrient+dMoment);
//调节连接权值
for(k=0;k<m_lInNodes;k++)
{
dGrient=dLinkStudy*(1.0-dLinkMoment)*m_ppHideNode[0][j].dErr*m_dpInput[k];
dMoment=dLinkMoment*(m_ppHideNode[0][j].pLink[k]-m_ppHideNode[0][j].pPreLink[k]);
m_ppHideNode[0][j].pPreLink[k]=m_ppHideNode[0][j].pLink[k];
m_ppHideNode[0][j].pLink[k]+=(dGrient+dMoment);
}
}
}
else if(m_lHideLayers>=3)
{
//最后隐层的偏移值、连接权值
for(j=0;j<m_lpHideNodes[m_lHideLayers-1];j++)
{
//调节偏移值
dGrient=dOffStudy*(1.0-dOffMoment)*m_ppHideNode[m_lHideLayers-1][j].dErr;
dMoment=dOffMoment*(m_ppHideNode[m_lHideLayers-1][j].dOff-m_ppHideNode[m_lHideLayers-1][j].dPreOff);
m_ppHideNode[m_lHideLayers-1][j].dPreOff=m_ppHideNode[m_lHideLayers-1][j].dOff;
m_ppHideNode[m_lHideLayers-1][j].dOff+=(dGrient+dMoment);
//调节连接权值
for(k=0;k<m_lpHideNodes[m_lHideLayers-2];k++)
{
dGrient=dLinkStudy*(1.0-dLinkMoment)*m_ppHideNode[m_lHideLayers-1][j].dErr*m_ppHideNode[m_lHideLayers-2][k].dOut;
dMoment=dLinkMoment*(m_ppHideNode[m_lHideLayers-1][j].pLink[k]-m_ppHideNode[m_lHideLayers-1][j].pPreLink[k]);
m_ppHideNode[m_lHideLayers-1][j].pPreLink[k]=m_ppHideNode[m_lHideLayers-1][j].pLink[k];
m_ppHideNode[m_lHideLayers-1][j].pLink[k]+=(dGrient+dMoment);
}
}
//中间隐层的偏移值、连接权值
for(i=m_lHideLayers-2;i>0;i--)
for(j=0;j<m_lpHideNodes[i];j++)
{
//调节偏移值
dGrient=dOffStudy*(1.0-dOffMoment)*m_ppHideNode[i][j].dErr;
dMoment=dOffMoment*(m_ppHideNode[i][j].dOff-m_ppHideNode[i][j].dPreOff);
m_ppHideNode[i][j].dPreOff=m_ppHideNode[i][j].dOff;
m_ppHideNode[i][j].dOff+=(dGrient+dMoment);
//调节连接权值
for(k=0;k<m_lpHideNodes[i-1];k++)
{
dGrient=dLinkStudy*(1.0-dLinkMoment)*m_ppHideNode[i][j].dErr*m_ppHideNode[i-1][k].dOut;
dMoment=dLinkMoment*(m_ppHideNode[i][j].pLink[k]-m_ppHideNode[i][j].pPreLink[k]);
m_ppHideNode[i][j].pPreLink[k]=m_ppHideNode[i][j].pLink[k];
m_ppHideNode[i][j].pLink[k]+=(dGrient+dMoment);
}
}
//第1隐层的偏移值、连接权值
for(j=0;j<m_lpHideNodes[0];j++)
{
//调节偏移值
dGrient=dOffStudy*(1.0-dOffMoment)*m_ppHideNode[0][j].dErr;
dMoment=dOffMoment*(m_ppHideNode[0][j].dOff-m_ppHideNode[0][j].dPreOff);
m_ppHideNode[0][j].dPreOff=m_ppHideNode[0][j].dOff;
m_ppHideNode[0][j].dOff+=(dGrient+dMoment);
//调节连接权值
for(k=0;k<m_lInNodes;k++)
{
dGrient=dLinkStudy*(1.0-dLinkMoment)*m_ppHideNode[0][j].dErr*m_dpInput[k];
dMoment=dLinkMoment*(m_ppHideNode[0][j].pLink[k]-m_ppHideNode[0][j].pPreLink[k]);
m_ppHideNode[0][j].pPreLink[k]=m_ppHideNode[0][j].pLink[k];
m_ppHideNode[0][j].pLink[k]+=(dGrient+dMoment);
}
}
}
}
/*=====================================================================
功能:用整个训练样本集训练网络
参数:(入口)pSampleSet:训练样本集
(入口)dStudyRate:学习率
(入口)dMomentRate:动量率,即在网络训练中动量的影响因子
(入口)lMaxIterNums:网络训练的最大迭代次数
(入口)dMinRMS:网络训练的最小均方误差
=======================================================================*/
long CBPNN_Simulate::Train(TrainSample *pSampleSet,long lSamples,double dStudyRate,
double dMomentRate,long lMaxIterNums,double dMinRMS)
{
long lErr=0;//错误返回类型
int iIterNums;//迭代次数
double dRMS;//均方误差
double dTemp=0.0;
//进度控制条参数
int iOldPos,iCurPos;
double dStep,dPos;
BOOL bIsBigger100;
LPCTSTR lpszSubProgressName;
long i,j;
//子控制进度条参数
StartProgress();
lpszSubProgressName="网络训练... ";
SetSubProgressName(lpszSubProgressName);
if(lMaxIterNums>=100)
{
bIsBigger100=TRUE;
dStep=(double)lMaxIterNums/100;
dPos=dStep;
}
else
{
bIsBigger100=FALSE;
dStep=100/(double)lMaxIterNums;
dPos=0.0;
}
//网络训练
iIterNums=0;
dRMS=1000.0;//赋一个较大的值,保证开始进入循环
while((iIterNums<lMaxIterNums)&&(dRMS>dMinRMS))
{
//用整个样本集对网络进行
dRMS=0.0;
for(i=0;i<lSamples;i++)
{
TrainWithOneSample(pSampleSet[i],dStudyRate,dMomentRate);//一个样本对网络训练
dRMS+=m_dError;
}
dRMS/=lSamples;//平均均方误差
iIterNums++;
//子控制进度条显示
if(bIsBigger100)
{
if(iIterNums==(int)dPos)
{
StepIt();
dPos+=dStep;
}
}
else
{
iOldPos=(int)dPos;
dPos+=dStep;
iCurPos=(int)dPos;
for(j=iOldPos;j<iCurPos;j++)
StepIt();
}
}
SetPos(100);//子控制进度条位置移到最后
return lErr;
}
//用单个样本训练网络
void CBPNN_Simulate::TrainWithOneSample(TrainSample Sample,double dStudyRate,double dMomentRate)
{
m_dError=0.0;//误差置0
FPInput(Sample.dpInput);//输入信息前向传播
ComputeErr(Sample.dTarget);//计算单个训练样本的网络误差
BPErr(Sample.dTarget);//误差反向传播
Adjust(dStudyRate,dMomentRate);//调节网络的全部连接权值、阀值
}
/*==================================================================================
功能:用训练后稳定的网络进行插值拟合
参数:(入口)dpInput:网络输入
(出口)dSimulate:输入经过网络后得到的拟合值
==================================================================================*/
void CBPNN_Simulate::Simulate(double *dpInput,double &dSimulate)
{
FPInput(dpInput);//输入信息前向传播
dSimulate=m_pOutNode[0].dOut;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -