BP神经网络-- C语言实现

BP神经网络-- C语言实现

      在上一篇文章中,介绍了BP神经网络的基本模型、模型中的一些术语并对模型进行了数学上的分析,对它的原理有了初步的认识。那么如何用程序语言来具体的实现它,将是我们下一步需要讨论的问题。本文选取的是C语言来实现一个简单的单隐藏层的BP神经网络(默认大家了解了BP神经网络的基本概念,本文中涉及到些术语参见上一篇  基本模型 ),因此对于其他C类语言(C#、JAVA等)只需对本文中的代码稍作修改即可移植。

 

一些数据的定义

   首先,我们介绍些下文中描述的程序里面的一些重要数据的定义。

#define Data  820
#define In 2
#define Out 1
#define Neuron 45
#define TrainC 5500

      Data 用来表示已经知道的数据样本的数量,也就是训练样本的数量。In 表示对于每个样本有多少个输入变量; Out 表示对于每个样本有多少个输出变量。Neuron 表示神经元的数量,TrainC 来表示训练的次数。再来我们看对神经网络描述的数据定义,来看下面这张图里面的数据类型都是 double 型。

BP神经网络

 

图1

      d_in[Data][In] 存储 Data 个样本,每个样本的 In 个输入。d_out[Data][Out] 存储 Data 个样本,每个样本的 Out 个输出。我们用邻接表法来表示 图1 中的网络,w[Neuron][In]  表示某个输入对某个神经元的权重,v[Out][Neuron] 来表示某个神经元对某个输出的权重;与之对应的保存它们两个修正量的数组 dw[Neuron][In] 和 dv[Out][Neuron]。数组 o[Neuron] 记录的是神经元通过激活函数对外的输出,OutputData[Out]  存储BP神经网络的输出。

 

程序的执行过程

         在这里,先不考虑具体函数的执行细节,从大体上来介绍程序的执行过程。用伪代码来表示,具体的内容后面一步步介绍,如下:

复制代码
主函数main{

    读取样本数据 readData();
       初始化BP神经网络  initBPNework(){

            包括数据的归一,神经元的初始化 w[Neuron][In]、v[Out][Neuron]等;
        }
        BP神经网络训练 trainNetwork(){
            do{
                for(i 小于 样本容量 Data){
                    
            计算按照第 i 个样本输入,产生的BP神经网络的输出 computO(i);
                    累记误差精度;
                    反馈调节BP神经网络中的神经元,完成第 i 个样本的学习 backUpdate(i);
                }
            }while(达到训练次数 或者 符合误差精度);
        }

        存储训练好的神经元信息  writeNeuron();
        用一些数据来测试,训练出来的BP神经网络的结果;
        return 0;
}
复制代码

       以上是处理的流程,对于读取数据、保存数据之类的处理本文将略去这方面内容,突出主干部分。

 

初始化BP神经网络

      初始化主要是涉及两个方面的功能,一方面是对读取的训练样本数据进行归一化处理,归一化处理就是指的就是将数据转换成0~1之间。在BP神经网络理论里面,并没有对这个进行要求,不过实际实践过程中,归一化处理是不可或缺的。因为理论模型没考虑到,BP神经网络收敛的速率问题,一般来说神经元的输出对于0~1之间的数据非常敏感,归一化能够显著提高训练效率。可以用以下公式来对其进行归一化,其中 加个常数A 是为了防止出现 0 的情况(0不能为分母)。

       y=(x-MinValue+A)/(MaxValue-MinValue+A)

      另一方面,就是对神经元的权重进行初始化了,数据归一到了(0~1)之间,那么权重初始化为(-1~1)之间的数据,另外对修正量赋值为0。实现参考代码如下:

复制代码
void initBPNework(){

    int i,j;
   /*
    找到数据最小、最大值
   */
    for(i=0; i){
        Minin[i]=Maxin[i]=d_in[0][i];
        for(j=0; j)
        {
            Maxin[i]=Maxin[i]>d_in[j][i]?Maxin[i]:d_in[j][i];
            Minin[i]=Minin[i]Minin[i]:d_in[j][i];
        }
    }
    for(i=0; i){
        Minout[i]=Maxout[i]=d_out[0][i];
        for(j=0; j)
        {
            Maxout[i]=Maxout[i]>d_out[j][i]?Maxout[i]:d_out[j][i];
            Minout[i]=Minout[i]Minout[i]:d_out[j][i];
        }
    }
    /*
    归一化处理
    */
    for (i = 0; i < In; i++)
        for(j = 0; j < Data; j++)
            d_in[j][i]=(d_in[j][i]-Minin[i]+1)/(Maxin[i]-Minin[i]+1);
    for (i = 0; i < Out; i++)
        for(j = 0; j < Data; j++)
            d_out[j][i]=(d_out[j][i]-Minout[i]+1)/(Maxout[i]-Minout[i]+1);
    /*
    初始化神经元
  */
    for (i = 0; i < Neuron; ++i)    
        for (j = 0; j < In; ++j){    
            w[i][j]=(rand()*2.0/RAND_MAX-1)/2;
            dw[i][j]=0;
        }
    for (i = 0; i < Neuron; ++i)    
         for (j = 0; j < Out; ++j){
             v[j][i]=(rand()*2.0/RAND_MAX-1)/2;
              dv[j][i]=0;
         }
}
复制代码

 

BP神经网络训练

      这部分应当说是整个BP神经网络形成的引擎,驱动着样本训练过程的执行。由BP神经网络的基本模型知道,反馈学习机制包括两大部分,一是BP神经网络产生预测的结果,二是通过预测的结果和样本的准确结果进行比对,然后对神经元进行误差量的修正。因此,我们用两个函数来表示这样的两个过程,训练过程中还对平均误差 e 进行监控,如果达到了设定的精度即可完成训练。由于不一定能够到达预期设定的精度要求,我们添加一个训练次数的参数,如果次数达到也退出训练。实现参考代码如下:

 

复制代码
void  trainNetwork(){
    int i,c=0;
    do{
        e=0;
        for (i = 0; i < Data; ++i){
            computO(i);
            e+=fabs((OutputData[0]-d_out[i][0])/d_out[i][0]);
            backUpdate(i);
        }
        //printf("%d  %lf\n",c,e/Data);
        c++;
    }while(c0.01);
}
复制代码

 

        其中的函数,computO(i) (O是output缩写)计算BP神经网络预测第 i 个样本的输出也就是第一个过程。backUpdate(i) 是根据预测的第 i 个样本输出对神经网络的权重进行更新,e用来监控误差。

   BP神经网络程序实现的骨架已经介绍完了,训练过程中核心的两个函数computO(i) 和 backUpdate(i) 的实现如下。


BP神经网络输出

      函数 computO(i) 负责的是通过BP神经网络的机制对样本 i 的输入,预测其输出。回想BP神经网络的基本模型(详情见 基本模型)对应的公式(1)还有 激活函数对应的公式(2):

BP神经网络    

BP神经网络

      

      在前篇设计的BP神经网络中,输入层与隐藏层权重对应的数据结构是w[Neuron][In],隐藏层与输出层权重对应的数据结构是v[Out][Neuron],并且数组 o[Neuron] 记录的是神经元通过激活函数对外的输出,BP神经网络预测的样本结果保存在OutputData[Out]中。由此,就可以得到以下实现的参考代码:

复制代码
void computO(int var){

    int i,j;
    double sum,y;
        
        /*
            神经元输出
         */
    
        for (i = 0; i < Neuron; ++i){
        sum=0;
        for (j = 0; j < In; ++j)
            sum+=w[i][j]*d_in[var][j];
        o[i]=1/(1+exp(-1*sum));
    }

/*  隐藏层到输出层输出 */

    for (i = 0; i < Out; ++i){
        sum=0;
        for (j = 0; j < Neuron; ++j)
            sum+=v[i][j]*o[j];

        OutputData[i]=sum;
    }    
}
复制代码

 

BP神经网络的反馈学习

         函数 backUpdate(i) 负责的是将预测输出的结果与样本真实的结果进行比对,然后对神经网络中涉及到的权重进行修正,也这是BP神经网络实现的关键所在。如何求到对于 w[Neuron][In] 和 v[Out][Neuron] 进行修正的误差量便是关键所在!误差修正量的求法在基本模型一文中数学分析部分有解答,具体问题具体分析,落实到我们设计的这个BP神经网络上来说,需要得到的是对w[Neuron][In] 和 v[Out][Neuron] 两个数据进行修正误差,误差量用数据结构 dw[Neuron][In]  和  dv[Out][Neuron]  来进行存储。那么来分析下这两个修正误差量是什么样的?推导的思路与基本模型中推导误差量的一致,这里仅列出对具体对于我们设计的BP神经网络中的数学推导过程:

   

BP神经网络

      如果你不想知道推导过程,那么只需要看上面中的两个 所以(有三个点的地方) 的内容,就可以知道所需要的误差量是什么样的了;如果想要想弄明白的话,或许需要自己在稿子上画画看推导推导。到这里完成了数学推导,实现的代码就很容易写了。在具体实现对误差修改中,我们再加上学习率,并且对先前学习到的修正误差量进行继承,直白的说就是都乘上一个0到1之间的数,具体的见如下实现参考代码:

#define A  0.2
#define B  0.4
#define a  0.2
#define b  0.3
复制代码
void backUpdate(int var)
{
    int i,j;
    double t;
    for (i = 0; i < Neuron; ++i)
    {
        t=0;
        for (j = 0; j < Out; ++j){
            t+=(OutputData[j]-d_out[var][j])*v[j][i];

            dv[j][i]=A*dv[j][i]+B*(OutputData[j]-d_out[var][j])*o[i];
            v[j][i]-=dv[j][i];
        }

        for (j = 0; j < In; ++j){
            dw[i][j]=a*dw[i][j]+b*t*o[i]*(1-o[i])*d_in[var][j];
            w[i][j]-=dw[i][j];
        }
    }
}
复制代码

  

       好了,至此BP神经网络的C语言实现就全部完成了。最后,我们可以测试下BP神经网络的运行。我这里是这样给出数据的,两个输入a、b(10以内的数),一个输出 c,c=a+b。换句话说就是教BP神经网络加法运算。在 45个神经元,820个训练样例,样本平均误差小于0.01时完成训练(学习率等见参考代码)的条件下,最后预测 (6,8),(2.1,7),(4.3,8)实际输出结果如下:

      最后附上参考实现代码,以及实验训练时的数据、和神经元信息。(本示例 仅为BP神经网络实现的 简单DEMO,若实际使用还需多加考虑!!!)

  参考代码下载


你可能感兴趣的:(matlab,C,Machine,Learning,control,algorithm)