阅读 148

【神经网络基础】BP算法原理及两种实现

一、BP算法

以一个单隐层神经网络做二分类为例,如图:

1.先简单介绍一个各个参数:

m:表示样本数量。

y:各个样本真实值,维度为m*1

n^{[l]}:表示第l层的神经元个数。

a^{[l]}:表示第l层的输入变量,也是第l-1层z^{[l]}经过激活函数处理后的结果。其维度一般为a^{[l]}=n^{[l]}*m

w^{[l]}:表示第l层权重参数,其维度一般为w^{[l]}=n^{[l]}*n^{[l-1]}

b^{[l]}:表示第l层偏置量参数,其维度一般为b^{[l]}=n^{[l]}*m

z^{[l]}:表示第l层线性变换后的结果,其维度一般为z^{[l]}=n^{[l]}*m

2.前向传播计算过程:

  • 输入层a^{[0]}是一个n^{[0]}*m的矩阵,即为m个样本,每个样本包含n^{[0]}个特征,本例为3*5。
  • 隐藏层有n^{[1]}个隐藏单元。该隐层中包括两步计算,

一是线性变换,w_{[i]}^{[1]}为第一个隐藏层的第i个隐藏单元参数,b_{[i]}^{[1]}为第一个隐藏层的第i个隐藏单元偏置量;z^{[1]}=w^{[1]}*a^{[0]}+b^{[1]}

第二步是激活函数,非线性变换,并且将数值变换到0-1之间,本例选择sigmoid函数作为激活函数。a^{[1]}=sigmoid(z^{[1]})

  • 输出层只有一个节点,n^{[2]}=1,对于本层而言,输入就是a^{[1]},线性变换与激活函数处理之后得到最终预测值a^{[2]},根据均方误差计算损失函数L(y,a)。

3.反向传播过程,更新参数值:

反向传播是利用链式法则对各个参数求偏导数的过程。我们的训练目标是使得损失函数最小化,神经网络中利用梯度下降法更新参数w和b使得损失函数L值最小化。了解梯度下降的话,应该知道梯度下降中更新参数的办法是使得各个参数按一定步长(学习率)沿着函数下降最快的方向(由于梯度方向就是函数上升最快的方向,因此函数下降最快的方向就是梯度反方向)移动,直到找到全局或局部最优解为止。

首先要清楚z^{[k]}a^{[k]}的来源:

z^{[k]}=w^{[k]}*a^{[k-1]}+b^{[k]}

a^{[k]}=f(z^{[k]}) #f为一种激活函数

那么接下来求第k层和第k-1层的w与b的偏导数。

\frac{{\partial L(y,a)}}{{\partial w^{[k]}}} = \frac{{\partial L(y,a)}}{{\partial z^{[k]}}}*\frac{{\partial z^{[k]}}}{{\partial w^{[k]}}}

\frac{{\partial L(y,a)}}{{\partial b^{[k]}}} = \frac{{\partial L(y,a)}}{{\partial z^{[k]}}}*\frac{{\partial z^{[k]}}}{{\partial b^{[k]}}}

一是求\delta^{[k]}=\frac{{\partial L(y,a)}}{{\partial z^{[k]}}},定义\delta^{[k]}为第k层的误差项,反映了该层对最终总误差的影响。根据链式法则:

\delta^{[k]}=\frac{{\partial a^{[k]}}}{{\partial z^{[k]}}}*\frac{{\partial z^{[k+1]}}}{{\partial a^{[k]}}}*\frac{{\partial L(y,a)}}{{\partial z^{[k+1]}}} = f'(z^{[k]}) (w^{[k+1]})^{T}\delta^{[k+1]}

二是求\frac{{\partial z^{[k]}}}{{\partial w^{[k]}}}\frac{{\partial z^{[k]}}}{{\partial b^{[k]}}}

\frac{{\partial z^{[k]}}}{{\partial w^{[k]}}} =a^{[k-1]}

\frac{{\partial z^{[k]}}}{{\partial b^{[k]}}}=1

因此求第k层的偏导数依赖于第k+1层的偏导数的值,体现了反向传播的意义。

\frac{{\partial L(y,a)}}{{\partial w^{[k]}}} =\delta^{[k]}*(a^{[k-1]})^{T}

\frac{{\partial L(y,a)}}{{\partial b^{[k]}}}=\delta^{[k]}

然后更新参数为:

w^{[k]}-=lr*\frac{{\partial L(y,a)}}{{\partial w^{[k]}}}

b^{[k]}-=lr*\frac{{\partial L(y,a)}}{{\partial b^{[k]}}}

在多次循环迭代中,不断执行前向传播计算损失函数值与反向传播更新参数,最终使得损失在一定范围内。

二、Python实现BP神经网络

#coding:utf-8
#BP算法的python实现
import numpy as np

def sigmoid(x):
    return 1/(1+np.exp(-x))

def derivative(x):
    return (1-x)*x

class nn(object):
    def __init__(self,layer):
        np.random.seed(2)
        self.w=[]
        for i in range(1,len(layer)):
            # np.random.random((1000,20))代表生成1000行 20列的浮点数,浮点数都是从0-1中随机。
            self.w.append(2*np.random.random((layer[i-1],layer[i]))-1)

    def train(self,x,y,lr,echo):
        a=[x]
        for ech in range(echo):
            for i in range(0,len(self.w)):
                a.append(sigmoid(np.dot(a[i],self.w[i])))
            if(ech%100==0):
                print('echo',ech,'-error %f:',np.mean((a[-1]-y)**2))
            l_error=-(y-a[-1])
            for k in range(len(self.w)-1,-1,-1):
                l_delta = l_error*derivative(np.array(a[k+1]))
                w_update=np.dot(a[k].T,l_delta)
                l_error=np.dot(l_delta,self.w[k].T)
                self.w[k]-=lr*w_update
        return self.w

    def predict(self,w,test):
        l1 = sigmoid(np.dot(test, self.w[0]))
        l2 = sigmoid(np.dot(l1, self.w[1]))
        if l2 >= 0.5:
            print(l2,"1")
        else:
            print(l2,"0")

layer=[3,4,1]
x = np.array([[0, 0, 1],[0, 1, 1],[1, 0, 1],[1, 1, 1],[0, 0, 1]])
y = np.array([[0],[1],[1],[0],[0]])
nn=nn(layer)
w=nn.train(x,y,0.1,2000)
nn.predict(w,[1,1,0])
复制代码

三、tensorflow实现BP神经网络

待更新
复制代码
关注下面的标签,发现更多相似文章
评论