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

📄 bpnet.cpp

📁 分别用C++、C、Matlab编写的BP神经网络源程序。
💻 CPP
字号:
// BpNet.cpp : implementation file
////////////////////////////////////////////////////////////////////
/////////////////人工神经网络BP算法/////////////////////////////////
//1、动态改变学习速率
//2、加入动量项
//3、运用了Matcom4.5的矩阵运算库(可免费下载,头文件matlib.h),
//   方便矩阵运算,当然,也可自己写矩阵类
//4、可暂停运算
//5、可将网络以文件的形式保存、恢复
///////////////作者:同济大学材料学院   张纯禹//////////////////////
///////////////email:chunyu_79@hotmail.com//////////////////////////
///////////////QQ:53806186//////////////////////////////////////////
///////////////欢迎不断改进!欢迎讨论其他实用的算法!/////////////////

#include "BpNet.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CBpNet
IMPLEMENT_SERIAL( CBpNet, CObject, 1 )

CBpNet::CBpNet()
{initM(MATCOM_VERSION);//启用矩阵运算库
}

CBpNet::~CBpNet()
{exitM();
 delete this;
}




/////////////////////////////////////////////////////////////////////////////
// CBpNet message handlers
//创建新网络
void CBpNet::Create(Mm mInputData, Mm mTarget, int iInput, int iHidden, int iOutput)
{ int i,j;
  mSampleInput=zeros(mInput.rows(),mInput.cols());
  mSampleTarget=zeros(mTarget.rows(),mTarget.cols());  
  mSampleInput=mInputData;
  mSampleTarget=mTarget;
  this->iInput=iInput;
  this->iHidden=iHidden;
  this->iOutput=iOutput;
  //创建计算用的单个样本矩阵
  mInput=zeros(1,this->iInput);
  mHidden=zeros(1,this->iHidden);
  mOutput=zeros(1,this->iOutput);
  //创建权重矩阵,并赋初值
  mWeighti=zeros(this->iInput,this->iHidden);
  mWeighto=zeros(this->iHidden,this->iOutput); 
  //赋初值
  for(i=1;i<=this->iInput;i++)
	  for(j=1;j<=this->iHidden;j++)
		  mWeighti.r(i,j)=randab(-1.0,1.0);
  for(i=1;i<=this->iHidden;i++)
	  for(j=1;j<=this->iOutput;j++)
		  mWeighto.r(i,j)=randab(-1.0,1.0);
  
  //创建阙值矩阵,并赋值
  mThresholdi=zeros(1,this->iHidden);
  for(i=1;i<=this->iHidden;i++)
	  mThresholdi.r(i)=randab(-1.0,1.0);
  mThresholdo=zeros(1,this->iOutput);
  for(i=1;i<=this->iOutput;i++)
	  mThresholdo.r(i)=randab(-1.0,1.0);
  //创建权重变化矩阵
  mChangei=zeros(this->iInput,this->iHidden);
  mChangeo=zeros(this->iHidden,this->iOutput);
  
  mInputNormFactor=zeros(iInput,2);
  mTargetNormFactor=zeros(iOutput,2);
  //误差矩阵
   mOutputDeltas=zeros(iOutput);
   mHiddenDeltas=zeros(iHidden);
  //学习速率赋值
  dblLearnRate1=0.5;
  dblLearnRate2=0.5;
  dblMomentumFactor=0.95;
  
  m_isOK=false;
  m_IsStop=false;
  dblMse=1.0e-6;//误差限
  dblError=1.0;
  lEpochs=0;

}
//根据已有的网络进行预测
Mm CBpNet::simulate(Mm mData)
{int i,j;
 Mm mResult;
 Mm data=zeros(mData.rows(),mData.cols());
 data=mData;
 if(mData.cols()!=iInput)
 {::MessageBox(NULL,"输入数据变量个数错误!","输入数据变量个数错误!",MB_OK);
  return mResult;
 }
 mResult=zeros(data.rows(),iOutput); 
 //正规化数据
 for(i=1;i<=data.rows();i++)
	 for(j=1;j<=data.cols();j++) 
         data.r(i,j)=(data.r(i,j)-mInputNormFactor.r(j,1))/(mInputNormFactor.r(j,2)-mInputNormFactor.r(j,1));
 //计算
	 int iSample;
	 Mm mInputdata,mHiddendata,mOutputdata;
	 mInputdata=zeros(1,iInput);
	 mHiddendata=zeros(1,iHidden);
	 mOutputdata=zeros(1,iOutput);
	 double sum=0.0;
   for(iSample=1;iSample<=data.rows();iSample++){ 
	 //输入层数据
	    for(i=1;i<=iInput;i++)
		  mInputdata.r(i)=data.r(iSample,i);
	 //隐层数据	
		for(j=1;j<=iHidden;j++){
		  sum=0.0;
		 for(i=1;i<=iInput;i++)
			sum+=mInputdata.r(i)*mWeighti.r(i,j);
		 sum-=mThresholdi.r(j); 
		 mHiddendata.r(j)=1.0/(1.0+exp(-sum));
		}
    
  //输出数据
	for(j=1;j<=iOutput;j++){
		sum=0.0;
		for(i=1;i<=iHidden;i++)
			sum+=mHiddendata.r(i)*mWeighto.r(i,j);
		sum-=mThresholdo.r(j); 
		mOutputdata.r(j)=1.0/(1.0+exp(-sum));
	}
	
	//转换
	for(j=1;j<=iOutput;j++)
        mResult.r(iSample,j)=mOutputdata.r(j)*(mTargetNormFactor.r(j,2)-mTargetNormFactor.r(j,1))+mTargetNormFactor.r(j,1);
 }
  
 return (mResult);
}

void CBpNet::LoadBpNet(CString &strNetName)
{CFile file;
 
 if(file.Open(strNetName,CFile::modeRead)==0)   
 {MessageBox(NULL,"无法打开文件!","错误",MB_OK);
  return;
 }
 else{
	 CArchive myar(&file,CArchive::load);
	 Serialize(myar); 
	 myar.Close();
 }
 file.Close(); 
}

bool CBpNet::SaveBpNet(CString &strNetName)
{CFile file;
 if(strNetName.GetLength()==0)
	 return(false);
 if(file.Open(strNetName,CFile::modeCreate|CFile::modeWrite)==0)   
 {MessageBox(NULL,"无法创建文件!","错误",MB_OK);
  return(false);
 }
 else{
	 CArchive myar(&file,CArchive::store);
	 Serialize(myar); 
	 myar.Close();
 }
 file.Close(); 
 return(true);
}
//网络学习
void CBpNet::learn()
{ int iSample=1;
  double dblTotal;
  MSG msg;
  if(m_IsStop)
	  m_IsStop=false;
  //数据正规化处理
  normalize();

  while(dblError>dblMse&&!m_IsStop){
   dblTotal=0.0;
   for(iSample=1;iSample<=mSampleInput.rows();iSample++){
	forward(iSample);
    backward(iSample);
	dblTotal+=dblErr;//总误差
  }
   if(dblTotal/dblError>1.04){//动态改变学习速率
	   dblLearnRate1*=0.7;
       dblLearnRate2*=0.7;
   }
   else{
       dblLearnRate1*=1.05;
       dblLearnRate2*=1.05;
   }
   lEpochs++;
   dblError=dblTotal;

   ::PeekMessage(&msg,NULL,0,0,PM_REMOVE);
   ::DispatchMessage(&msg);
     msg.message=-1;
   ::DispatchMessage(&msg);//这样可以消除屏闪和假死机
  }
if(dblError<=dblMse)
 m_isOK=true;
else
 m_isOK=false;

}

void CBpNet::stop()
{
 m_IsStop=true;
}

double CBpNet::randab(double a, double b)
{ //注意,如果应用矩阵库,头文件matlib.h对rand()函数重新定义,只产生(0,1)
  //之间的随机数
  return((b-a)*rand()+a);
}

//将数据转化到(0,1)区间
void CBpNet::normalize()
{
 
 int i,j;
  //输入数据范围
  mInputNormFactor=scope(mSampleInput);
  //目标数据范围
  mTargetNormFactor=scope(mSampleTarget);

 for(i=1;i<=mSampleInput.rows();i++)
	 for(j=1;j<=mSampleInput.cols();j++)
		 mSampleInput.r(i,j)=(mSampleInput.r(i,j)-mInputNormFactor.r(j,1))/(mInputNormFactor.r(j,2)-mInputNormFactor.r(j,1));
 
 for(i=1;i<=mSampleTarget.rows();i++)
	 for(j=1;j<=mSampleTarget.cols();j++)
		 mSampleTarget.r(i,j)=(mSampleTarget.r(i,j)-mTargetNormFactor.r(j,1))/(mTargetNormFactor.r(j,2)-mTargetNormFactor.r(j,1));
 
}

//前向计算 
void CBpNet::forward(int iSample)
{//根据第iSample个样本,前向计算
	if(iSample<1||iSample>mSampleInput.rows()){
		MessageBox(NULL,"无此样本数据:索引出界!","无此样本数据:索引出界!",MB_OK);
		return;
	}
	int i,j;
	double sum=0.0;
	
	//输入层数据
	for(i=1;i<=iInput;i++)
		mInput.r(i)=mSampleInput.r(iSample,i);
	
	//隐层数据
    
	for(j=1;j<=iHidden;j++){
		sum=0.0;
		for(i=1;i<=iInput;i++)			
			sum+=mInput.r(i)*mWeighti.r(i,j);
		
		sum-=mThresholdi.r(j); 
		mHidden.r(j)=1.0/(1.0+exp(-sum));
	}
    	
	//输出数据
	for(j=1;j<=iOutput;j++){
		sum=0.0;
		for(i=1;i<=iHidden;i++)
			sum+=mHidden.r(i)*mWeighto.r(i,j);
		sum-=mThresholdo.r(j); 
		mOutput.r(j)=1.0/(1.0+exp(-sum));
	}
   	
}

//后向反馈
void CBpNet::backward(int iSample)
{
	if(iSample<1||iSample>mSampleInput.rows()){
		MessageBox(NULL,"无此样本数据:索引出界!","无此样本数据:索引出界!",MB_OK);
		return;
	}
    int i,j;
	
    //输出误差
	for(i=1;i<=iOutput;i++)
		mOutputDeltas.r(i)=mOutput.r(i)*(1-mOutput.r(i))*(mSampleTarget.r(iSample,i)-mOutput.r(i));
	
	//隐层误差
	double sum=0.0;
	for(j=1;j<=iHidden;j++){
		sum=0.0;
		for(i=1;i<=iOutput;i++)
			sum+=mOutputDeltas.r(i)*mWeighto.r(j,i);
		mHiddenDeltas.r(j)=mHidden.r(j)*(1-mHidden.r(j))*sum;
	}
	//更新隐层-输出权重
	
	double dblChange;
	for(j=1;j<=iHidden;j++)
		for(i=1;i<=iOutput;i++){
			dblChange=mOutputDeltas.r(i)*mHidden.r(j);
			mWeighto.r(j,i)=mWeighto.r(j,i)+dblLearnRate2*dblChange+dblMomentumFactor*mChangeo.r(j,i);
			mChangeo.r(j,i)=dblChange;
		}
    
	//更新输入-隐层权重
    for(i=1;i<=iInput;i++)
		for(j=1;j<=iHidden;j++){
			dblChange=mHiddenDeltas.r(j)*mInput.r(i);
            mWeighti.r(i,j)=mWeighti.r(i,j)+dblLearnRate1*dblChange+dblMomentumFactor*mChangei.r(i,j); 
			mChangei.r(i,j)=dblChange;
		}
	//修改阙值
	for(j=1;j<=iOutput;j++)
	    mThresholdo.r(j)-=dblLearnRate2*mOutputDeltas.r(j);  
	for(i=1;i<=iHidden;i++) 
	    mThresholdi.r(i)-=dblLearnRate1*mHiddenDeltas.r(i); 
   	//计算误差
	dblErr=0.0;
	for(i=1;i<=iOutput;i++)
		dblErr+=0.5*(mSampleTarget.r(iSample,i)-mOutput.r(i))*(mSampleTarget.r(iSample,i)-mOutput.r(i));
	
   
}

//求数据列的范围
Mm CBpNet::scope(Mm mData)
{Mm mScope;
 mScope=zeros(mData.cols(),2);
 double  min,max;
 for(int i=1;i<=mData.cols();i++){
	 min=max=mData.r(1,i); 
	 for(int j=1;j<=mData.rows();j++){
		 if(mData.r(j,i)>=max)
			 max=mData.r(j,i);
		 if(mData.r(j,i)<=min)
			 min=mData.r(j,i);
	 }
	 if(min==max)
		 min=0.0;
	 mScope.r(i,1)=min;
	 mScope.r(i,2)=max;
 }
 return(mScope);

}

//显示矩阵数据,方便调试
void CBpNet::display(Mm data)
{CString strData,strTemp;
 int i=1,j=1;
 for(i=1;i<=data.rows();i++){
	 for(j=1;j<=data.cols();j++){
	 strTemp.Format("%.3f ",data.r(i,j));
	 strData+=strTemp;
	 }
	 strData=strData+"\r\n";
 }
 ::MessageBox(NULL,strData,"",MB_OK);

}

void CBpNet::Serialize(CArchive &ar)
{CObject::Serialize(ar);
 ///////////////////////////////////// 
if(ar.IsStoring()){
     int i,j;
	 double dblData;
	 CString strTemp="Bp";
	 ar<<strTemp;//写入标志
	//纪录神经元个数
	 ar<<iInput<<iHidden<<iOutput;
    //纪录权值
	 for(i=1;i<=iInput;i++)
		 for(j=1;j<=iHidden;j++){
			 dblData=mWeighti.r(i,j);
		     ar<<dblData;
		 }
     for(i=1;i<=iHidden;i++)
		 for(j=1;j<=iOutput;j++){
			 dblData=mWeighto.r(i,j);
			 ar<<dblData;
		 }
	
      //记录权值变化
	 for(j=1;j<=iHidden;j++)
		for(i=1;i<=iOutput;i++)
			ar<<mChangeo.r(j,i);
	
    //输入-隐层权重变化
     for(i=1;i<=iInput;i++)
		for(j=1;j<=iHidden;j++)
			ar<<mChangei.r(i,j);
		
      //纪录阙值
	 for(i=1;i<=iHidden;i++){
              dblData=mThresholdi.r(i);
			  ar<<dblData;
			  }
     for(i=1;i<=iOutput;i++){
		      dblData=mThresholdo.r(i);
			  ar<<dblData;
			  }
     //纪录输入输出的极值
	 for(i=1;i<=iInput;i++){
		  dblData=mInputNormFactor.r(i,1);
		  ar<<dblData; //极小值
		  dblData=mInputNormFactor.r(i,2);
		  ar<<dblData; //极大值
         }
	 for(i=1;i<=iOutput;i++)
		 {dblData=mTargetNormFactor.r(i,1);
		  ar<<dblData; //输出数据极小值
		  dblData=mTargetNormFactor.r(i,2);
		  ar<<dblData; 
		 }
	 //误差范围
	 ar<<dblMse; 
	 //学习速率
	 ar<<dblLearnRate1<<dblLearnRate2;
	 
}
         
 else{
	 int i,j;
	 CString strTemp="";
	 double dblTemp;
	 ar>>strTemp;//读入标志
	//读入神经元个数
	 ar>>iInput>>iHidden>>iOutput;
	 mChangei=zeros(iInput,iHidden);
     mChangeo=zeros(iHidden,iOutput);
	 mWeighti=zeros(iInput,iHidden);
	 mWeighto=zeros(iHidden,iOutput);
    //读入权值
	 for(i=1;i<=iInput;i++)
		  for(j=1;j<=iHidden;j++)
		  { ar>>dblTemp;
		    mWeighti.r(i,j)=dblTemp;
		  }
	 	  
     for(i=1;i<=iHidden;i++)
		 for(j=1;j<=iOutput;j++)
		 { ar>>dblTemp;
		   mWeighto.r(i,j)=dblTemp;
		 }
	
	 //读入权值变化
	 for(j=1;j<=iHidden;j++)
		for(i=1;i<=iOutput;i++)
			ar>>mChangeo.r(j,i);
	
     //输入-隐层权重
     for(i=1;i<=iInput;i++)
		for(j=1;j<=iHidden;j++)
			ar>>mChangei.r(i,j);
	
     //读入阙值
     mThresholdi=zeros(1,iHidden);
	 for(i=1;i<=iHidden;i++)
	 {ar>>dblTemp;
	  mThresholdi.r(i)=dblTemp;
	 }
	 mThresholdo=zeros(1,iOutput);
     for(i=1;i<=iOutput;i++)
	 {ar>>dblTemp;
	  mThresholdo.r(i)=dblTemp;
	 }
     //读入输入输出的极值
     mInputNormFactor=zeros(iInput,2);
	 for(i=1;i<=iInput;i++){
		  ar>>dblTemp;
		  mInputNormFactor.r(i,1)=dblTemp; //极小值
		  ar>>dblTemp;
		  mInputNormFactor.r(i,2)=dblTemp; //极大值
         }
	 mTargetNormFactor=zeros(iOutput,2);
	 for(i=1;i<=iOutput;i++)
		 {ar>>dblTemp;
	      mTargetNormFactor.r(i,1)=dblTemp; //输出数据极小值
		  ar>>dblTemp;
		  mTargetNormFactor.r(i,2)=dblTemp; 
		 }
	 //读入误差范围
	 ar>>dblMse; 
	 //读入学习速率
	 ar>>dblLearnRate1>>dblLearnRate2;
	 

	 //创建计算用的单个样本矩阵
     mInput=zeros(1,iInput);
     mHidden=zeros(1,iHidden);
     mOutput=zeros(1,iOutput);
	 //误差矩阵
	 mOutputDeltas=zeros(iOutput);
	 mHiddenDeltas=zeros(iHidden);
     
 }

}

//如果不是新网络,比如从文件恢复的网络,调用此函数构建学习样本
void CBpNet::LoadPattern(Mm mIn, Mm mOut)
{ if(mIn.cols()!=iInput||mOut.cols()!=iOutput){
	::MessageBox( NULL,"学习样本格式错误!","错误",MB_OK);
	return;
}
  mSampleInput=zeros(mIn.rows(),mIn.cols());
  mSampleTarget=zeros(mOut.rows(),mOut.cols());  
  mSampleInput=mIn;
  mSampleTarget=mOut;
    
  m_isOK=false;
  m_IsStop=false;
  lEpochs=0;
  dblMomentumFactor=0.95;
  dblError=1.0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -