BP神经网络原理推导(学习笔记)

BP神经网络算法部分原理推导(梯度下降法)

20160715xujie

         以下图所示网络为例,来源于网上某位大神的BP网络C代码,根据C代码源码进行理解。


 

         上图显示的是一个只含有一个隐含层的网络,(对于一个刚接触ANN的人,好吓人的说,不要怕,看完后面你就不怕他了),隐层和输出层的神经元激活函数都是Sigmod函数:


         每一个神经元的输入加权求和之后作为Sigmod函数的输入:


         其中,Wji是上一层第i个神经元与当前层第j个神经元之间的系数(权值),这样就构成的整个网络的前向传播,那么后向传播的参数调整是如何实现的呢?

         已知,每一个训练样本的输入(X[n][0],X[n][1], X[n][2], X[n][3],)都对应着一个期望的输出(d[n][0], d[n][1], d[n][2]);那么,网络实际上的输出值(y[n][0],y[n][1],y[n][2])与期望值之间就会存在差异,这个差值就作为梯度下降法的损失函数E:(这个损失函数指的是针对单个样本):


         我先这样来理解一下神经网络,在神经网络中,从输入开始,每一层的输入都是上一层所有神经元的计算结果,也就是说总是先计算上一层,在计算下一层,数据经过每一层都会有相应的输出,回忆一下高等数学中的嵌套函数,不也是一样的吗?总是先计算内函数(上一层),在把内函数的计算结果(上一层的输出)当做自变量继续计算。

         好了,如果我们把网络比喻成了嵌套函数,那么,网络中的参数也就好理解了,比如说有一个嵌套函数:

P(x,y,z)=f(w0*g(w3*x,w4*y),w1*u(w5*y,w6*t(w7*x,w8*z)),w2*q(w9*y,w10*z));

         我们可以宏观的理解为P函数由三个自变量x,y,z和w0---w10这十一个系数构成的,如果我们已知这个函数的若干个点(xi,yi,zi)和对应的P函数值P(xi,yi,zi),要拟合这个函数的话,就是已知x,y,z去求解其中的系数嘛,这时每一个系数成了自变量,我的天,11个自变量的大函数哦,P(w0,w1,w2,w3,...,w10)。

         好了,回到神经网络,在BP神经网络中,我们想要求解  来修正Wji(看一下梯度下降法就知道为啥了),但是损失函数E的定义中并没有Wji,只有yj和dj(这里j代表输出层,所以E得定义中用的是下标j),又因为dj不是自变量,所以针对输出层的第n个神经元,目前我们只能得到

         

         

 

for(k=0;k<nk;k++)/*单样本循环*/

         {

                   for(i=0;i<ni;i++)//计算隐层

                   {

                            t=0;

                            for(h=0;h<nh;h++)

                                     t+=whi[h][i]*x[k][h];

                            xi[i]=t+thi[i]; //thi应该是偏置

                            yi[i]=sigmoid(xi[i]);//激活函数输出

                   }

                   for(j=0;j<nj;j++)//计算输出层

                   {

                            t=0;

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

                                     t+=wij[i][j]*yi[i];

                            xj[j]=t+thj[j];

                            yj[j]=sigmoid(xj[j]);

                   } 

 

                   for(j=0;j<nj;j++)/*输出层单样本点误差变化*/ //这里是变化率,而不是偏微分,所以少了一项yi,是为了方便下一步计算;其实在更新Wji时,是会补上这个yi的。

                            pxj[j]=yj[j]*(1-yj[j])*(yj[j]-d[k][j]);//

                   for(i=0;i<ni;i++)/*隐层单样本点误差变化率*/

                   {

                            t=0;

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

                                     t+=pxj[j]*wij[i][j];

                            pxi[i]=yi[i]*(1-yi[i])*t;

                   }

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

                   {

                            thj[j]=thj[j]-nr*pxj[j];//因为偏置没有输入,输出就是其本身,也就是说相当于输入为a1,输出为thj=Wij,输出为xj=Wij=thj;

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

                            wij[i][j]=wij[i][j]-nr*pxj[j]*yi[i];

                   }

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

                   {

                            thi[i]=thi[i]-nr*pxi[i];

                   for(h=0;h<nh;h++)

                            whi[h][i]=whi[h][i]-nr*pxi[i]*x[k][h];//这个x[k][h]相当于yh[h],因为已经到了输入层,所以就是x

                   }

 

                   t=0;

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

                            t+=(yj[j]-d[k][j])*(yj[j]-d[k][j])/2.0;

                   error[k]=t;

                   gerror+=error[k];/*全局误差 g(lobal)error*/

         }/*单样本循环结束*/

注:具体参考的代码来源想不起来了

猜你喜欢

转载自blog.csdn.net/xujie126/article/details/54691826