基于bp神经网络的学习组员:沈梦叶,叶枫,夏鼎1.BP神经网络模型关于程序中的变量•程序中的使用了两个结构体定义bp神经网络net和定义net中的每一层,本程序很简单的使用了3层网络模式,输入层是30个神经元,隐层是10个神经元,输出成只有一个神经元。•typedefstruct{/*ANET:*/•LAYER**Layer;/*-layersofthisnet*///这个网络有多少层•LAYER*InputLayer;/*-inputlayer*///输入层•LAYER*OutputLayer;/*-outputlayer*///输出层•REALAlpha;/*-momentumfactor*///动量因子•REALEta;/*-learningrate*///学习步长•REALGain;/*-gainofsigmoidfunction*///S函数的系数•REALError;/*-totalneterror*///整一个net的误差•}NET;•这个是关于层的结构体的定义•typedefstruct{•INTUnits;*///神经元个数•REAL*Output;*///神经元的输出数组•REAL*Error;*///每一个神经元的误差数组•REAL**Weight;//这是每一个神经元与上一层之间的圈子•REAL**WeightSave;//这个是在最后结束之时保存最后的权值•REAL**dWeight;//•}LAYER;•这就是这个程序中主要的两个数据类型,下面开始介绍BP神经网络。1.BP神经网络的初始化•1.初始化网络•1.1在这个过程中,主要是要对整个网络进行了内存分配和分别对每一层也进行了内存的分配。还有就是对每一层中的几个成员变量进行了内存分配,做好了这些以后也对层间的权值进行了内存分配。•1.2还有还对网络中的InputLayer(输入层),OutputLayer(输出层),Alpha(动量因子),Eta(学习步长),Gain(S函数的系数)•Net-Layer[l]-Units=Units[l];•Net-Layer[l]-Output=(REAL*)calloc(Units[l]+1,sizeof(REAL));•Net-Layer[l]-Error=(REAL*)calloc(Units[l]+1,sizeof(REAL));Net-Layer[l]-Weight=(REAL**)calloc(Units[l]+1,sizeof(REAL*));Net-Layer[l]-WeightSave=(REAL**)calloc(Units[l]+1,sizeof(REAL*));Net-Layer[l]-dWeight=(REAL**)calloc(Units[l]+1,sizeof(REAL*));Net-InputLayer=Net-Layer[0];Net-OutputLayer=Net-Layer[NUM_LAYERS-1];Net-Alpha=0.9;Net-Eta=0.25;Net-Gain=1;•2.初始化层间的权值•这些过程在函数RandomWeights中完成。这个函数通过三层循环为每一个神经元到下一个神经元之间的权值进行赋值,而这里放权值的变量是用一个二维数组来存储的,使用前一层的神经元与这一层神经元的位置来确定之间的权值,这个权值通过使用RandomEqualREAL函数是随机产生的在[-0.50.5]之间•voidRandomWeights(NET*Net)•{•INTl,i,j;••for(l=1;lNUM_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]=RandomEqualREAL(-0.5,0.5);•}•}•}•}2.设置样本值•1.设置样本值这一过程主要要对我们的现有的数据进行一定的处理。有一个sunspots数组是用来储存280年之间的太阳黑子发生的概率是多少,我们要使用bp算法来对这个接下来今年的太阳黑子进行预测,所以sunspots是我们的测试数据。对这个数组进行了稍微的修改为了能减小之间的不合理性。for(Year=0;YearNUM_YEARS;Year++){Sunspots_[Year]=//对Sunspots进行计算,然后改变他们的值Sunspots[Year]=((Sunspots[Year]-Min)/(Max-Min))*(HI-LO)+LO;//hi为0.9lo为0.1Mean+=Sunspots[Year]/NUM_YEARS;//所有的sunspots的值相加除以num_years,mean是平均值}•3.Training•接下来我们就应该去训练这个网络•3.1计算隐含层各神经元的输入和输出•这个过程的处理集中了PropagateLayer中,这个函数有3个参数,分别为net,upper(高层)•Lower(底层),这个函数主要是通过循环的调用这个函数,来求出高层神经元的输入和输•出。神经元的输入是通过于前一层的每一个神经元之间的权值乘以那个神经元的输出的•和,在函数中通过变量sum来求输入,然后我们使用sigmoidfunction来求出对应神经元的•输出,然后保存到每一层的输出数组中去,而这个函数的功能也就完成了这些功能。•voidPropagateLayer(NET*Net,LAYER*Lower,LAYER*Upper)•{•INTi,j;•REALSum;•for(i=1;i=Upper-Units;i++){•Sum=0;•for(j=0;j=Lower-Units;j++){•Sum+=Upper-Weight[i][j]*Lower-Output[j];//高层的权重乘以底层的输出•}•Upper-Output[i]=1/(1+exp(-Net-Gain*Sum));•}•}•可以看出程序和算法中所说的一样,在计算权值的过程。•从红色那个语句我们可以看出,它使用的是sigmoidfunction,这里的Net-Gain是一个系数,这个为1。•sigmoidfunction=1/(1+exp(-x));•3.2调整网络的权值•这个过程主要在两个函数中完成,这两个函数其实也就是整个BP网络的精髓所在,也是BP网络能学习的要点之处,这两个函数分别为ComputeOutputError和BackpropagateLayer,前者是用来求出上面输出层的输出值与我们的样本值(期望值)之间的差距,而后者则是通过ComputeOutputError求出的误差来调整一个变量,这个变量为每一个神经元的Error的值,这个值书上公式中的d,这个值与稍后的调成权值的有着直接的关系。•ComputeOutputError:•这个函数处理的是输出层上的东西,通过对每一神经元的循环,然后比较每一个神经元的输出值与期望值(Target),然后通过公式(d(m,i)=(y(m,i)-y(s,i))*(y(m,i)*(1-y(m,i))),m为输出层)来求出输出层的每一个神经元的误差,然后通过求和再求出net的总误差。•voidComputeOutputError(NET*Net,REAL*Target)//计算输出与实际之间的误差•{•INTi;•REALOut,Err;••Net-Error=0;•for(i=1;i=Net-OutputLayer-Units;i++){•Out=Net-OutputLayer-Output[i];•Err=Target[i-1]-Out;•Net-OutputLayer-Error[i]=Net-Gain*Out*(1-Out)*Err;•Net-Error+=0.5*sqr(Err);//这个就是标准的J函数,也就是整个net的误差•}•}•d(m,i)=(y(m,i)-y(s,i))*(y(m,i)*(1-y(m,i))),m为输出层•Out*(1-Out)对应于y(m,i)*(1-y(m,i))•Err=Target[i-1]-Out对应于y(m,i)-y(s,i)•所以可以看出,在计算d(m,i)是完全与算法对应的。•这里我们可以找到每一层的Error数组用来存储的是每一个神经元的d;•这里我们已经计算出输出层的d了,我们就可以根据上面提到的公式去退出前几层的d;•BackpropagateLayer:•这个函数也有三个参数,分别为net,lower(底层),upper(高层)。这个函数是通过输出层的误差也反向的去改变前面几层的与权值直接相关的d这个值。通过循环的使用这个函数来有限次的改变这个值,这个值的计算的公式为d(k,i)=y(k,i)*(1-y(k,i))*∑w(k+1,l,i)*d(k+1,l)来计算的,程序中通过使用循环来求的上层权值与error的乘积之和,然后在求出这层的d值。•voidBackpropagateLayer(NET*Net,LAYER*Upper,LAYER*Lower)•{•INTi,j;•REALOut,Err;••for(i=1;i=Lower-Units;i++){//i=1排除了输入层•Out=Lower-Output[i];•Err=0;•for(j=1;j=Upper-Units;j++){•Err+=Upper-Weight[j][i]*Upper-Error[j];•}•Lower-Error[i]=Net-Gain*Out*(1-Out)*Err;•}•}•公式为d(k,i)=y(k,i)*(1-y(k,i))*∑w(k+1,l,i)*d(k+1,l),这里的k不是输出层•循环中的Err+=Upper-Weight[j][i]*Upper-Error[j];就是对应于∑w(k+1,l,i)*d(k+1,l)•而Out*(1-Out)就是对应的y(k,i)*(1-y(k,i)),•通过上面的调整,我们基本已经完成了对d进行了调整•3.3修改权值•公式:∆W(k,i,j)=-ε*d(k,i)*y(k-1,j)这个过程主要在AdjustWeights完成,这个函数主要是根据上个BackpropagateLayer•求出来的error值来调整每一层每一个神经元之间的权值。这个调整和一开始的赋值差不多,也是通过3重循环来改变,每一个神经元之间的权值。使用的公式就是我们上面提到的求∆W(k,i,j)的公式。不过这个的ε是Eta,而d就是每一个神经元的error的值,y就是上一层的某个神经元的输出值。•代码如下•voidAdjustWeights(NET*Net)//调整权重•{•INTl,i,j;•REALOut,Err,dWeight;•for(l=1;lNUM_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];•dWeight=Net-Layer[l]-dWeight[i][j];•Net-Layer[l]-Weight[i][j]+=Net-Eta*Err*Out+Net-Alpha*dWeight;•Net-Layer[l]-dWeight[i][j]=Net-Eta*Err*Out;•}}}}•Out=Net-Layer[l-1]-Output[j];为上一层的输出值,也就是公式中的Y(k-1,j)•Net-Layer[l]-Weight[i