⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bpnn_simulate.cpp

📁 这是我自己花了很多时间写的一个BP神经网络类
💻 CPP
📖 第 1 页 / 共 2 页
字号:
}

//==================================================//
//功能:计算训练单个样本后的网络误差

//=================================================//
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 + -