c++调用matlab神经网络,BP神经网络原理及C++实战

前一段时间做了一个数字识别的小系统,基于BP神经网络算法的,用MFC做的交互。在实现过程中也试着去找一些源码,总体上来讲,这些源码的可移植性都不好,多数将交互部分和核心算法代码杂糅在一起,这样不仅代码阅读困难,而且重要的是核心算法不具备可移植性。设计模式,设计模式的重要性啊!于是自己将BP神经网络的核心算法用标准C++实现,这样可移植性就有保证的,然后在核心算法上实现基于不同GUI库的交互(MFC,QT)是能很快的搭建好系统的。下面边介绍BP算法的原理(请看《数字图像处理与机器视觉》非常适合做工程的伙伴),边给出代码的实现,最后给出基于核心算法构建交互的例子。

人工神经网络的理论基础

1.感知器

感知器是一种具有简单的两种输出的人工神经元,如下图所示。

c++调用matlab神经网络,BP神经网络原理及C++实战_第1张图片

2.线性单元

只有1和-1两种输出的感知器实际上限制了其处理和分类的能力,下图是一种简单的推广,即不带阈值的感知器。

c++调用matlab神经网络,BP神经网络原理及C++实战_第2张图片

3.误差准则

使用的是一个常用的误差度量标准,平方误差准则。公式如下。

95732e0ea88892cd264ff7a38d9b5437.png

其中D为训练样本,td为训练观测值d的训练输出,ot为观测值d的实际观测值。如果是个凸函数就好了(搞数学的,一听到凸函数就很高兴,呵呵!),但还是可以用梯度下降的方法求其参数w。

4.梯度下降推导

在高等数学中梯度的概念实际上就是一个方向向量,也就是方向导数最大的方向,也就是说沿着这个方向,函数值的变化速度最快。我们这里是做梯度下降,那么就是沿着梯度的负方向更新参数w的值来快速达到E函数值的最小了。这样梯度下降算法的步骤基本如下:

1)初始化参数w(随机,或其它方法)。

2)求梯度。

3)沿梯度方向更新参数w,可以添加一个学习率,也就是按多大的步子下降。

4)重复1),2),3)直到达到设置的条件(迭代次数,或者E的减小量小于某个阈值)。

梯度的表达式如下:

cf8a73942b54f4e65f9fad99412b57a6.png

那么如何求梯度呢?就是复合函数求导的过程,如下:

c++调用matlab神经网络,BP神经网络原理及C++实战_第3张图片

其中xid为样本中第d个观测值对应的一个输入分量xi。这样,训练过程中参数w的更新表达式如下(其中添加了一个学习率,也就是下降的步长):

c++调用matlab神经网络,BP神经网络原理及C++实战_第4张图片

于是参数wi的更新增量为:

d69ba0ef81427f30e26b852a0c22fadf.png

对于学习率选择的问题,一般较小是能够保证收敛的,看下图吧。

c++调用matlab神经网络,BP神经网络原理及C++实战_第5张图片

5.增量梯度下降

对于4中的梯度下降算法,其缺点是有时收敛速度慢,如果在误差曲面上存在多个局部极小值,算法不能保证能够找到全局极小值。为了改善这些缺点,提出了增量梯度下降算法。增量梯度下降,与4中的梯度下降的不同之处在于,4中对参数w的更新是根据整个样本中的观测值的误差来计算的,而增量梯度下降算法是根据样本中单个观测值的误差来计算w的更新。

6.梯度检验

这是一个比较实用的内容,如何确定自己的代码就一定没有错呢?因为在求梯度的时候是很容易犯错误的,我就犯过了,嗨,调了两天才找出来,一个数组下表写错了,要是早一点看看斯坦福大学的深度学习基础教程就好了,这里只是截图一部分,有时间去仔细看看吧。

c++调用matlab神经网络,BP神经网络原理及C++实战_第6张图片

多层神经网络

好了有了前面的基础,我们现在就可以进行实战了,构造多层神经网络。

1.Sigmoid神经元

Sigmoid神经元可由下图表示:

c++调用matlab神经网络,BP神经网络原理及C++实战_第7张图片

2.神经网络层

一个三层的BP神经网络可由下图表示:

c++调用matlab神经网络,BP神经网络原理及C++实战_第8张图片

3.神经元和神经网络层的标准C++定义

由2中的三层BP神经网络的示意图中可以看出,隐藏层和输出层是具有类似的结构的。神经元和神经网络层的定义如下:

// Neuron.h

#ifndef __SNEURON_H__

#define __SNEURON_H__

#define NEED_MOMENTUM //if you want to addmomentum, remove the annotation

#define MOMENTUM 0.6 //momentumcoefficient, works on when defined NEED_MOMENTUM

typedef double WEIGHT_TYPE; // definedatatype of the weight

struct SNeuron{//neuron cell

/******Data*******/

intm_nInput; //number of inputs

WEIGHT_TYPE*m_pWeights;  //weights array of inputs

#ifdef NEED_MOMENTUM

WEIGHT_TYPE*m_pPrevUpdate; //record last weights update when momentum is needed

#endif

doublem_dActivation; //output value, through Sigmoid function

doublem_dError; //error value of neuron

/********Functions*************/

voidInit(int nInput){

m_nInput= nInput + 1; //add a side term,number of inputs is actual number of actualinputs plus 1

m_pWeights= new WEIGHT_TYPE[m_nInput];//allocate for weights array

#ifdef NEED_MOMENTUM

m_pPrevUpdate= new WEIGHT_TYPE[m_nInput];//allocate for the last weights array

#endif

m_dActivation= 0; //output value, through SIgmoid function

m_dError= 0;  //error value of neuron

}

~SNeuron(){

//releasememory

delete[]m_pWeights;

#ifdef NEED_MOMENTUM

delete[]m_pPrevUpdate;

#endif

}

};//SNeuron

struct SNeuronLayer{//neuron layer

/************Data**************/

intm_nNeuron; //Neuron number of this layer

SNeuron*m_pNeurons; //Neurons array

/*************Functions***************/

SNeuronLayer(intnNeuron, int nInputsPerNeuron){

m_nNeuron= nNeuron;

m_pNeurons= new SNeuron[nNeuron];  //allocatememory for nNeuron neurons

for(inti=0; i

m_pNeurons[i].Init(nInputsPerNeuron);  //initialize neuron

}

}

~SNeuronLayer(){

delete[]m_pNeurons;  //release neurons array

}

};//SNeuronLayer

#endif//__SNEURON_H__

代码中定义了一个NEED_MOMENTUM,它是用来解决局部极小值的问题的,其含义是本次权重的更新是依赖于上一次权重更新的。另外还有一种解决局部极小值问题的方法是,将w初始化为接近于0的随机数。

4.反向传播(BP)算法

前面虽然有了神经元和神经网络层的定义,但要构造一个三层的BP神经网络之前,还要搞清楚BP算法是如何来学习神经网络的参数的。它仍采用梯度下降算法,但不同的是这里的输出是整个网络的输出,而不再是一个单元的输出,所有对误差函数E重新定义如下:

d47915511bbcee5925318d52d52d5708.png

其中outputs是网络中输出层单元的集合,tkd,okd是训练样本中第d个观测值在第k个输出单元的而输出值。

1)BP算法推导

先引入下列符号:

c++调用matlab神经网络,BP神经网络原理及C++实战_第9张图片

增量梯度下降算法中,对于每个训练样本中第d个观测的一个输入权重wij的增量如下表示:

3e7b2d7b542ad05ac5e30b6084e24aca.png

其中Ed是训练样本中第d个观测的误差,通过对输出层所有单元的求和得到:

ed923b990002011cf55e1295a750cfdb.png

这里说明一下,神经网络输出层的所有单元联合一起表示一个样本观测的训练值的。假设样本观测值为5种,即5种类别,那么先验训练数据的类别表示为:1,0,0,0,0;0,1,0,0,0;0,0,1,0,0;0,0,0,1,0;0,0,0,0,1。这样在对神经网络训练时,我们的训练输出值的表示也就是类似的,当然基于神经元的结构表示,我们也可以将先验训练数据的类别表示中的1换成0.9等。

下面我们就要求梯度了(要分层求解,输出层,隐藏层),梯度向量中的各元素求解如下:

c++调用matlab神经网络,BP神经网络原理及C++实战_第10张图片

1)当单元j是一个输出单元时:

5f3471731d0f12220f02660fa0e1f505.png

其中:

c++调用matlab神经网络,BP神经网络原理及C++实战_第11张图片

于是得到:

c++调用matlab神经网络,BP神经网络原理及C++实战_第12张图片

2)当单元j是一个隐藏层单元时,有如下推导:

c++调用matlab神经网络,BP神经网络原理及C++实战_第13张图片

5.标准C++构建三层BP神经网络

该神经网络提供了重要的两个接口。一个是一次训练训练接口TrainingEpoch,可用于上层算法构建训练函数时调用;另一个是计算给定一个输入神经网络的输出接口CalculateOutput,它在一次训练函数中被调用,更重要的是,在上层算法中构建识别函数调用。

头文件:// NeuralNet.h: interface for theCNeuralNet class.

//

//

#ifndef __NEURALNET_H__

#define __NEURALNET_H__

#include 

#include 

#include "Neuron.h"

using namespace std;

typedef vector iovector;

#define BIAS 1 //bias term's coefficient w0

/*************Random functions initializingweights*************/

#define WEIGHT_FACTOR 0.1 //used to confineinitial weights

/*Return a random float between 0 to 1*/

inline double RandFloat(){ return(rand())/(RAND_MAX+1.0); }

/*Return a random float between -1 to 1*/

inline double RandomClamped(){ returnWEIGHT_FACTOR*(RandFloat() - RandFloat()); }

class CNeuralNet{

private:

/*Initialparameters, can not be changed throghout the whole training.*/

intm_nInput;  //number of inputs

intm_nOutput; //number of outputs

intm_nNeuronsPerLyr; //unit number of hidden layer

intm_nHiddenLayer; //hidden layer, not including the output layer

/***Dinamicparameters****/

doublem_dErrorSum;  //one epoch's sum-error

SNeuronLayer*m_pHiddenLyr;  //hidden layer

SNeuronLayer*m_pOutLyr;     //output layer

public:

/*

*Constructorand Destructor.

*/

CNeuralNet(intnInput, int nOutput, int nNeuronsPerLyr, int nHiddenLayer);

~CNeuralNet();

/*

*Computeoutput of network, feedforward.

*/

bool CalculateOutput(vector input,vector& output);

/*

*Trainingan Epoch, backward adjustment.

*/

bool TrainingEpoch(vector& SetIn,vector& SetOut, double LearningRate);

/*

*Geterror-sum.

*/

doubleGetErrorSum(){ return m_dErrorSum; }

SNeuronLayer*GetHiddenLyr(){ return m_pHiddenLyr; }

SNeuronLayer*GetOutLyr(){ return m_pOutLyr; }

private:

/*

*Biuldnetwork, allocate memory for each layer.

*/

voidCreateNetwork();

/*

*Initializenetwork.

*/

voidInitializeNetwork();

/*

*Sigmoidencourage fuction.

*/

doubleSigmoid(double netinput){

doubleresponse = 1.0;  //control steep degreeof sigmoid function

return(1 / ( 1 + exp(-netinput / response) ) );

}

};

#endif //__NEURALNET_H__

实现文件:// NeuralNet.cpp: implementation of theCNeuralNet class.

//

//

#include "stdafx.h"

#include "NeuralNet.h"

#include 

CNeuralNet::CNeuralNet(int nInput, intnOutput, int nNeuronsPerLyr, int nHiddenLayer){

assert(nInput>0 && nOutput>0 && nNeuronsPerLyr>0 &&nHiddenLayer>0 );

m_nInput= nInput;

m_nOutput= nOutput;

m_nNeuronsPerLyr= nNeuronsPerLyr;

if(nHiddenLayer!= 1)

m_nHiddenLayer= 1;

else

m_nHiddenLayer= nHiddenLayer; //temporarily surpport only one hidden layer

m_pHiddenLyr= NULL;

m_pOutLyr= NULL;

CreateNetwork();   //allocate for each layer

InitializeNetwork();  //initialize the whole network

}

CNeuralNet::~CNeuralNet(){

if(m_pHiddenLyr!= NULL)

deletem_pHiddenLyr;

if(m_pOutLyr!= NULL)

deletem_pOutLyr;

}

void CNeuralNet::CreateNetwork(){

m_pHiddenLyr= new SNeuronLayer(m_nNeuronsPerLyr, m_nInput);

m_pOutLyr= new SNeuronLayer(m_nOutput, m_nNeuronsPerLyr);

}

void CNeuralNet::InitializeNetwork(){

inti, j;  //variables for loop

/*usepresent time as random seed, so every time runs this programm can producedifferent random sequence*/

//srand((unsigned)time(NULL) );

/*initializehidden layer's weights*/

for(i=0;im_nNeuron; i++){

for(j=0;jm_pNeurons[i].m_nInput; j++){

m_pHiddenLyr->m_pNeurons[i].m_pWeights[j]= RandomClamped();

#ifdefNEED_MOMENTUM

/*whenthe first epoch train started, there is no previous weights update*/

m_pHiddenLyr->m_pNeurons[i].m_pPrevUpdate[j]= 0;

#endif

}

}

/*initializeoutput layer's weights*/

for(i=0;im_nNeuron; i++){

for(intj=0; jm_pNeurons[i].m_nInput; j++){

m_pOutLyr->m_pNeurons[i].m_pWeights[j]= RandomClamped();

#ifdefNEED_MOMENTUM

/*whenthe first epoch train started, there is no previous weights update*/

m_pOutLyr->m_pNeurons[i].m_pPrevUpdate[j]= 0;

#endif

}

}

m_dErrorSum= 9999.0;  //initialize a large trainingerror, it will be decreasing with training

}

boolCNeuralNet::CalculateOutput(vector input,vector& output){

if(input.size()!= m_nInput){ //input feature vector's dimention not equals to input of network

returnfalse;

}

inti, j;

doublenInputSum;  //sum term

/*computehidden layer output*/

for(i=0;im_nNeuron; i++){

nInputSum= 0;

for(j=0;jm_pNeurons[i].m_nInput-1; j++){

nInputSum+= m_pHiddenLyr->m_pNeurons[i].m_pWeights[j] * input[j];

}

/*plusbias term*/

nInputSum+= m_pHiddenLyr->m_pNeurons[i].m_pWeights[j] * BIAS;

/*computesigmoid fuction's output*/

m_pHiddenLyr->m_pNeurons[i].m_dActivation= Sigmoid(nInputSum);

}

/*computeoutput layer's output*/

for(i=0;im_nNeuron; i++){

nInputSum= 0;

for(j=0;jm_pNeurons[i].m_nInput-1; j++){

nInputSum+= m_pOutLyr->m_pNeurons[i].m_pWeights[j]

*m_pHiddenLyr->m_pNeurons[j].m_dActivation;

}

/*plusbias term*/

nInputSum+= m_pOutLyr->m_pNeurons[i].m_pWeights[j] * BIAS;

/*computesigmoid fuction's output*/

m_pOutLyr->m_pNeurons[i].m_dActivation= Sigmoid(nInputSum);

/*saveit to the output vector*/

output.push_back(m_pOutLyr->m_pNeurons[i].m_dActivation);

}

returntrue;

}

bool CNeuralNet::TrainingEpoch(vector&SetIn, vector& SetOut, double LearningRate){

inti, j, k;

doubleWeightUpdate;  //weight's update value

doubleerr;  //error term

/*increment'sgradient decrease(update weights according to each training sample)*/

m_dErrorSum= 0;  // sum of error term

for(i=0;i

iovectorvecOutputs;

/*forwardlyspread inputs through network*/

if(!CalculateOutput(SetIn[i],vecOutputs)){

returnfalse;

}

/*updatethe output layer's weights*/

for(j=0;jm_nNeuron; j++){

/*computeerror term*/

err= ((double)SetOut[i][j]-vecOutputs[j])*vecOutputs[j]*(1-vecOutputs[j]);

m_pOutLyr->m_pNeurons[j].m_dError= err;  //record this unit's error

/*updatesum error*/

m_dErrorSum+= ((double)SetOut[i][j] - vecOutputs[j]) * ((double)SetOut[i][j] -vecOutputs[j]);

/*updateeach input's weight*/

for(k=0;km_pNeurons[j].m_nInput-1; k++){

WeightUpdate= err * LearningRate * m_pHiddenLyr->m_pNeurons[k].m_dActivation;

#ifdef NEED_MOMENTUM

/*updateweights with momentum*/

m_pOutLyr->m_pNeurons[j].m_pWeights[k]+=

WeightUpdate+ m_pOutLyr->m_pNeurons[j].m_pPrevUpdate[k] * MOMENTUM;

m_pOutLyr->m_pNeurons[j].m_pPrevUpdate[k]= WeightUpdate;

#else

/*updateunit weights*/

m_pOutLyr->m_pNeurons[j].m_pWeights[k]+= WeightUpdate;

#endif

}

/*biasupdate volume*/

WeightUpdate= err * LearningRate * BIAS;

#ifdef NEED_MOMENTUM

/*updatebias with momentum*/

m_pOutLyr->m_pNeurons[j].m_pWeights[k]+=

WeightUpdate+ m_pOutLyr->m_pNeurons[j].m_pPrevUpdate[k] * MOMENTUM;

m_pOutLyr->m_pNeurons[j].m_pPrevUpdate[k]= WeightUpdate;

#else

/*updatebias*/

m_pOutLyr->m_pNeurons[j].m_pWeights[k]+= WeightUpdate;

#endif

}//for out layer

/*updatethe hidden layer's weights*/

for(j=0;jm_nNeuron; j++){

err= 0;

for(intk=0; km_nNeuron; k++){

err+= m_pOutLyr->m_pNeurons[k].m_dError *m_pOutLyr->m_pNeurons[k].m_pWeights[j];

}

err*= m_pHiddenLyr->m_pNeurons[j].m_dActivation * (1 -m_pHiddenLyr->m_pNeurons[j].m_dActivation);

m_pHiddenLyr->m_pNeurons[j].m_dError= err;  //record this unit's error

/*updateeach input's weight*/

for(k=0;km_pNeurons[j].m_nInput-1; k++){

WeightUpdate= err * LearningRate * SetIn[i][k];

#ifdef NEED_MOMENTUM

/*updateweights with momentum*/

m_pHiddenLyr->m_pNeurons[j].m_pWeights[k]+=

WeightUpdate+ m_pHiddenLyr->m_pNeurons[j].m_pPrevUpdate[k] * MOMENTUM;

m_pHiddenLyr->m_pNeurons[j].m_pPrevUpdate[k]= WeightUpdate;

#else

m_pHiddenLyr->m_pNeurons[j].m_pWeights[k]+= WeightUpdate;

#endif

}

/*biasupdate volume*/

WeightUpdate= err * LearningRate * BIAS;

#ifdef NEED_MOMENTUM

/*updatebias with momentum*/

m_pHiddenLyr->m_pNeurons[j].m_pWeights[k]+=

WeightUpdate+ m_pHiddenLyr->m_pNeurons[j].m_pPrevUpdate[k] * MOMENTUM;

m_pHiddenLyr->m_pNeurons[j].m_pPrevUpdate[k]= WeightUpdate;

#else

/*updatebias*/

m_pHiddenLyr->m_pNeurons[j].m_pWeights[k]+= WeightUpdate;

#endif

}//forhidden layer

}//forone epoch

returntrue;

}

6.基于BP核心算法构建MVC框架

到此为止我们的核心算法已经构建出来了,再应用两次Strategy 设计模式,我们就很容易构建出一个MVC框架(see also:http://remyspot.blog.51cto.com/8218746/1574484)。下面给出一个应用Strategy设计模式基于CNeuralNet类构建一个Controller,在Controller中我们就可以开始依赖特定的GUI库了。下面的这个Controller是不能直接使用的,你所要做的是参考该代码(重点参看

boolTrain(vector& SetIn, vector& SetOut);

bool SaveTrainResultToFile(const char* lpszFileName, boolbCreate);

bool LoadTrainResultFromFile(const char* lpszFileName, DWORDdwStartPos);

int Recognize(CString strPathName, CRect rt, double&dConfidence);

接口的实现), 然后基于前面的核心BP算构建你自己的Controller,然后在该Controller的上层实现你自己的交互功能。

说明一下,Train接口中的SetIn是训练数据的特征,SetOut是训练数据的类别表示。

头文件:#ifndef __OPERATEONNEURALNET_H__

#define __OPERATEONNEURALNET_H__

#include "NeuralNet.h"

#define NEURALNET_VERSION 1.0

#define RESAMPLE_LEN 4

class COperateOnNeuralNet{

private:

/*network*/

CNeuralNet*m_oNetWork;

/*network'sparameter*/

intm_nInput;

intm_nOutput;

intm_nNeuronsPerLyr;

intm_nHiddenLayer;

/*trainingconfiguration*/

intm_nMaxEpoch;  // max training epoch times

doublem_dMinError; // error threshold

doublem_dLearningRate;

/*dinamiccurrent parameter*/

intm_nEpochs;

doublem_dErr;  //mean error of oneepoch(m_dErrorSum/(num-of-samples * num-of-output))

boolm_bStop; //control whether stop or not during the training

vector m_vecError;   //record each epoch'straining error, used for drawing error curve

public:

COperateOnNeuralNet();

~COperateOnNeuralNet();

voidSetNetWorkParameter(int nInput, int nOutput, int nNeuronsPerLyr, intnHiddenLayer);

boolCreatNetWork();

voidSetTrainConfiguration(int nMaxEpoch, double dMinError, double dLearningRate);

voidSetStopFlag(bool bStop) { m_bStop = bStop; }

doubleGetError(){ return m_dErr; }

intGetEpoch(){ return m_nEpochs; }

intGetNumNeuronsPerLyr(){ return m_nNeuronsPerLyr; }

boolTrain(vector& SetIn, vector& SetOut);

bool SaveTrainResultToFile(const char* lpszFileName, boolbCreate);

bool LoadTrainResultFromFile(const char* lpszFileName, DWORDdwStartPos);

int Recognize(CString strPathName, CRect rt, double&dConfidence);

};

/*

* Can be used when saving or readingtraining result.

*/

struct NEURALNET_HEADER{

DWORDdwVersion;  //version imformation

/*initialparameters*/

intm_nInput;  //number of inputs

intm_nOutput; //number of outputs

intm_nNeuronsPerLyr; //unit number of hidden layer

intm_nHiddenLayer; //hidden layer, not including the output layer

/*trainingconfiguration*/

intm_nMaxEpoch;  // max training epoch times

doublem_dMinError; // error threshold

doublem_dLearningRate;

/*dinamiccurrent parameter*/

intm_nEpochs;

doublem_dErr;  //mean error of oneepoch(m_dErrorSum/(num-of-samples * num-of-output))

};

#endif //__OPERATEONNEURALNET_H__

实现文件:// OperateOnNeuralNet.cpp: implementationof the COperateOnNeuralNet class.

//

//

#include "stdafx.h"

#include "MyDigitRec.h"

#include "OperateOnNeuralNet.h"

#include "Img.h"

#include 

/*

*Handle message during waiting.

*/

void WaitForIdle()

{

MSGmsg;

while(::PeekMessage(&msg,NULL, 0, 0, PM_REMOVE))

{

::TranslateMessage(&msg);

::DispatchMessage(&msg);

}

}

COperateOnNeuralNet::COperateOnNeuralNet(){

m_nInput= 0;

m_nOutput= 0;

m_nNeuronsPerLyr= 0;

m_nHiddenLayer= 0;

m_nMaxEpoch= 0;

m_dMinError= 0;

m_dLearningRate= 0;

m_oNetWork= 0;

m_nEpochs= 0;

m_dErr= 0;

m_bStop= false;

}

COperateOnNeuralNet::~COperateOnNeuralNet(){

if(m_oNetWork)

deletem_oNetWork;

}

voidCOperateOnNeuralNet::SetNetWorkParameter(int nInput, int nOutput, intnNeuronsPerLyr, int nHiddenLayer){

assert(nInput>0 && nOutput>0 && nNeuronsPerLyr>0 &&nHiddenLayer>0 );

m_nInput= nInput;

m_nOutput= nOutput;

m_nNeuronsPerLyr= nNeuronsPerLyr;

m_nHiddenLayer= nHiddenLayer;

}

bool COperateOnNeuralNet::CreatNetWork(){

assert(m_nInput>0 && m_nOutput>0 && m_nNeuronsPerLyr>0&& m_nHiddenLayer>0 );

m_oNetWork= new CNeuralNet(m_nInput, m_nOutput, m_nNeuronsPerLyr, m_nHiddenLayer);

if(m_oNetWork)

returntrue;

else

returnfalse;

}

voidCOperateOnNeuralNet::SetTrainConfiguration(int nMaxEpoch, double dMinError,double dLearningRate){

assert(nMaxEpoch>0&& !(dMinError<0) && dLearningRate!=0);

m_nMaxEpoch= nMaxEpoch;

m_dMinError= dMinError;

m_dLearningRate= dLearningRate;

}

boolCOperateOnNeuralNet::Train(vector& SetIn, vector&SetOut){

m_bStop= false;  //no stop during training

CStringstrOutMsg;

do{

/*trainone epoch*/

if(!m_oNetWork->TrainingEpoch(SetIn, SetOut, m_dLearningRate) ){

strOutMsg.Format("Erroroccured at training %dth epoch!",m_nEpochs+1);

AfxMessageBox(strOutMsg);

returnfalse;

}else{

m_nEpochs++;

}

/*computemean error of one epoch(m_dErrorSum/(num-of-samples * num-of-output))*/

intsum = m_oNetWork->GetErrorSum();

m_dErr= m_oNetWork->GetErrorSum() / ( m_nOutput * SetIn.size() );

m_vecError.push_back(m_dErr);

if(m_dErr

break;

}

/*stopin loop to chech wether user's action made or message sent, mostly for changem_bStop */

WaitForIdle();

if(m_bStop){

break;

}

}while(--m_nMaxEpoch> 0);

returntrue;

}

boolCOperateOnNeuralNet::SaveTrainResultToFile(const char* lpszFileName, boolbCreate){

CFilefile;

if(bCreate){

if(!file.Open(lpszFileName,CFile::modeWrite|CFile::modeCreate))

returnfalse;

}else{

if(!file.Open(lpszFileName,CFile::modeWrite))

returnfalse;

file.SeekToEnd();  //add to end of file

}

/*createnetwork head information*/

/*initialparameter*/

NEURALNET_HEADERheader = {0};

header.dwVersion= NEURALNET_VERSION;

header.m_nInput= m_nInput;

header.m_nOutput= m_nOutput;

header.m_nNeuronsPerLyr= m_nNeuronsPerLyr;

header.m_nHiddenLayer= m_nHiddenLayer;

/*trainingconfiguration*/

header.m_nMaxEpoch= m_nMaxEpoch;

header.m_dMinError= m_dMinError;

header.m_dLearningRate= m_dLearningRate;

/*dinamiccurrent parameter*/

header.m_nEpochs= m_nEpochs;

header.m_dErr= m_dErr;

file.Write(&header,sizeof(header));

/*writeweight information to file*/

inti, j;

/*hiddenlayer weight*/

for(i=0;iGetHiddenLyr()->m_nNeuron; i++){

file.Write(&m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_dActivation,

sizeof(m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_dActivation));

file.Write(&m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_dError,

sizeof(m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_dError));

for(j=0;jGetHiddenLyr()->m_pNeurons[i].m_nInput; j++){

file.Write(&m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_pWeights[j],

sizeof(m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_pWeights[j]));

}

}

/*outputlayer weight*/

for(i=0;iGetOutLyr()->m_nNeuron; i++){

file.Write(&m_oNetWork->GetOutLyr()->m_pNeurons[i].m_dActivation,

sizeof(m_oNetWork->GetOutLyr()->m_pNeurons[i].m_dActivation));

file.Write(&m_oNetWork->GetOutLyr()->m_pNeurons[i].m_dError,

sizeof(m_oNetWork->GetOutLyr()->m_pNeurons[i].m_dError));

for(j=0;jGetOutLyr()->m_pNeurons[i].m_nInput; j++){

file.Write(&m_oNetWork->GetOutLyr()->m_pNeurons[i].m_pWeights[j],

sizeof(m_oNetWork->GetOutLyr()->m_pNeurons[i].m_pWeights[j]));

}

}

file.Close();

returntrue;

}

boolCOperateOnNeuralNet::LoadTrainResultFromFile(const char* lpszFileName, DWORDdwStartPos){

CFilefile;

if(!file.Open(lpszFileName,CFile::modeRead)){

returnfalse;

}

file.Seek(dwStartPos,CFile::begin);  //point to dwStartPos

/*readin NeuralNet_Head infomation*/

NEURALNET_HEADERheader = {0};

if(file.Read(&header, sizeof(header)) != sizeof(header) ){

returnfalse;

}

/*chechversion*/

if(header.dwVersion!= NEURALNET_VERSION){

returnfalse;

}

/*checkbasic NeuralNet's structure*/

if(header.m_nInput!= m_nInput

||header.m_nOutput != m_nOutput

||header.m_nNeuronsPerLyr != m_nNeuronsPerLyr

||header.m_nHiddenLayer != m_nHiddenLayer

||header.m_nMaxEpoch != m_nMaxEpoch

||header.m_dMinError != m_dMinError

||header.m_dLearningRate != m_dLearningRate ){

returnfalse;

}

/*dynamicparameters*/

m_nEpochs= header.m_nEpochs;  //update trainingepochs

m_dErr= header.m_dErr;                    //update training error

/*readin NetWork's weights*/

inti,j;

/*readin hidden layer weights*/

for(i=0;iGetHiddenLyr()->m_nNeuron; i++){

file.Read(&m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_dActivation,

sizeof(m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_dActivation));

file.Read(&m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_dError,

sizeof(m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_dError));

for(j=0;jGetHiddenLyr()->m_pNeurons[i].m_nInput; j++){

file.Read(&m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_pWeights[j],

sizeof(m_oNetWork->GetHiddenLyr()->m_pNeurons[i].m_pWeights[j]));

}

}

/*readin out layer weights*/

for(i=0;iGetOutLyr()->m_nNeuron; i++){

file.Read(&m_oNetWork->GetOutLyr()->m_pNeurons[i].m_dActivation,

sizeof(m_oNetWork->GetOutLyr()->m_pNeurons[i].m_dActivation));

file.Read(&m_oNetWork->GetOutLyr()->m_pNeurons[i].m_dError,

sizeof(m_oNetWork->GetOutLyr()->m_pNeurons[i].m_dError));

for(j=0;jGetOutLyr()->m_pNeurons[i].m_nInput; j++){

file.Read(&m_oNetWork->GetOutLyr()->m_pNeurons[i].m_pWeights[j],

sizeof(m_oNetWork->GetOutLyr()->m_pNeurons[i].m_pWeights[j]));

}

}

returntrue;

}

int COperateOnNeuralNet::Recognize(CStringstrPathName, CRect rt, double &dConfidence){

intnBestMatch;  //category number

doubledMaxOut1 = 0; //max output

doubledMaxOut2 = 0; //second max output

CImggray;

if(!gray.AttachFromFile(strPathName)){

return-1;

}

/*convert the picture waitiong for being recognized to vector*/

vectorvecToRec;

for(intj=rt.top; j

for(inti=rt.left; i

intnGray = 0;

for(intmm=j; mm

for(intnn=i; nn

nGray+= gray.GetGray(nn, mm);

}

nGray/= RESAMPLE_LEN*RESAMPLE_LEN;

vecToRec.push_back(nGray/255.0);

}

}

/*computethe output result*/

vectoroutputs;

if(!m_oNetWork->CalculateOutput(vecToRec,outputs)){

AfxMessageBox("Recfailed!");

return-1;

}

/*findthe max output unit, and its unit number is the category number*/

nBestMatch= 0;

for(intk=0; k

if(outputs[k]> dMaxOut1){

dMaxOut2= dMaxOut1;

dMaxOut1= outputs[k];

nBestMatch= k;

}

}

dConfidence= dMaxOut1 - dMaxOut2;  //compute beliefdegree

returnnBestMatch;

}

你可能感兴趣的:(c++调用matlab神经网络)