美文网首页
BP神经网络算法的深度解析和工程实例搭建

BP神经网络算法的深度解析和工程实例搭建

作者: dobolong | 来源:发表于2018-09-01 15:05 被阅读0次

    首先声明,这篇文章不是神经网络的扫盲文,如果只想知道神经网络的概念那笔者还是推荐找一些深入浅出的文章来看。但是如果需要自己实际搭建和使用一个神经网络,同时具备一定的数学功底的话,那这篇文章就是为了深入的剖析神经网络算法的工作过程和模型而写的。这里笔者把整个神经网络的工作过程由特殊情况推广到一般情况,让读者了解整个神经网络的工作过程,并且给出实际搭建一个神经网络的方法。希望有意愿了解的读者能够拿起笔跟着文章一起把公式写一遍。

    神经网络必备的基础的数学知识:

    梯度:
    相较于单变量的函数,梯度和导数的含义是一样的,但是对于一个多变量的向量来说,其梯度的含义就是在某点处变化最快的向量场,例如对于一个三元函数t=f(x,y,z)来说,其在空间某点的梯度就是:

    梯度

    链式法则:
    链式法则常用于复合函数求导问题


    链式法则

    神经网络算法:

    神经网路算法灵感来源于生物细胞中的神经元结构,神经元具有树状突触用来和其他神经元进行交流,在数学上突触就可以视为信号的来源和对象。不同神经元之间的树状突触大小可能不同,不同大小的突触对于信号的响应程度也不同,在数学上对于信号的响应程度就可以用权值来表示。对于相互交流频繁的神经元其之间的突触连接更加紧密,对应的也就是其信号的权值较高。神经元对得到的信号进行总结,在数学上就是对所有输入信号乘以各自的权值后求和。神经元在对总结好信号进行处理,判断是否需要输出生物电信号,在数学上就是将求和的信号作为代入到某个函数中,得到函数结果,根据结果决定输出值。一个神经元可以有多个输出对象,但是只有一个输出结果,也就是相同的输出结果可以输出给多个输出对象。

    image

    如图所示归纳出一个神经元的数学模型,一个神经元有多个输入x1、x2......xn,每个输入对应了各自的权值k1、k2......kn,则其输入的加权和为

    s_i=x_1*k_1+x_2*k_2+......x_n*k_n

    假设其输入的偏置为b,则实际的加权和为

    s_i=x_1*k_1+x_2*k_2+......x_n*k_n+b

    现在,输入变量的表达式得到了,那输入和输出的关系,即函数f()怎么得到呢?一般来说,考虑到输出的结果在0到1的范围内,而输入的结果的取值范围则为实数域,因此需要一个函数其定义域为实数域,值域为0到1,常见的函数有阶跃函数、sigmoid函数等,将s_i带入函数中,得到的结果就是神经元的输出h。这里输出的值只有一个,但是输出的对象可以有多个。

    在了解单个神经元的数学模型后,将多个神经元组合起来形成网络,就是神经网络。神经网络的组成主要有三部分。对于没有其他神经元的输入,只有输出的神经元,往往在第一层作为感受器而存在,这一层叫做输入层。对于没有其他神经元的输出,只有别的神经元对其输入的神经元往往在最后一层作为执行器而存在,这一层叫做输出层。而中间既有神经元的输入又有神经元的输出的均为隐层。一般来说输入层和输出层只有一个,但是隐层可以有多个。

    image

    为了方便数学模型的表示,我们对于各层之间的变量进行一个命名。对于某一层的某一个神经元,与之相关的参数有:来自上一层的输入和权值和对下一层的输出和权值,以及其输入的加权和,还有该神经元的处理函数。

    神经元命名规则

    如图所示,对于第M层的第j个神经元,其输入的加权和为s_j^M,表示第M层的第j个神经元的加权和s;其输出为x_j^M,表示第M层的第j个神经元的输出x;而第L层的第i个神经元和第M层的第j个神经元之间的权值为k_{i-j}^M;而第M层的处理函数可以写为f_M()。由此一个神经元有关的变量就全部都能表示了。

    根据上面所讲述的神经元的知识,可以得到,对于第M层的第j个神经元,有以下关系方程

    1.来自上一层的输入乘以对应的权值得到该神经元的加权和
    s_j^M = x_1^L * k_{1-j}^L +...... x_i^L * k_{i-j}^L +...... x_l^L * k_{l-j}^L
    用累加来表示,可以写成
    s_j^M = \sum_{i=1}^l (x_i^L * k_{i-j}^L )

    2.对加权和进行函数处理得到该神经元的输出
    x_j^M=f_M(s_j^M)

    由此可以类推出任意层的任意一个神经元的关系方程。

    在信号的正向传递中,所有的信号经过一个个的神经元,在上述关系方程的计算下层层累积最终对输出造成影响。

    这里,对于神经网络来说,在一次神经网络计算过程中,其各个神经元之间的权值的变化将会导致输出的变化,为了得到一个较为理想的输出,就要改变其各个神经元之间的权值,从而最终得到一个合适的输出,使得该输出和理想输出的差值最小。这就变成了一个数学上求最值的问题,最值的对象是偏差值,也就是求偏差值最小值。其自变量就是神经网络中的各个神经元之间的权值。对于这种多变量的函数,求最值的问题就关系到了文章开头所说的梯度。也就是求出在当前权值组合下偏差对于各权值的梯度,然后按照与梯度相反的方向,稍微修改权值,;然后再计算该权值下的梯度,然后按照与梯度相反的方向修改权值,重复上述步骤一直到输出偏差到达最小值。这就是为什么神经网络算法又是一种学习算法的原因,因为它会自己不断的趋向最优的结果。

    但是这里存在一个问题,就是有可能最终得到的结果只是一个局部最优解,而不是全局最优解。对于这种情况可以通过设定初始权值,惯性等来避免,这里先不进行阐述。

    现在对上述求梯度这一过程给出数学上的表达。这里也是神经网络算法反向传递的精髓所在。

    首先以一个3-4-2的神经网络为例,然后类比成a-b-c的神经网络,然后再类比成更多层的神经网络。

    3-4-2神经网络正向传递

    首先输入通过正向传递到达输出,这里我们先一第二层的第一个和第三层的第一个为例:

    第2层第1个神经元:

    s_1^2 = x_1^1 * k_{1-1}^1 + x_2^1 * k_{2-1}^1 + x_3^1 * k_{3-1}^1

    x_1^2=f(s_1^2 )

    类比出第2层第j个神经元:

    s_j^2 = x_1^1 * k_{1-j}^1 + ...... x_i^1 * k_{i-j}^1 + ...... x_a^1 * k_{a-j}^1 =\sum_{i=1}^a x_i^1 * k_{i-j}^1

    x_j^2=f(s_j^2 )

    第3层第1个神经元:

    s_1^3 = x_1^2 * k_{1-1}^2 + x_2^2 * k_{2-1}^2 + x_3^2 * k_{3-1}^2 + x_4^2 * k_{4-1}^2

    x_1^3=f(s_1^3 )

    类比出第3层第k个神经元:

    s_k^3 = \sum_{j=1}^b x_j^2 * k_{j-k}^2

    x_k^3=f(s_k^3 )

    对于输出,这里的神经网络计算得到的输出是x_1^3x_2^3,当理想的输出已知,且为y1和y2时,我们能计算得到输出的偏差(这里的系数1/2是为了后续求导的时候抵消因求平方的导数带来的系数2)

    E= \frac{1}{2} (x_1^3-y_1)^2 + \frac{1}{2} (x_2^3-y_2)^2

    对于a-b-c的神经网络,类比上式可以得到:

    E= \frac{1}{2} \sum_{i=1}^c (x_k^3-y_k)^2

    到此,一个神经网络的正向传递已经结束,得到了神经网络的输出和偏差,下面就是反向调节,使得系统偏差最小。在简单的函数问题中,求一个函数最小值的方法通常是通过求导,得到函数的极值点并判断。对于多变量的函数,其最小值的方法不能简单的通过求导数得到,但是可以通过求梯度,并沿着梯度变化趋势的反方向修改当前值,然后再次计算,直到到达最小值。

    求梯度通俗来说,就是对各个变量求偏导数得到的向量。对于误差E来说,其自变量是神经网络中的所有神经元之间的权值k,所以下面我们以3-4-2的神经网络中的k_{1-1}^1k_{1-1}^2 为例,求其梯度,同时类比推导出对于一个a-b-c的神经网络,其第一层i神经元到第二层j神经元,以及第二层j神经元到第三层k神经元的权值的梯度。

    首先是k_{1-1}^2,对其进行偏导,可以得到\frac{\partial E}{\partial k_{1-1}^2},根据链式法则,我们先分析一下各函数的复合函数。

    首先:

    E= \frac{1}{2} (x_1^3-y_1)^2 + \frac{1}{2} (x_2^3-y_2)^2 =g_1(x_1^3,x_2^3)

    可以看出E是关于x_1^3x_2^3的函数,其中x_1^3=f(s_1^3)x_2^3=f(s_2^3),又有:

    s_1^3 = x_1^2 * k_{1-1}^2 + x_2^2 * k_{2-1}^2 + x_3^2 * k_{3-1}^2 + x_4^2 * k_{4-1}^2=g_2(x_1^2, x_2^2, x_3^2, x_4^2, k_{1-1}^2, k_{2-1}^2, k_{3-1}^2, k_{4-1}^2)

    s_2^3 = x_1^2 * k_{1-2}^2 + x_2^2 * k_{2-2}^2 + x_3^2 * k_{3-2}^2 + x_4^2 * k_{4-2}^2=g_2(x_1^2, x_2^2, x_3^2, x_4^2, k_{1-2}^2, k_{2-2}^2, k_{3-2}^2, k_{4-2}^2)

    可以看出s_1^3是关于x_1^2, x_2^2, x_3^2, x_4^2, k_{1-1}^2, k_{2-1}^2, k_{3-1}^2, k_{4-1}^2的函数,s_2^3是关于x_1^2, x_2^2, x_3^2, x_4^2, k_{1-2}^2, k_{2-2}^2, k_{3-2}^2, k_{4-2}^2的函数。其中x_1^2=f(s_1^2)x_2^2=f(s_2^2)x_3^2=f(s_3^2)x_4^2=f(s_4^2),又有:

    s_1^2 = x_1^1 * k_{1-1}^1 + x_2^1 * k_{2-1}^1 + x_3^1 * k_{3-1}^1=g_3(k_{1-1}^1,k_{2-1}^1,k_{3-1}^1)

    其中x_1^1, x_2^1,x_3^1是系统给定的输入,因此在进行偏差计算时不认为是一个变量,这里注意一下。同理可以得到s_2^2,s_3^2,s_4^2的函数关系式:

    s_2^2=g_3(k_{1-2}^1,k_{2-2}^1,k_{3-2}^1)

    s_3^2=g_3(k_{1-3}^1,k_{2-3}^1,k_{3-3}^1)

    s_4^2=g_3(k_{1-4}^1,k_{2-4}^1,k_{3-4}^1)

    又上述函数关系式可以得到各变量之间的求导关系,并利用开始提到的链式法则就能求出对任意一个变量的偏导数:

    链式法则 变量传递图

    如图所示得到了一个链式法则的变量的传递图,根据这个图可以求出偏差E对于任意权值k的偏导数,例如当需要求出\frac{\partial E}{\partial k_{1-1}^2}时,根据上图可以得到:

    \frac{\partial E}{\partial k_{1-1}^2} = \frac{\partial E}{\partial x_1^3} \frac{\partial x_1^3}{\partial s_1^3} \frac{\partial s_1^3}{\partial k_{1-1}^2}

    同理,当需要求出\frac{\partial E}{\partial k_{1-1}^1}时,根据上图可以得到:

    \frac{\partial E}{\partial k_{1-1}^1} = \frac{\partial E}{\partial x_1^3} \frac{\partial x_1^3}{\partial s_1^3} \frac{\partial s_1^3}{\partial x_1^2} \frac{\partial x_1^2}{\partial s_1^2} \frac{\partial s_1^2}{\partial k_{1-1}^1} + \frac{\partial E}{\partial x_2^3} \frac{\partial x_2^3}{\partial s_2^3} \frac{\partial s_2^3}{\partial x_1^2} \frac{\partial x_1^2}{\partial s_1^2} \frac{\partial s_1^2}{\partial k_{1-1}^1}

    其他的权重的偏导数可以类比上述两个式子得到,当关于所有的权值的偏导数都得到后,组成的向量就是偏差在当前位置处的梯度。根据梯度就能不断靠近偏差的最小值点,从而得到满意的输出。

    这里仔细观察上述的链式法则的变量传递图,可以发现一个有趣的事情,当我们把如图所示的部分视为一个新的神经元的话,整个链式法则就像是把神经网络反向一样,变成了一个2-4-(3)的神经网络。

    链式法则 反向传递示意图

    实际上反向传递就是这么来的,神经网络通过对误差的反向传递得到对于所有权值的偏导,即当前的梯度,然后通过反向梯度的方法得到最优解。

    读到这里应该已经对3-4-2的神经网络具体怎么工作有了一个概念,那么接下来要由特殊推至一般,得到任意架构的神经网络其梯度的算法。首先是对于三层的a-b-c的神经网络,上述过程的描述:

    上面已经推导出了正向传递时的a-b-c的神经网络的关系方程:

    第2层第j个神经元:

    s_j^2 =\sum_{i=1}^a x_i^1 * k_{i-j}^1

    x_j^2=f(s_j^2 )

    第3层第k个神经元:

    s_k^3 = \sum_{j=1}^b x_j^2 * k_{j-k}^2

    x_k^3=f(s_k^3 )

    偏差:

    E= \frac{1}{2} \sum_{k=1}^c (x_k^3-y_k)^2

    对于任意的第二层第j个神经元到第三层第k个神经元的权值k_{j-k}^2的偏导数\frac{\partial E}{\partial k_{j-k}^2},有:

    \frac{\partial E}{\partial k_{j-k}^2} = \frac{\partial E}{\partial x_k^3} \frac{\partial x_k^3}{\partial s_k^3} \frac{\partial s_k^3}{\partial k_{j-k}^2}

    这里已知:

    \frac{\partial E}{\partial x_k^3} = x_k^3-y_k

    \frac{\partial x_k^3}{\partial s_k^3}=f'(s_k^3 )

    \frac{\partial s_k^3}{\partial k_{j-k}^2}= x_j^2

    带入到上式中可以得到:

    \frac{\partial E}{\partial k_{j-k}^2} = ( x_k^3-y_k)*f'(s_k^3 )*x_j^2

    同理对于第一层的第i个神经元到第二层的第j个神经元的权值k_{i-j}^1的偏导数,有:

    \frac{\partial E}{\partial k_{i-j}^1} = \sum_{k=1}^c ( \frac{\partial E}{\partial x_k^3} \frac{\partial x_k^3}{\partial s_k^3} \frac{\partial s_k^3}{\partial x_j^2} \frac{\partial x_j^2}{\partial s_j^2} \frac{\partial s_j^2}{\partial k_{i-j}^1})

    这里已知:

    \frac{\partial s_k^3}{\partial x_j^2}=k_{j-k}^2

    \frac{\partial x_j^2}{\partial s_j^2}=f'(s_j^2 )

    \frac{\partial s_j^2}{\partial k_{i-j}^1}=x_i^1

    带入上式可以得到:

    \frac{\partial E}{\partial k_{i-j}^1} = \sum_{k=1}^c [ (x_k^3-y_k)*f'(s_k^3 )*k_{j-k}^2*f'(s_j^2 )*x_i^1]

    到这里,仔细观察上述得到的两个一般情况下的权值的偏导数,可以看出来,假设将(x_k^3-y_k)看成输入,将f'(s_k^3 )看成函数处理,将k_{j-k}^2看成两细胞之间的权值,那么整个方程就可以看做是:

    上一层的某一个神经元输入是(x_k^3-y_k),经过该神经元f'(s_k^3 )的函数处理后,得到该神经元的输出,输出结果乘两神经元之间的权值k_{j-k}^2是加权后的输出,所有加权后的输出结果的和就是\sum_{k=1}^c [ (x_k^3-y_k)*f'(s_k^3 )*k_{j-k}^2],也就是下一层的某个神经元的输入,再经过该神经元f'(s_j^2 )的处理得到\sum_{k=1}^c [ (x_k^3-y_k)*f'(s_k^3 )*k_{j-k}^2]*f'(s_j^2 )......这个过程和前面所提到的神经网络的正向传递的步骤很相似,所以可以想到通过什么方法将正向和反向两个过程结合在一个神经网络的结构下。

    这里仔细观察上一段话的描述,可以发现,如果我在神经元细胞中增加一个反向的通道,通道的输入是误差(对于输出层的神经元来说)或者上一层神经元的输出的加权和(对于隐层的神经元来说),函数处理是该神经元的f'( ),那么可以得到以下神经元的模型:

    神经元模型

    如图所示,虚线表示两个神经元之间的联系程度,即权值,s表示正向通道的加权和,即该神经元正向通道的输入,x表示正向通道的输出;t表示反向通道的加权和,即该神经元反向通道的输入,y表示反向通道的输出,则有一个神经元细胞有如下关系式:

    正向通道:

    s_j^M=\sum_{i=1}^a x_i^L k_{i-j}^{L-M}

    x_j^M=f( s_j^M )

    反向通道:

    t_j^M=\sum_{k=1}^c y_k^N k_{j-k}^{M-N}

    y_j^M=f'( s_j^M )*t_j^M

    该神经元左边任意一个权值的偏导数(因为反向传递时假如每一层都能得到该层左边的权值的偏导数,从输出层一层一层依次计算,就能得到全部的权值的偏导数):

    \frac{\partial E}{\partial k_{i-j}^{L-M}}=y_j^M * x_i^L

    到这里,一个神经元已经可以搭建了,只要每个神经元都能实现上述正向通道、反向通道、权值偏导数计算即是一个合格的神经元,再将多个神经元组合成一层层的神经元层,再将各层之间进行连接,就得到了一个神经网络。这就是一个神经网络搭建的过程。那下面将通过代码实例来给出一个神经网络的搭建过程。

    (后面笔者还在更新......)

    相关文章

      网友评论

          本文标题:BP神经网络算法的深度解析和工程实例搭建

          本文链接:https://www.haomeiwen.com/subject/ewwswftx.html