(分享)BP神经网络C程序

 

在该题的程序设计中采用了文件相关的操作,记录了相关学习和测试信息数据。权值用伪随机数函数随机产生(范围是(0,0.5))

采用结构体及链表来实现神经网络的结构

分为实例结构体、层结构体和网络结构体

数据结构的设计参照了《人工神经网络原理》(马锐编著,北京:机械工业出版社,2010,7)一书

学习算法的优化也参照该书

采用学习效率自适应调整算法优化源程序的学习算法,以减少学习次数

由于能力和知识有限,该程序存在较大漏洞误差,在调整学习率时,不好掌握调节系数

初始权值的限定范围适中,则程序的学习次数将明显减少

在随机赋初始权值(0,0.5)时,学习次数可调节至135,但对测试数据的判别效果不理想,没有采用

 

 

 

#include<stdio.h>

#include<stdlib.h>

#include<math.h>

#include<malloc.h>

 

#define TRUE         1

#define FALSE        0

 

#define NUM_LAYERS   4

#define NUM          20        //训练实例个数

#define N            2         //输入层单元数

#define M            2         //输出层单元数

 

int Units[NUM_LAYERS] = {N,3,3,M};   //每层单元数

       FILE *fp,*fb;

 

typedef struct                //训练实例

{

       float x[N];

       float y[M];

}TRAIN;

 

typedef struct                //网络层结构

{

       int Units;               //该层中单元的个数

       float *Output;           //第 i 个单元的输出

       float *Error;            //第 i 个单元的校正误差

       float **Weight;          //第 i 个单元的连接权值

}LAYER;

 

typedef struct                        //网络

{

       LAYER **Layer;                     //隐层定义

       LAYER *Inputlayer;                 //输入层

       LAYER *Outputlayer;                //输出层

       float Error;                        //允许误差

       float Eta;                          //学习率

}NET;

 

//初始化伪随机数发生器

void InitializeRandoms()

{

       srand(4711);

       return;

}

 

//产生随机实数并规范化

float RandomReal()                      //产生(-0.5,0.5)之间的随机数

{

       return (float)((rand()%100)/200.0);

}

 

//初始化训练数据

void InitializeTrainingData(TRAIN *training)

{

       int i,j;

       char filename[20];

       printf("\n请输入训练实例的数据文件名: \n");

       gets(filename);

       fb = fopen(filename,"r");

       fprintf(fp,"\n\n--Saving initialization training datas ...\n");

       for(i=0;i<NUM;i++)

       {

              for(j=0;j<N;j++)

              {

                     fscanf(fb,"%f",&(training+i)->x[j]);

                     fprintf(fp,"%10.4f",(training+i)->x[j]);

              }

              for(j=0;j<M;j++)

              {

                     fscanf(fb,"%f",&(training+i)->y[j]);

                     fprintf(fp,"%10.4f",(training+i)->y[j]);

              }

              fprintf(fp,"\n");

       }

       fclose(fb);

       return;

}

 

//应用程序初始化

void InitializeApplication(NET *Net)

{

       Net->Eta = (float)0.3;

       Net->Error = (float)0.0001;

       fp = fopen("BPResultData.txt","w+");

       return;

}

 

//应用程序关闭时终止打开的文件

void FinalizeApplication(NET *Net)

{

       fclose(fp);

       return;

}

 

//分配内存,建立网络

void GenerateNetwork(NET *Net)

{

       int l,i;

       Net->Layer = (LAYER **)calloc(NUM_LAYERS,sizeof(LAYER *));

       for(l=0;l<NUM_LAYERS;l++)

       {

              Net->Layer[l] = (LAYER *)malloc(sizeof(LAYER));

              Net->Layer[l]->Units      = Units[l];

              Net->Layer[l]->Output     = (float *) calloc(Units[l]+1,sizeof(float));

              Net->Layer[l]->Error      = (float *) calloc(Units[l]+1,sizeof(float));

              Net->Layer[l]->Weight     = (float **)calloc(Units[l]+1,sizeof(float *));

              Net->Layer[l]->Output[0]  = 1;

              if(l != 0)

                     for(i=1;i <= Units[l];i++)                          //下标从"1"开始

                            Net->Layer[l]->Weight[i] = (float *)calloc(Units[l-1]+1,sizeof(float));

       }

       Net->Inputlayer  = Net->Layer[0];

       Net->Outputlayer = Net->Layer[NUM_LAYERS - 1];

       return;

}

 

//产生随机实数作为初始连接权值

void RandomWeights(NET *Net)

{

       int l,i,j;

       for(l=1;l<NUM_LAYERS;l++)

              for(i=1;i <= Net->Layer[l]->Units;i++)

                     for(j=0;j <= Net->Layer[l-1]->Units;j++)

                            Net->Layer[l]->Weight[i][j] = RandomReal();

       return;

}

 

//设置输入层的输出值

void SetInput(NET *Net,float *Input)

{

       int i;

       for(i=1;i <= Net->Inputlayer->Units;i++)

              Net->Inputlayer->Output[i] = Input[i-1];                          //输入层采用 u(x) = x

       return;

}

 

//设置输出层的输出值

void GetOutput(NET *Net,float *Output)

{

       int i;

       for(i=1;i <= Net->Outputlayer->Units;i++)

              Output[i-1] = (float)(1/(1 + exp(-Net->Outputlayer->Output[i])));         //输出层采用 f(x)=1/(1+e^(-x))

       return;

}

 

//层间顺传播

void PropagateLayer(NET *Net,LAYER *Lower,LAYER *Upper)

{

       int i,j;

       float sum;

       for(i=1;i <= Upper->Units;i++)

       {

              sum = 0;

              for(j=1;j <= Lower->Units;j++)

                     sum += (Upper->Weight[i][j] * Lower->Output[j]);

              Upper->Output[i] = (float)(1/(1 + exp(-sum)));

       }

       return;

}

 

//整个网络所有层间的顺传播

void PropagateNet(NET *Net)

{

       int l;

       for(l=0;l < NUM_LAYERS-1;l++)

              PropagateLayer(Net,Net->Layer[l],Net->Layer[l+1]);

       return;

}

 

//计算输出层误差

void ComputeOutputError(NET *Net,float *target)

{

       int i;

       float Out,Err;

       for(i=1;i <= Net->Outputlayer->Units;i++)

       {

              Out = Net->Outputlayer->Output[i];

              Err = target[i-1] - Out;

              Net->Outputlayer->Error[i] = Out*(1-Out)*Err;

       }

       return;

}

 

//层间逆传播

void BackpropagateLayer(NET *Net,LAYER *Upper,LAYER *Lower)

{

       int i,j;

       float Out,Err;

       for(i=1;i <= Lower->Units;i++)

       {

              Out = Lower->Output[i];

              Err = 0;

              for(j=1;j <= Upper->Units;j++)

                     Err += (Upper->Weight[j][i] * Upper->Error[j]);

              Lower->Error[i] = Out*(1-Out)*Err;

       }

       return;

}

 

//整个网络所有层间的逆传播

void BackpropagateNet(NET *Net)

{

       int l;

       for(l=NUM_LAYERS-1;l>1;l--)

              BackpropagateLayer(Net,Net->Layer[l],Net->Layer[l-1]);

       return;

}

 

//权值调整

void AdjustWeights(NET *Net)

{

       int l,i,j;

       float Out,Err;

       for(l=1;l<NUM_LAYERS;l++)

              for(i=1;i <= Net->Layer[l]->Units;i++)

                     for(j=0;j <= Net->Layer[l-1]->Units;j++)

                     {

                            Out = Net->Layer[l-1]->Output[j];

                            Err = Net->Layer[l]->Error[i];

                            Net->Layer[l]->Weight[i][j] += (Net->Eta*Err*Out);

                     }

       return;

}

 

//网络处理过程

void SimulateNet(NET *Net,float *Input,float *Output,float *target,int TrainOrNot)

{

       SetInput(Net,Input);                             //输入数据

       PropagateNet(Net);                               //模式顺传播

       GetOutput(Net,Output);                           //形成输出

       ComputeOutputError(Net,target);                  //计算输出误差

       if(TrainOrNot)

       {

              BackpropagateNet(Net);                       //误差逆传播

              AdjustWeights(Net);                          //调整权值

       }

       return;

}

 

//训练过程

void TrainNet(NET *Net,TRAIN *training)

{

       int l,i,j,k;

       int count=0,flag=0;

       float Output[M],outputfront[M],ERR,err,sum;

       do

       {

              flag = 0;

              sum = 0;

              ERR = 0;

              if(count >= 1)

                     for(j=0;j<M;j++)

                            outputfront[j]=Output[j];

              SimulateNet(Net,(training+(count%NUM))->x,Output,(training+(count%NUM))->y,TRUE);

              if(count >= 1)

              {

                     k = count%NUM;

                     for(i=1;i <= Net->Outputlayer->Units;i++)

                     {

                            sum += Net->Outputlayer->Error[i];

                            err = (training+k-1)->y[i-1] - outputfront[i-1];

                            ERR += (outputfront[i-1] * (1 - outputfront[i-1]) * err);

                     }

                     if(sum <= ERR)

                            Net->Eta = (float)(0.9999 * Net->Eta);

                     else

                            Net->Eta = (float)(1.0015 * Net->Eta);

 

              }

              if(count >= NUM)

              {

                     for(k=1;k <= M;k++)

                            if(Net->Outputlayer->Error[k] > Net->Error)

                            {   flag=1;     break;   }

                     if(k>M)

                            flag=0;

              }

              count++;

       }while(flag || count <= NUM);

       fprintf(fp,"\n\n\n");

       fprintf(fp,"--training results ... \n");

       fprintf(fp,"training times:   %d\n",count);

       fprintf(fp,"\n*****the final weights*****\n");

       for(l=1;l<NUM_LAYERS;l++)

       {

              for(i=1;i <= Net->Layer[l]->Units;i++)

              {

                     for(j=1;j <= Net->Layer[l-1]->Units;j++)

                            fprintf(fp,"%15.6f",Net->Layer[l]->Weight[i][j]);

                     fprintf(fp,"\n");

              }

              fprintf(fp,"\n\n");

       }

}

 

//评估过程

void EvaluateNet(NET *Net)

{

       int i;

       printf("\n\n(");

       fprintf(fp,"\n\n(");

       for(i=1;i <= Net->Inputlayer->Units;i++)

       {

              printf(" %.4f",Net->Inputlayer->Output[i]);

              fprintf(fp,"%10.4f",Net->Inputlayer->Output[i]);

       }

       printf(")\t");

       fprintf(fp,")\t");

       for(i=1;i <= Net->Outputlayer->Units;i++)

       {

              if(fabs(Net->Outputlayer->Output[i] - 1.0) <= 0.0499)

              {

                     printf("肯定是第 %d 类, ",i);

                     fprintf(fp,"肯定是第 %d 类, ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.9) <= 0.0499)

              {

                     printf("几乎是第 %d 类,  ",i);

                     fprintf(fp,"几乎是第 %d 类, ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.8) <= 0.0499)

              {

                     printf("极是第 %d 类, ",i);

                     fprintf(fp,"极是第 %d 类, ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.7) <= 0.0499)

              {

                     printf("很是第 %d 类, ",i);

                     fprintf(fp,"很是第 %d 类, ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.6) <= 0.0499)

              {

                     printf("相当是第 %d 类,  ",i);

                     fprintf(fp,"相当是第 %d 类,  ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.5) <= 0.0499)

              {

                     printf("差不多是第 %d 类, ",i);

                     fprintf(fp,"差不多是第 %d 类, ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.4) <= 0.0499)

              {

                     printf("比较像是第 %d 类, ",i);

                     fprintf(fp,"比较像是第 %d 类, ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.3) <= 0.0499)

              {

                     printf("有些像是第 %d 类, ",i);

                     fprintf(fp,"有些像是第 %d 类, ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.2) <= 0.0499)

              {

                     printf("有点像是第 %d 类, ",i);

                     fprintf(fp,"有点像是第 %d 类, ",i);

              }

              if(fabs(Net->Outputlayer->Output[i] - 0.1) <= 0.0499)

              {

                     printf("稍稍像是第 %d 类, ",i);

                     fprintf(fp,"稍稍像是第 %d 类, ",i);

              }

              if(Net->Outputlayer->Output[i] <= 0.0499)

              {

                     printf("肯定不是第 %d 类, ",i);

                     fprintf(fp,"肯定不是第 %d 类, ",i);

              }

       }

       printf("\n\n");

       fprintf(fp,"\n\n\n");

       return;

}

 

//测试过程

void TestNet(NET *Net)

{

       TRAIN Testdata;

       float Output[M];

       int i,j,flag=0;

       char select;

       fprintf(fp,"\n\n--Saving test datas ...\n");

       do

       {

              printf("\n请输入测试数据(x1 x2 ... y1 y2 ...): \n");

              for(j=0;j<N;j++)

              {

                     scanf("%f",&Testdata.x[j]);

                     fprintf(fp,"%10.4f",Testdata.x[j]);

              }

              for(j=0;j<M;j++)

              {

                     scanf("%f",&Testdata.y[j]);

                     fprintf(fp,"%10.4f",Testdata.y[j]);

              }

              fprintf(fp,"\n");

              SimulateNet(Net,Testdata.x,Output,Testdata.y,FALSE);

              fprintf(fp,"\n--NET Output and Error of the Test Data ....\n");

              for(i=1;i <= Net->Outputlayer->Units;i++)

                     fprintf(fp,"%10.6f  %10.6f\n",Net->Outputlayer->Output[i],Net->Outputlayer->Error[i]);

              EvaluateNet(Net);

              printf("\n继续测试?(y/n):\n");

              getchar();

              scanf("%c",&select);

              printf("\n");

              if((select == 'y')||(select == 'Y'))

                     flag = 1;

              else

                     flag=0;

       }while(flag);

       return;

}

 

//主函数

void main()

{

       TRAIN TrainingData[NUM];

       NET Net;

       InitializeRandoms();                                  //初始化伪随机数发生器

       GenerateNetwork(&Net);                                //建立网络

       RandomWeights(&Net);                                  //形成初始权值

       InitializeApplication(&Net);                          //应用程序初始化,准备运行

       InitializeTrainingData(TrainingData);                 //记录训练数据

       TrainNet(&Net,TrainingData);                          //开始训练

       TestNet(&Net);

       FinalizeApplication(&Net);                            //程序关闭,完成善后工作

       return;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值