3个神经网络代码

  • 格式:docx
  • 大小:27.14 KB
  • 文档页数:18

LOGICNERVECELL *NN::findNerveCell(U2 n) /*tmpnc 指向找到的神经元的前一个 *nc指向找到的那个*/{LOGICNERVECELL *tmpnc;if(*nc->nc->nerve_cell_num == n){return(*tmpnc);}else if(*nv->next == NULL){*nc = frist_nc; /*重新指向第一个*/return(NULL);}else{tmpnc = *nc;*nc = *nc->next;findNerveCell(n);}return(NULL);}NN::NN(U2 init){INIT = init;n_cell = INIT;recycle_cell = 0;recycle = (LOGICNERVECELL *)(malloc(sizeof(LOGICNERVECELL))*MAX_RECYCLE);/*================================================================*/*nc = (LOGICNERVECELL *)(malloc(sizeof(LOGICNERVECELL)));*nc->nc = (NERVECELL*)(malloc(sizeof(NERVECELL)));*nc->nc->nerve_cell_num = 1;*nc->nc->input = NULL;*nc->nc->output = NULL;frist_nc = *nc;for(int i=2;i<=n_cell;i++){*nc->next = (LOGICNERVECELL *)(malloc(sizeof(LOGICNERVECELL)));*nc->next->nc = (NERVECELL*)(malloc(sizeof(NERVECELL)));if(i==(n_cell)){*nc->next->nc->nerve_cell_num = i;*nc->next->nc->input = NULL;*nc->next->nc->output = NULL;*nc->next = NULL;}else{*nc->next->nc->nerve_cell_num = i;*nc->next->nc->input = NULL;*nc->next->nc->output = NULL;*nc = *nc->next;}}frist_nc = *nc; /*重新指想第一个神经元*/}NN::~NN(){//释放所有占用的内寸}void NN::addNerveCellByNum(U2 n) /*n为增加多少个*/{for(int i=1;i<=n;i++){*nc->next = (LOGICNERVECELL *)(malloc(sizeof(LOGICNERVECELL))); *nc->next->nc = (NERVECELL*)(malloc(sizeof(NERVECELL)));if(i==n){*nc->next->nc->nerve_cell_num = n_cell;*nc->next->nc->input = NULL;*nc->next->nc->output = NULL;*nc->next = NULL;}else{*nc->next->nc->nerve_cell_num = i+n_cell;*nc->next->nc->input = NULL;*nc->next->nc->output = NULL;*nc = *nc->next;}}*nc = frist_nc; /*重新指想第一个神经元*/n_cell = n_cell+n;return;}//**************基于BP的ANN类*******************// --Feathersky//***********************************************#ifndef ANN_BP_H#define ANN_BP_H#include "math.h"#include <stdlib.h>#include <iostream.h>#include <fstream.h>#include <iomanip.h>#include"MemoryTool1.h"//-------------------------------------------------------------------------------class ANN_BP{public:int nMethod; //动量项标志double Rate; //学习率int layer1; //输入层结点数int layer2; //中间层结点数int layer3; //输出层结点数double *Y1; //第一层输出double *Y2; //第二层输出double *Y3; //第三层输出double *Dest; //期望输出double **W1; //权值矩阵double **W2;double **SW1; //第一层权值的改变量动量项作法使用double **SW2; //第二层权值的改变量动量项作法使用double *S3; //辅助变量double *S2; //辅助变量double **G1_1; //第一层权值距阵各分量偏导double **G2_1; //第二层权值距阵各分量偏导public:// 类构造函数,输入参数为3层BP网络每层的结点数。

// 在此函数中进行内存分配等初始化工作ANN_BP(){Y1=Y2=Y3=Dest=NULL;W1=W2=NULL;SW1=SW2=NULL;S3=S2=NULL;G1_1=G2_1=NULL;SetMethod();}ANN_BP(int input,int middle,int output){SetLayerNodeCount(input,middle,output);SetMethod();}// 类析构函数释放分配的内存~ANN_BP(){FreeMemory();}void FreeMemory(){delete[] Y1;delete[] Y2;delete[] Y3;delete[] Dest;free2D(W1);free2D(W2);free2D(SW1);free2D(SW2);delete[] S2;delete[] S3;free2D(G1_1);free2D(G2_1);}void SetLayerNodeCount(int input,int middle,int output) {FreeMemory();layer1=input+1; //输入层结点数layer2=middle; //中间层结点数layer3=output; //输出层结点数Y1 = new double[layer1];Y2 = new double[layer2];Y3 = new double[layer3];Dest= new double[layer3];W1 =malloc2D(layer2,layer1);W2 =malloc2D(layer3,layer2);SW1 =malloc2D(layer2,layer1);SW2 =malloc2D(layer3,layer2);S2 = new double[layer2];S3 = new double[layer3];G1_1 =malloc2D(layer2,layer1);G2_1 =malloc2D(layer3,layer2);initial();}void SetMethod(int method=0){nMethod=method; //是否使用动量项标志}private://用随机数初始化权值void initial(){for(int i=0;i<layer1;i++)for(int j=0;j<layer2;j++){W1[i][j]=(double)(rand()%2000-1000)/1000;if(W1[i][j]==0) W1[i][j]=0.1;}for( i=0;i<layer2;i++)for(int j=0;j<layer3;j++){W2[i][j]=(double)(rand()%2000-1000)/1000;if(W2[i][j]==0) W2[i][j]=0.1;}}int sgn(double i){if(i>0) return1;if(i<0) return -1;return0;}//sigmoid 函数double func(double i){// return (double)( (1-exp(-i))/(1+exp(-i)) );if(i<-45) return0;if(i>45) return1;return 1.0/(1.0+exp(-i));}/*我在程序中调试,曾遇见过此类溢出,故此技巧是必须的Subject: How to avoid overflow in the logistic function?The formula for the logistic activation function is often wri tten as:netoutput = 1 / (1+exp(-netinput));But this formula can produce floating-point overflow in the e xponential function if you program it in this simple form. To avo id overflow, you can do this:if (netinput < -45) netoutput = 0;else if (netinput > 45) netoutput = 1;else netoutput = 1 / (1+exp(-netinput));The constant 45 will work for double precision on all machine s that I know of, but there may be some bizarre machines where it will require some adjustment. Other activation functions can be handled similarly.*/void ComputeY() // 计算各层输出Y1[], Y2[],Y3[]{int i;for(i=0; i<layer2; i++){Y2[i]=0;for(int j=0;j<layer1;j++) Y2[i]+=Y1[j]*W1[j][i]; Y2[i]=func(Y2[i]);}for(i=0; i<layer3; i++){Y3[i]=0;for(int j=0;j<layer2;j++) Y3[i]+=Y2[j]*W2[j][i];Y3[i]=func(Y3[i]);}}void ComputeG() //计算误差对各层矩阵的偏导,求得梯度信息{int i,j;for(i=0;i<layer3;i++){S3[i]=(Dest[i]-Y3[i])*(1-Y3[i])*Y3[i];}for(i=0;i<layer2;i++){S2[i]=0;for(int j=0;j<layer3;j++) S2[i]+=W2[i][j]*S3[j];S2[i]*=(1-Y2[i]) * Y2[i];}for( i=0;i<layer1;i++ )for( j=0;j<layer2;j++ )G1_1[i][j]=Y1[i]*S2[j];for( i=0;i<layer2;i++ )for( j=0;j<layer3;j++ )G2_1[i][j]=Y2[i]*S3[j];}void WeightAdapt() // 按梯度方向修正权值{if(nMethod==0) //不使用动量项改进{for(int i=0;i<layer2;i++)for(int j=0;j<layer3;j++){W2[i][j]+=Rate*G2_1[i][j]; }for(i=0;i<layer1;i++)for(int j=0;j<layer2;j++){W1[i][j]+=Rate*G1_1[i][j];}}if(nMethod==1) //使用动量项改进此方式只有对一个样本训练的次数大于1时有用{for(int i=0;i<layer2;i++)for(int j=0;j<layer3;j++){W2[i][j]+=Rate*G2_1[i][j]+0.5*Rate*SW2[i][j];SW2[i][j]=Rate*G2_1[i][j];}for(i=0;i<layer1;i++)for(int j=0;j<layer2;j++){W1[i][j]+=Rate*G1_1[i][j]+0.5*Rate*SW1[i][j];SW1[i][j]=Rate*G1_1[i][j];}}}public://LimitTrainCount 最大训练次数//Error 允许学习误差double TrainOneCase(double Input[],double Out[],double Error= 0.000001,int LimitTrainCount=500){int w,h;if(nMethod==1){for( h=0; h<layer1; h++)for( w=0; w<layer2; w++){SW1[h][w]=0; //动量项置为0}for( h=0; h<layer2; h++)for( w=0; w<layer3; w++){SW2[h][w]=0; //动量项置为0}}Y1[layer1-1]=-1; //域值对应的输入for(int i=0;i<layer1-1;i++) Y1[i] = Input[i];for( i=0;i<layer3;i++) Dest[i] = Out[i];double TrainError;Rate=0.3;do{if(--LimitTrainCount<0) break;ComputeY();ComputeG();WeightAdapt();TrainError=0;for(i=0; i<layer3; i++) TrainError+=(Dest[i]-Y3[i] )*(Dest[i]-Y3[i])/2;Rate=0.05+TrainError/5; //根据误差自适应修改学习率}while(TrainError>Error); // 误差指标return TrainError; //返回误差}double ComputeError(double Input[],double Out[]){double TrainError=0;Y1[layer1-1]=-1;for(int i=0;i<layer1-1;i++) Y1[i] = Input[i];for( i=0;i<layer3;i++) Dest[i] = Out[i];ComputeY();for(i=0; i<layer3; i++) TrainError+=(Dest[i]-Y3[i])*(D est[i]-Y3[i])/2;return TrainError; //返回误差}//Out[]即为输出结果int DecideOneCase(double Input[],double Out[]){Y1[layer1-1]=-1;for(int i=0;i<layer1-1;i++) Y1[i] = Input[i];ComputeY();double max=0;int index=0;for(i=0;i<layer3; i++ ){Out[i]=Y3[i];if(Y3[i]>max){max=Y3[i];index=i;}}return index; //index 为out[]中最大的那个数的索引}/********************************************保存机制仅保存权重/*******************************************/int SaveWeight(char* file) //save the value of weight{ofstream in(file);in.precision(32);in<<layer1-1<<' '<<layer2<<' '<<layer3<<endl;for(int i=0;i<layer1;i++){for(int j=0;j<layer2;j++) in<<setw(64)<<W1[i][j]<< ' ';in<<endl;}in<<endl;for(i=0;i<layer2;i++){for(int j=0;j<layer3;j++) in<<setw(64)<<W2[i][j]<< ' ';in<<endl;}in.close();return1;}int LoadWeight(char * file) //load the value of weight{//CFileFind finder;//if(!finder.FindFile(file)) { initial(); return; } int input, middle, output;ifstream out(file);//out.precision(32);if(out.fail() || out.eof()) return0;out>>input>>middle>>output;SetLayerNodeCount(input,middle,output);for(int i=0;i<layer1;i++)for(int j=0;j<layer2;j++)out>>W1[i][j];for(i=0;i<layer2;i++)for(int j=0;j<layer3;j++)out>>W2[i][j];out.close();return1;}};#endif//--------------------二维数据内存管理----Feathersky-----------------------------------------------/*************************************************二维数据内存空间每行以DWORD方式对齐二位数据内存空间是连续的每行首地址另存于一数组**************************************************/#ifndef MEMORYTOOL1_H#define MEMORYTOOL1_H#include <malloc.h>/**************************************************************** ************* Funciton: malloc2D* Puroose: 分配二维数据内存空间***************************************************************** ***********/double ** malloc2D(int nW, int nH){double ** pLineHead=(double **)malloc(nH*sizeof(double *));double * pMem=(double *)malloc(nW*nH*sizeof(double));for(int i=0; i<nH; i++){pLineHead[i]=(double *)((BYTE *)pMem+nW*i*sizeof(double)) ;}return pLineHead;}/**************************************************************** ************* Funciton: Free2D* Puroose: 释放二维数据内存空间***************************************************************** ***********/inline void free2D(double ** & pLineHead){if(pLineHead){free(pLineHead[0]);free(pLineHead);}}#endif#include <cmath>#include <cstdlib>#include <cstdio>#include <ctime>//Rumelhart,1985,only one hidden layerconst double lr = 0.1;const double goal = 1e-1;const size_t SampleNum = 4;const size_t HidNeuron = 10;const size_t Input = 2;const size_t Output = 1;double Weight1[Input][HidNeuron] = {0};double Bias1[HidNeuron] = {0};double Weight2[HidNeuron][Output] = {0};double Bias2[Output] = {0};double InputValue[SampleNum][Input] ={0};double OutputValue[SampleNum][Output] ={0}; double Error[SampleNum][Output] = {0};double MSE = 1;void InitWeight(){size_t i,j;for( i=0; i<Input; i++){for(j=0; j<HidNeuron; j++){Weight1[i][j] = (rand()/(double)RAND_MAX)*2 - 1; }}for( i=0; i<HidNeuron; i++)Bias1[i] = (rand()/(double)RAND_MAX)*2 - 1;for( i=0; i<HidNeuron; i++){for(j=0; j<Output; j++){Weight2[i][j] = (rand()/(double)RAND_MAX)*2 - 1; }}for( i=0; i<Output; i++)Bias2[i] = (rand()/(double)RAND_MAX)*2 - 1;}double LogSigmoid(double x){return 1/(1+exp(-x));}double DetLogSigmoid(double x){return LogSigmoid(x) - pow(LogSigmoid(x),2.0); }void Computing(){size_t i,j,k;double sum=0;double hidOutput[SampleNum][HidNeuron] = {0}; double finOutput[SampleNum][Output] = {0};double detOutput[Output] = {0};double detHid[HidNeuron] = {0};double simHidError[HidNeuron] ={0};for(i=0; i<SampleNum; i++){//ForwardComputingfor(j=0; j<HidNeuron; j++){sum =0;for(k=0; k<Input+1; k++){if(k == Input)sum += (-1)*Bias1[j];elsesum += InputValue[i][k]*Weight1[k][j];}hidOutput[i][j] = LogSigmoid(sum);}for(j=0; j<Output; j++){sum =0;for(k=0; k<HidNeuron+1; k++){if(k == HidNeuron)sum += (-1)*Bias2[j];elsesum += hidOutput[i][k]*Weight2[k][j];}finOutput[i][j] = LogSigmoid(sum);Error[i][j] = OutputValue[i][j] - finOutput[i][j];}//BackwardComputingfor(j=0; j<Output; j++){detOutput[j] = finOutput[i][j]*(1-finOutput[i][j])*Error[i][j]; for(k=0; k<HidNeuron; k++){Weight2[k][j] += (lr*detOutput[j]*hidOutput[i][k]);}Bias2[j] += (lr*detOutput[j]*(-1));}for(j=0; j<HidNeuron; j++){simHidError[j] = 0;for(k=0; k<Output; k++){simHidError[j] += detOutput[k]*Weight2[j][k];}}for(j=0; j<HidNeuron; j++){detHid[j] = hidOutput[i][j]*(1-hidOutput[i][j])*simHidError[j]; for(k=0; k<Input; k++){Weight1[k][j] += (lr*detHid[j]*InputValue[i][k]);}Bias1[j] += (lr*detHid[j]*(-1));}}MSE=0;for(i =0; i<Output; i++){for(j=0; j<SampleNum; j++){MSE += (Error[j][i]*Error[j][i]);}}MSE = sqrt(MSE/SampleNum);}int main(){srand(unsigned(time(NULL)));static clock_t BeforeRunTime = clock(); InitWeight();InputValue[0][0] = 0;InputValue[0][1] = 0;OutputValue[0][0] = 0;InputValue[1][0] = 1;InputValue[1][1] = 1;OutputValue[1][0] = 0;InputValue[2][0] = 0;InputValue[2][1] = 1;OutputValue[2][0] = 1;InputValue[3][0] = 1;InputValue[3][1] = 0;OutputValue[3][0] = 1;size_t cEpoch = 0;while(MSE>goal){cEpoch++;Computing();printf("MSE: %.6f\n",MSE);}printf("Epochs %d\n",cEpoch);clock_t UsedTime = clock()-BeforeRunTime; printf("UsedTime %dms\n",UsedTime);getchar();return 0;}。