对BP神经网络的粗浅理解

我都不记得是出于何种原因诱发我这几天看神经网络(当然是人工神经网络。。)去了。。。不知道是突发奇想,或是上网看到相关内容,或是书本上的一些东西给我的启发。。。完全不记得了。只记得貌似是从前天看的。

对神经网络的基础定义啥的就不说了,本文的重点不是阐述关于神经网络的相关定义,神经元啊,激活函数(activation function)啊等等,而是对我这几天所看的BP网络的工作方式或者说BP网络学习的机制的一些理解。

BP神经网络分为3层,分别为输入层,隐藏层和输出层。如下图:

BP神经网络模型

其中输入层提供输入数据,实际上输入层中的神经元不工作,或者说这些神经元的输出就是输入数据。隐藏层接收输入层的输出,然后传递到输出层,输出层的神经元处理后得到输出数据。其中隐藏层也可以是多层神经元,一般来说都只用一层。

BP网络是这样学习的。训练数据依次提供给输入层,在输出层得到输出结果之后,与正确结果进行比对,若误差在可接受范围内,就可以终止学习。否则,根据该误差对网络的权值w进行更新,以使误差变小。那么关键就是该怎么更新权值的问题了。

先定义几个量。为了方便,规定隐藏层只有1层。设有m个输入和n个输出,其中输入为(d_0,d_1,\dots ,d_m),正确输出为(t_0,t_1,\dots ,d_n)。对神经元j,设其输入为x_j,其输出为y_j,神经元的激活函数为f,神经元i到神经元j的边的权值为w_{ji}。定义误差e为

e=\frac{1}{2}\sum_{j\text{ in output layer}}(t_j-y_j)^2.

先不问为什么,算几个量。首先计算e对w_{kj}的偏导数,其中k是输出层神经元,j是隐藏层神经元。如图:a1

首先有

x_k=\sum_{j\text{ in hide layer}}w_{kj}y_j

y_k=f(x_k),因此

\begin{array}{l}\frac{\partial e}{\partial w_{kj}} & =\frac{\partial e}{\partial y_k}\frac{\partial y_k}{\partial w_{kj}} \\ & =\frac{\partial e}{\partial y_k}\frac{\partial y_k}{\partial x_k}\frac{\partial x_k}{\partial w_{kj}} \\ & =-(t_k-y_k)f'(x_k)y_j\end{array}

\delta_{o_k}=(t_k-y_k)f'(x_k),因此有

\frac{\partial e}{\partial w_{kj}}=-\delta_{o_k}y_j.

始终需要注意上面的k是指输出层的神经元,j是隐藏层神经元,并且\delta_{o_k}的值只与输出层神经元k有关

继续计算e对w_{ji}的偏导数,其中j是隐藏层神经元,i是输入层神经元。如图:a2同样

\begin{array}{l}\frac{\partial e}{\partial w_{ji}} & =\sum_{k\text{ in output layer}}\frac{\partial e}{\partial x_k}\frac{\partial x_k}{\partial w_{ji}} \\ & =\sum_{k\text{ in output layer}}\frac{\partial e}{\partial x_k}\frac{\partial x_k}{\partial y_j}\frac{\partial y_j}{\partial x_j}\frac{\partial x_j}{\partial w_{ji}} \\ & =\sum_{k\text{ in output layer}}-\delta_{o_k}w_{k_j}f'(x_j)d_i \\ & =-\left[f'(x_j)\sum_{k\text{ in output layer}}\delta_{o_k}w_{k_j}\<br />
ight]d_i.\end{array}

同样的记

\delta_{h_j}=f'(x_j)\sum_{k\text{ in output layer}}\delta_{o_k}w_{k_j}

则有

\frac{\partial e}{\partial w_{ji}}=-\delta_{h_j}d_i

如果隐藏层不止一层,对应的e对相关权值的偏导计算类似。

好了,求了偏导有啥用呢?以w_{kj}的更新为例,其中k是输出层神经元,j是隐藏层神经元。想一下导数的意义,若导数为正,则自变量增函数值也增。为负则相反。那么对e来说,目的是要使e的值变小,如果对某个w_{kj}\frac{\partial e}{\partial w_{kj}}为正,那么对w_{kj}的修改就应该减小,反之则应该增大。即可令

\Delta w_{kj}=-\beta\frac{\partial e}{\partial w_{kj}}=\beta\delta_{o_k}y_j.

其中\beta叫做学习率(learning rate),是一个0到1之间的实数。对w_{kj}的更新则为

w_{kj}=w_{kj}+\Delta w_{kj}=w_{kj}+\beta\delta_{o_k}y_j.

这样经过若干次迭代之后,e的值就能渐渐减小到局部最优。对w_{ji}的更新也是如此。

从另一个方面来说,梯度向量就是偏导数,而梯度的指向就是指着增长对快的方向,那么我们只要沿着梯度相反方向迭代,就能逐渐趋于局部最小值。相反,如果沿着梯度方向迭代,就能趋于局部最大值。(当函数为1元函数时,梯度退化为导数,是一个标量或者说是1维的向量)。

从每层的\delta值来看,前一层的\delta值需要后一层的\delta值。如要求隐藏层的\delta\delta_h,就需要输出层的\delta\delta_o,这也是BP神经网络的BP两个字的来由:Backpropagation。即,误差向后传播

我已经写了一个C++的例程实现了BPNN,模拟了两个数相加,感觉还好,下次好好整理下看再写一篇粗略实现。

参考资料:
Backpropagation - Wikipedia, the free encyclopedia
Delta rule - Wikipedia, the free encyclopedia
Gradient descent - Wikipedia, the free encyclopedia



8 thoughts on “对BP神经网络的粗浅理解

    • 碉堡。。!我感觉现在虽然会写个BP,但是字符识别那东西还得想下输入的问题。。估计得找些特征点啥的。。。而且。。。感觉数据太大了 = =

        • 额。。这个。。木有。。php没学到家,还不会添加这功能。。好像有个多说的评论插件,但感觉太那啥了。。就没用

        • 用了下那个wp thread comment插件。。我的有问题不知道怎么搞。。。先是提示错误说没有什么id,然后google下解决了后,点那个回复之后把评论部分都变没了。。而且搞的同时有个reply和回复在上面,很不协调。。没用了
          不知道你的是什么插件?还是自己写的?我看了你的回复中还可以加html标签来着

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*