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

📄 neuronet_bp.cpp

📁 该程序是BP神经网络算法C++类定义及其说明;经过调试。可用有效工具。对于机器人开发非常好。
💻 CPP
字号:
#include "StdAfx.h"
#include "neuronet_bp.h"
#include "math.h"

CNeuroNet_BP::CNeuroNet_BP()
{
}

CNeuroNet_BP::CNeuroNet_BP(INT NumLayer, INT* pNumNodeInEachLayer, CString  MyFileName)
{
	Alpha = 0.9;
	Eta = 0.45;
	Gain = 5;
	Error = 0;
	nLayer = NumLayer;
	pLayer = new NeuroLayer[nLayer];
	this->TrainTimes =0;
	fileName = MyFileName;

	//构建网络
	for(INT i=0; i<nLayer; i++)
	{
		pLayer[i].nNode = pNumNodeInEachLayer[i];
	}

	this->nInput = pLayer[0].nNode;

	//分配网络变量空间
	this->GenerateNet();
	//随机设定权值
	this->RandomWeight();
}

CNeuroNet_BP::~CNeuroNet_BP(void)
{
}


// 随机赋权值
void CNeuroNet_BP::RandomWeight(void)
{
	srand(4567);
	for(INT i=0; i<nLayer; i++)
	{
		for(INT  j=0; j<pLayer[i].nNode; j++)
		{
			for(INT	 k=0; k<pLayer[i].nInput; k++)
			{
				pLayer[i].ppWeight[j][k] = (rand()%100-50)/100.0;		//随机赋权值(-0.5, 0.5);
				pLayer[i].ppDWeight[j][k] = 0.0;
			}
		}
	}

}

// 从文件中读取神经网络的权值
BOOL CNeuroNet_BP::ReadNetFromFile(void)
{

	CFile	file;
	if(file.Open(fileName, CFile::modeRead)==FALSE)
	{
		return FALSE;
	}

	char	*pChar = new char[10];
	file.Read((void*)pChar, 10);
	//if(pChar != "NeuroBP")
	//{
	//	return FALSE;
	//}
	file.Read((void*)&this->TrainTimes, sizeof(DWORD));
	file.Read((void*)&this->Error, sizeof(DOUBLE));
	file.Read((void*)&this->Alpha, sizeof(DOUBLE));
	file.Read((void*)&this->Eta, sizeof(DOUBLE));
	file.Read((void*)&this->Gain, sizeof(DOUBLE));
	file.Read((void*)&this->nInput, sizeof(INT));
	file.Read((void*)&this->nLayer, sizeof(INT));

	//读出每层节点数
	INT*	pNumNode = new INT[nLayer];
	for(INT i=0; i<nLayer; i++)
	{
		file.Read((void*)&pNumNode[i], sizeof(INT));
	}

	///
	pLayer = new NeuroLayer[nLayer];
	for(INT i=0; i<nLayer; i++)
	{
		pLayer[i].nNode = pNumNode[i];
	}	
	this->GenerateNet();

	//给每个神经元赋权值
	for(INT i=0; i<nLayer; i++)
	{
		for(INT j=0; j<pLayer[i].nNode; j++)
		{
			file.Read(pLayer[i].ppWeight[j], pLayer[i].nInput*sizeof(DOUBLE));	//读出每层的所有权值
			file.Read(pLayer[i].ppDWeight[j], pLayer[i].nInput*sizeof(DOUBLE));	//读出每层的所有权值
			//TRACE("pw[%d][%d][0]= %f", i, j, pLayer[i].ppWeight[j]);
		}
	}
    
	return TRUE;
}

// 把权值保存到文件
BOOL CNeuroNet_BP::SaveNetToFile(void)
{
	INT	nTemp = 0;

	char	ID[10] = "NeuroBP";
	//char	Memo[100] = "未说明"; 
    
	HANDLE hFile = CreateFile(_T(fileName),
         GENERIC_WRITE, FILE_SHARE_READ,
         NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

   if (hFile == INVALID_HANDLE_VALUE)
   {
      AfxMessageBox(_T("Couldn't create the file!"));
	  return FALSE;
   }

    // Attach a CFile object to the handle we have.
    CFile file(hFile);

	file.Write((void*)ID, 10);				//写入文件类型标记
	//file.Write((void*)Memo, 100);			//写入描述参数
	file.Write((void*)&TrainTimes, sizeof(DWORD));		//写入已训练次数
	file.Write((void*)&this->Error, sizeof(DOUBLE));	//写入最近的系统误差
	file.Write((void*)&this->Alpha, sizeof(DOUBLE));
	file.Write((void*)&this->Eta, sizeof(DOUBLE));
	file.Write((void*)&this->Gain, sizeof(DOUBLE));
	file.Write(&(this->nInput), sizeof(INT));		//写入输入数据宽度
	file.Write(&(this->nLayer), sizeof(INT));	

	//写入每层节点数
	for(INT i=0; i<nLayer; i++)				
	{
		file.Write(&(pLayer[i].nNode), sizeof(INT));		
	}	

	//写入每层所有节点的权值
	for(INT i=0; i<nLayer; i++)				
	{
		for(INT j=0; j<pLayer[i].nNode; j++)
		{
			file.Write(pLayer[i].ppWeight[j],  pLayer[i].nInput*sizeof(DOUBLE));
			file.Write(pLayer[i].ppDWeight[j],  pLayer[i].nInput*sizeof(DOUBLE));

			//TRACE("pw[%d][%d][0]= %f", i, j, pLayer[i].ppWeight[j]);
		}
	}

	file.Close();

	return TRUE;
}

// 处理输入数据,产生输出
BOOL CNeuroNet_BP::Propagate( DOUBLE*  pInput)
{
	this->pInput = pInput;

	//计算输出结果
	for(INT i=0; i<this->nLayer; i++)
	{
		if(i==0)
		{
			pLayer[i].pInput = this->pInput;
		}
		else
		{
			pLayer[i].pInput = pLayer[i-1].pOutput;
		}

		for(INT j=0; j<pLayer[i].nNode; j++)
		{
			pLayer[i].pOutput[j] = func(i, j);
			TRACE("pOut[%d][%d]=\t%f\t", i, j, pLayer[i].pOutput[j]);
	}
	}

	return TRUE;
}

// 节点转移函数
DOUBLE  CNeuroNet_BP::func(INT i, INT j)
{
	DOUBLE	sigma = 0.0;
	for(INT k=0; k<pLayer[i].nInput; k++)
	{
		sigma = sigma + pLayer[i].pInput[k] * pLayer[i].ppWeight[j][k];
	}
	
	sigma = 1.0/(1.0 + exp(-sigma*this->Gain));
	return sigma;
}

//用样本数据进行训练
void  CNeuroNet_BP::Train(DOUBLE* pInput, DOUBLE* pTeach)
{
	Propagate(pInput);				//处理数据
	ComputeOutputError(pTeach);		//计算误差
	BackPropagate();				//反向传播,调整权值
	this->TrainTimes++;
}

//******************************************************************************
//                  反 向 传 播   调 整 权 值
// *****************************************************************************
// 计算输出误差
void  CNeuroNet_BP::ComputeOutputError(DOUBLE*	pTarget)
{
  DOUBLE	Out, Err;
  this->Error=0;

  for(INT i=0; i<pLayer[nLayer-1].nNode; i++)
  {
	Out = pLayer[nLayer-1].pOutput[i];
	Err = pTarget[i] - Out;
	//this->pLayer[nLayer-1].pError[i] = Gain*Out*(1-Out)*Err;
	this->pLayer[nLayer-1].pError[i] = Out*(1-Out)*Err;
	this->Error += 0.5*pow(Err, 2);
  }
}


//反向传播误差
void CNeuroNet_BP::BackPropagate(void)
{
	DOUBLE Out, Err;

	//反向计算误差
	for(INT i=nLayer-2; i>=0; i--)
	{
		for(INT j=0; j<pLayer[i].nNode; j++)
		{
			Out = pLayer[i].pOutput[j];
			Err = 0;

			for(INT k=0; k<pLayer[i+1].nNode; k++)
			{
				Err += pLayer[i+1].pError[k] * pLayer[i+1].ppWeight[k][j];
			}
			
			pLayer[i].pError[j] = Out * (1-Out) * Err;
		}
	}

	//调整权值
 	for(INT i=nLayer-1; i>=0; i--)		//层
	{
		for(INT j=0; j<pLayer[i].nNode; j++)
		{
			for(INT k=0; k<pLayer[i].nInput; k++)
			{
				//if(i==0)
				//{
				//	Out = pLayer[0].pInput[k];
				//}
				//else
				//{
					Out = pLayer[i].pInput[k];

				//}

				Err = pLayer[i].pError[j];
				pLayer[i].ppWeight[j][k] += this->Eta *Out*Err + this->Alpha*pLayer[i].ppDWeight[j][k];
				pLayer[i].ppDWeight[j][k] = this->Eta *Err * Out + this->Alpha*pLayer[i].ppDWeight[j][k];
			}
		}
	}
}



// 构建网络,分配变量空间
void CNeuroNet_BP::GenerateNet(void)
{
	for(INT i=0; i<nLayer; i++)
	{
		if(i==0)
		{
			pLayer[i].nInput = this->nInput;
		}
		else
		{
			pLayer[i].nInput = pLayer[i-1].nNode;
		}

		pLayer[i].pOutput = new DOUBLE[pLayer[i].nNode];		//为输出数据分配空间
		pLayer[i].pError = new DOUBLE[pLayer[i].nNode];			//为节点误差分配空间
		pLayer[i].ppWeight = new DOUBLE*[pLayer[i].nNode ];		//给权值的指针分配空间
		pLayer[i].ppDWeight = new DOUBLE*[pLayer[i].nNode ];	//给权值增量分配空间

		for(INT j=0; j<pLayer[i].nNode; j++)
		{
			pLayer[i].ppWeight[j] = new DOUBLE[pLayer[i].nInput];		//给每个节点的权值分配空间
			pLayer[i].ppDWeight[j] = new DOUBLE[pLayer[i].nInput];		//给每个权值增量分配空间
		}
	}

	this->pOutput = pLayer[nLayer-1].pOutput;
}

⌨️ 快捷键说明

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