BP,就是后向传播(back propagation),说明BP网络要向后传递一个什么东西,这个东西就是误差。

而神经网络,就是由神经元组成的网络,所以在考虑BP之前,还不得不弄清楚神经元是什么。

神经元

泛泛地说,神经元,就是一个函数 w ( x ) w(x) w(x),而且这个函数往往比较友好,可能是一个线性函数,可以表示为

w ( x ) = ∑ i w i x i w(x)=\sum_i w_ix_i w(x)=iwixi

其中 x i x_i xi x x x的诸分量,而且这个分量很可能不是一个标量,而是一个数组,甚至矩阵,即多维数组。

神经网络的目的,就是在给定 x , y x,y x,y的情况下,根据 y = w ( x ) y=w(x) y=w(x)求出 w i w_i wi的值。

如果仅仅是这个程度,那么神经元的地位就和矩阵计算发生了重叠,神经网络就直接退化成最小二乘法了,所以神经元在进行线性代数的计算之后,要引入一个非线性的函数;同时考虑到神经元对中心的偏移,所以网络中还要加一个 B B B参数,故整体可以表示为

w ( x ) = f ( ∑ i w i x i + b i ) w(x)=f\bigg(\sum_i w_ix_i+b_i\bigg) w(x)=f(iwixi+bi)

这里的 f f f是一个非线性函数,一般叫做激活函数,被这个函数一激活,那么平平无奇的矩阵计算,就华华丽丽地变身成了神经元。

这个激活函数并不需要十分复杂,但一般要起到归一化的作用,比如下面将要用到的sigmoid函数

σ ( x ) = 1 1 + exp ⁡ − x \sigma(x)=\frac{1}{1+\exp -x} σ(x)=1+expx1

BP原理及实现

单个神经元虽然组不成网络,但也有一个专门的名称,即单层感知机,可用于数据二分,由于用途单一,所以就不讲了,直接开始多层的BP网络的编写。

那么在书写之前,先声明一下要做的事情。现有一组 x x x和一组 y y y,我们希望建立一个神经网络 W W W,在 x x x经过 W W W之后,得到的结果 Y Y Y y y y的差值小于误差要求。

如前文所述,神经网络是由多个神经元组成的,而神经元最重要的两个参数是 W W W B B B,用以完成对函数 y y y的拟合,这个拟合的过程,即由 x x x得到 Y Y Y的过程,便是前向过程,相应地 W 1 W_1 W1 B 1 B_1 B1构成的就是前向网络。

而后向过程传递的是误差,这也同样需要神经元的帮助,从而需要另一组神经元 W 2 , B 2 W_2, B_2 W2,B2,这些参数的初值可以随机选取。考虑到BP网络实现起来非常轻便,故先将代码列在下面,然后再解读其含义

import numpy as np
sigmoid = lambda x : 1/(1+np.exp(-np.array(xs)))

def bpnn(xs, ys, nIter=101, th=0.005, nHide=10): 
    W1 = np.random.rand(nHide) 
    B1 = np.random.rand(nHide) 
    W2 = np.random.rand(nHide) 
    B2 = np.random.rand()
    for k in range(nIter):
        Y = []
        for xi,yi in zip(xs,ys):
            L1 = xi*W1-B1                # 隐含层输入数据
            L2 = sigmoid(L1)          #隐含层的输出数据
            Y.append(np.sum(W2*L2) - B2) #模型输出
            err = Y[-1] - yi                # 模型误差
            ##反馈,修改参数
            dB2 = -1*th*err
            dW2 = err*th*L2
            dB1 = W2*L2*(1-L2)*(-1)*err*th
            dW1 = W2*L2*(1-L2)*xi*err*th
            W1 = W1 - dW1
            B1 = B1 - dB1
            W2 = W2 - dW2
            B2 = B2 - dB2
        if k%100==0:
            print(k)
    return Y

bpnn的输入除了将要被拟合的xs,ys之外,还有迭代次数nIter, 学习率th以及神经元的权重个数nHide

其中, W 1 , B 1 , W 2 , B 2 W_1,B_1,W_2,B_2 W1,B1,W2,B2便是上文提到的网络参数,前两者用于前向传播,也就是根据 x s xs xs得到 Y Y Y,后两者用于后向传播,就是根据 Y Y Y y s ys ys得到误差。

这段程序的核心过程是for xi,yi in zip(xs,ys)中的内容,表示对每一组 x , y x,y x,y点对进行神经网络的学习,其中 L 1 L_1 L1 L 2 L_2 L2对应 W 1 , B 1 W_1, B_1 W1,B1 W 2 , B 2 W_2, B_2 W2,B2的两个隐藏层。

数据的流动过程为

x->L1->L2->Y->err

首先第一步,根据当前的 W 1 , B 1 W_1,B_1 W1,B1计算得到L1,通过激活函数,生成L2,通过L2得到拟合结果Y,通过比对Yy的值,就可以得到误差err。此为前向传播过程。

接下来就是根据err,来逆推参数的变化量,其基本流程为前向传播的逆过程,第一步得到dB2,其值为

δ B 2 = − θ ∗ σ \delta B_2=-\theta*\sigma δB2=θσ

其中 θ , σ \theta, \sigma θ,σ分别对应代码中的th, err,表示根据学习率和误差,对B2参数进行微调。

然后是dW2,值为

δ W 2 = θ ∗ σ ∗ L 2 \delta W_2=\theta*\sigma*L_2 δW2=θσL2

即除了受到误差和学习率的影响之外,也要考虑L2的影响。那么这个值是怎么来的呢?

σ = w 2 L 2 + b 2 − y ∂ σ ∂ w 2 = L 2 \begin{aligned} \sigma &= w_2L_2+b_2-y\\ \frac{\partial\sigma}{\partial w_2}&=L_2 \end{aligned} σw2σ=w2L2+b2y=L2

∂ σ ∂ w 2 \frac{\partial\sigma}{\partial w_2} w2σ相当于是 w 2 w_2 w2的微小变动对 σ \sigma σ的影响。之所以要引入学习率,乃因直接通过 σ L 2 \sigma L_2 σL2得到的值可能过大,从而跳过真值。

第三步是dB1,值为

δ B 1 = − θ σ w 2 L 2 ( 1 − L 2 ) \delta B_1=-\theta\sigma w_2L_2(1-L_2) δB1=θσw2L2(1L2)

其缘由为

σ = w 2 L 2 + b 2 − y = w 2 f ( w 1 L 1 + b 1 ) + b 2 − y ∂ σ ∂ w 2 = ∂ f ∂ w 1 \begin{aligned} \sigma&=w_2L_2+b_2-y=w_2f(w_1L_1+b1)+b_2-y\\ \frac{\partial\sigma}{\partial w_2}&=\frac{\partial f}{\partial w_1} \end{aligned} σw2σ=w2L2+b2y=w2f(w1L1+b1)+b2y=w1f

考虑到 f f f的表达式 f ( x ) = 1 1 + exp ⁡ − x f(x)=\frac{1}{1+\exp -x} f(x)=1+expx1,则

d f d x = e − x ( 1 + e − x ) = ( 1 − 1 1 + e − x ) ( 1 1 + e − x ) = f ( x ) ( 1 − f ( x ) ) \frac{\text d f}{\text d x}=\frac{e^{-x}}{(1+e^{-x})}=(1-\frac{1}{1+e^{-x}})(\frac{1}{1+e^{-x}})=f(x)(1-f(x)) dxdf=(1+ex)ex=(11+ex1)(1+ex1)=f(x)(1f(x))

考虑到其所谓的 x x x w 1 L 1 w_1L_1 w1L1构成,所以得到的结果就是w_1L_2(1-L_2)

同理,得到最后一组参数W1的更新方案,

测试

最后,又到了喜闻乐见的测试环节

if __name__=="__main__":
    xs = np.arange(1000)*0.01
    ys = np.sin(xs)
    Y = bpnn(xs, ys, nIter=501, th=0.005, nHide=10)
    fig = plt.figure()
    
    plt.plot(xs,ys)
    plt.plot(xs,Y,color='red',linestyle='--')
    plt.show()

得到结果为

在这里插入图片描述

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐