BP神经网络原理及Python实现
BP神经网络及Python实现
- BP神经网网络原理
- BP网络模型
- BP学习算法
- Python算法实现
- 多层感知器基本参数设定
最近刚好在跟着课程一起学TensorFlow,顺道把整个神经网络的理论复习一遍,最后通过Python实现BP算法。
BP神经网网络原理
从个人理解,BP(反向传播)算法主要是一种求解多层“感知器”中连接权重的迭代方法。其基本思想是,学习信号由信号的正向传播和反向传播两个过程组成,输入信号由输入层传入,经过各隐藏层处理后,传出输出层,若输出层的实际输出与期望的输出不符合时,则转入反向传播阶段。误差反穿是将输出误差以某种形式通过隐藏层向输出层主城传递,并将误差分配给各层的所有单元,并以此信号作为修正各单元权值的依据。这个权值调整的过程就是网络学习训练的过程,这个过程可以一直进行到网络输入的误差减少到可接受的程度或者进行到预先设定的学习次数。
BP网络模型
如上图所示的单隐层网络是目前应用最为广泛的多层感知器神经网络。其中包括了最左侧的输入层,中间的隐藏层和最右侧的输出层。
在三层感知器中,输入向量为 X = ( x 1 , x 2 , ⋯   , x i , ⋯   , x n ) T \boldsymbol { X } = \left( x _ { 1 } , x _ { 2 } , \cdots , x _ { i } , \cdots , x _ { n } \right) ^ { \mathrm { T } } X=(x1,x2,⋯,xi,⋯,xn)T,其中 x 0 = − 1 x_{0} = -1 x0=−1是为输出层神经元引入阈值而设置;隐藏层的输出向量为 Y = ( y 1 , y 2 , ⋯   , y i , ⋯   , y m ) T \boldsymbol { Y } = \left( y _ { 1 } , y _ { 2 } , \cdots , y _ { i } , \cdots , y _ { m } \right) ^ { \mathrm { T } } Y=(y1,y2,⋯,yi,⋯,ym)T,其中 y 0 = − 1 y_{0} = -1 y0=−1 是输出层神经元阈值;输出层向量为 O = ( o 1 , o 2 , ⋯   , o i , ⋯   , o l ) T \boldsymbol { O } = \left( o _ { 1 } , o _ { 2 } , \cdots , o _ { i } , \cdots , o _ { l } \right) ^ { \mathrm { T } } O=(o1,o2,⋯,oi,⋯,ol)T:;期望输出向量为 D = ( d 1 , d 2 , ⋯   , d i , ⋯   , d m ) T \boldsymbol { D } = \left( d _ { 1 } , d _ { 2 } , \cdots , d _ { i } , \cdots , d _ { m } \right) ^ { \mathrm { T } } D=(d1,d2,⋯,di,⋯,dm)T。输入层到隐藏层之间的权值矩阵用 V \boldsymbol { V} V表示,其中列向量 V j \mathbf { V } _ { j } Vj为隐藏层第j个神经元对应的权向量;隐层到输出层之间的权值矩阵用 W \boldsymbol { W} W表示,其中 W k \mathbf { W } _ { k } Wk表示输出层第 k k k个神经元对应的权向量。下面分析各层输出的数学关系。
对于输出层,有:
o k = f ( net k ) k = 1 , 2 , ⋯   , l o _ { k } = f \left( \text { net } _ { k } \right) \quad k = 1,2 , \cdots , l ok=f( net k)k=1,2,⋯,l
net k = ∑ j = 0 m w j k y j k = 1 , 2 , ⋯   , l \text { net } _ { k } = \sum _ { j = 0 } ^ { m } w _ { j k } y _ { j } \quad k = 1,2 , \cdots , l net k=∑j=0mwjkyjk=1,2,⋯,l
对于隐藏层,有:
y j = f ( net j ) j = 1 , 2 , ⋯   , m y _ { j } = f \left( \text { net } _ { j } \right) \quad j = 1,2 , \cdots , m yj=f( net j)j=1,2,⋯,m
net j = ∑ i = 0 n ν i j x i j = 1 , 2 , ⋯   , m \text { net } _ { j } = \sum _ { i = 0 } ^ { n } \nu _ { i j } x _ { i } \quad j = 1,2 , \cdots , m net j=∑i=0nνijxij=1,2,⋯,m
以上两式中,转移 f ( x ) f(x) f(x)函数采用单极性函数Sigmoid函数:
f ( x ) = 1 1 + e − x f ( x ) = \frac { 1 } { 1 + e ^ { - x } } f(x)=1+e−x1
由于 f ( x ) f(x) f(x)具有连续,可导的特点,且有:
f ( x ) = f ( x ) [ 1 − f ( x ) ] f(x)=f(x)[1-f(x)] f(x)=f(x)[1−f(x)]
BP学习算法
当网络输出与期望输出不等时,存在输出误差E,定义如下:
E = 1 2 ( d − O ) 2 = 1 2 ∑ k = 1 l ( d k − o k ) 2 E = \frac { 1 } { 2 } ( d - O ) ^ { 2 } = \frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left( d _ { k } - o _ { k } \right) ^ { 2 } E=21(d−O)2=21∑k=1l(dk−ok)2
将上述误差定义展开至隐藏层,有:
E = 1 2 ∑ k = 1 l [ d k − f ( net k ) ] 2 = 1 2 ∑ k = 1 l [ d k − f ( ∑ j = 0 m w j k y j ) ] 2 = 1 2 ∑ k = 1 l { d k − f [ ∑ j = 0 m w j k f ( n e t j ) ] } 2 = 1 2 ∑ k = 1 l { d k − f [ ∑ j = 0 m w j k f ( ∑ i = 0 n v i j x i ) ] } 2 E = \frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left[ d _ { k } - f \left( \text { net } _ { k } \right) \right] ^ { 2 }= \frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left[ d _ { k } - f \left( \sum _ { j = 0 } ^ { m } w _ { j k } y _ { j } \right) \right] ^ { 2 }=\frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left\{ d _ { k } - f \left[ \sum _ { j = 0 } ^ { m } w _ { j k } f \left( \mathrm { net } _ { j } \right) \right] \right\} ^ { 2 }= \frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left\{ d _ { k } - f \left[ \sum _ { j = 0 } ^ { m } w _ { j k } f \left( \sum _ { i = 0 } ^ { n } v _ { i j } x _ { i } \right) \right] \right\} ^ { 2 } E=21∑k=1l[dk−f( net k)]2=21∑k=1l[dk−f(∑j=0mwjkyj)]2=21∑k=1l{dk−f[∑j=0mwjkf(netj)]}2=21∑k=1l{dk−f[∑j=0mwjkf(∑i=0nvijxi)]}2
因此,网络误差是各层权值 w j k , v i j w _ { j k } , v _ { i j } wjk,vij的函数,因此调整权值可以改变误差。因此,调整权值的原则是使得误差不断地减小,采用最小梯度下降算法,则权值的调整量为:
Δ w j k = − η ∂ E ∂ w j k = − η ∂ E ∂ n e t k ∂ n e t k ∂ w j k \Delta w _ { j k } = - \eta \frac { \partial E } { \partial w _ { j k } }= - \eta \frac { \partial E } { \partial \mathrm { net } _ { k } } \frac { \partial \mathrm { net } _ { k } } { \partial w _ { j k } } Δwjk=−η∂wjk∂E=−η∂netk∂E∂wjk∂netk
Δ v i j = − η ∂ E ∂ v i j = − η ∂ E ∂ net j ∂ net j ∂ v i j \Delta v _ { i j } = - \eta \frac { \partial E } { \partial v _ { i j } } =- \eta \frac { \partial E } { \partial \text { net } _ { j } } \frac { \partial \text { net } _ { j } } { \partial v _ { i j } } Δvij=−η∂vij∂E=−η∂ net j∂E∂vij∂ net j
在推导过程中,对于输出层,均有 j = 0 , 1 , 2 , ⋯   , m , k = 1 , 2 , ⋯   , l j = 0,1,2 , \cdots , m , k = 1,2 , \cdots , l j=0,1,2,⋯,m,k=1,2,⋯,l,对隐藏层具有 i = 0 , 1 , 2 , ⋯   , n , j = 1 , 2 , ⋯   , m i = 0,1,2 , \cdots , n , j = 1,2 , \cdots , m i=0,1,2,⋯,n,j=1,2,⋯,m
对于输出层和隐藏层定义一个误差信号,令:
δ k ∘ = − ∂ E ∂ n e t k = − ∂ E ∂ o k ∂ o k ∂ n e t k = − ∂ E ∂ o k f ′ ( n e t k ) \delta _ { k } ^ { \circ } = - \frac { \partial E } { \partial \mathrm { net } _ { k } } = - \frac { \partial E } { \partial o _ { k } } \frac { \partial o _ { k } } { \partial \mathrm { net } _ { k } } = - \frac { \partial E } { \partial o _ { k } } f ^ { \prime } \left( \mathrm { net } _ { k } \right) δk∘=−∂netk∂E=−∂ok∂E∂netk∂ok=−∂ok∂Ef′(netk)
δ j y = − ∂ E ∂ n e t j = − ∂ E ∂ y j ∂ y j ∂ n e t j = − ∂ E ∂ y j f ′ ( n e t j ) \delta _ { j } ^ { y } = - \frac { \partial E } { \partial \mathrm { net } _ { j } } = - \frac { \partial E } { \partial y _ { j } } \frac { \partial y _ { j } } { \partial \mathrm { net } _ { j } } = - \frac { \partial E } { \partial y _ { j } } f ^ { \prime } \left( \mathrm { net } _ { j } \right) δjy=−∂netj∂E=−∂yj∂E∂netj∂yj=−∂yj∂Ef′(netj)
则,可以将权值调制为:
Δ w j k = η δ k o y j \Delta w _ { j k } = \eta \delta _ { k } ^ { o } y _ { j } Δwjk=ηδkoyj
Δ v i j = η δ j y x i \Delta v _ { i j } = \eta \delta _ {j } ^ { y } x _ { i } Δvij=ηδjyxi
对于输出层,有:
∂ E ∂ o k = − ( d k − o k ) \frac { \partial E } { \partial o _ { k } } = - \left( d _ { k } - o _ { k } \right) ∂ok∂E=−(dk−ok)
对于隐藏层,有:
∂ E ∂ y j = − ∑ k = 1 l ( d k − o k ) f ′ ( net k ) w j k \frac { \partial E } { \partial y _ { j } } = - \sum _ { k = 1 } ^ { l } \left( d _ { k } - o _ { k } \right) f ^ { \prime } \left( \text { net } _ { k } \right) w _ { j k } ∂yj∂E=−∑k=1l(dk−ok)f′( net k)wjk
将结果带入上式得:
δ k ∘ = ( d k − o k ) o k ( 1 − o k ) \delta _ { k } ^ { \circ } = \left( d _ { k } - o _ { k } \right) o _ { k } \left( 1 - o _ { k } \right) δk∘=(dk−ok)ok(1−ok)
δ j k = [ ∑ k = 1 t ( d k − o k ) f ′ ( net k ) w j k ] f ′ ( net j ) = ( ∑ k = 1 l δ k ∘ w j k ) y j ( 1 − y j ) \begin{aligned} \delta _ { j } ^ {k } & = \left[ \sum _ { k = 1 } ^ { t } \left( d _ { k } - o _ { k } \right) f ^ { \prime } \left( \text { net } _ { k } \right) w _ { j k } \right] f ^ { \prime } \left( \text { net } _ { j } \right) \\ & = \left( \sum _ { k = 1 } ^ { l } \delta _ { k } ^ { \circ } w _ { j k } \right) y _ { j } \left( 1 - y _ { j } \right) \end{aligned} δjk=[k=1∑t(dk−ok)f′( net k)wjk]f′( net j)=(k=1∑lδk∘wjk)yj(1−yj)
因此三层感知器的BP学习算法调整权值公式为:
{ Δ w j k = η δ k o y j = η ( d k − o k ) o k ( 1 − o k ) y j Δ v i j = η δ y ; x i = η ( ∑ k = 1 l δ k ∘ w j k ) y j ( 1 − y j ) x i \left\{ \begin{array} { l } { \Delta w _ { j k } = \eta \delta _ { k } ^ { o } y _ { j } = \eta \left( d _ { k } - o _ { k } \right) o _ { k } \left( 1 - o _ { k } \right) y _ { j } } \\ { \Delta v _ { i j } = \eta \delta ^ { y } ; x _ { i } = \eta \left( \sum _ { k = 1 } ^ { l } \delta _ { k } ^ { \circ } w _ { j k } \right) y _ { j } \left( 1 - y _ { j } \right) x _ { i } } \end{array} \right. {Δwjk=ηδkoyj=η(dk−ok)ok(1−ok)yjΔvij=ηδy;xi=η(∑k=1lδk∘wjk)yj(1−yj)xi
Python算法实现
多层感知器基本参数设定
Python采用Python3.6版本,分析数据采用sklearn库中的car数据集。该数据集共有6个特征,共被分成4类。故n=6,l=4,为防止模型过于复杂,训练时间太长,选定隐藏层的神经元数量m=5.
需要注意的是此代码可以成功运行,但准确率并不是很高,整体代码逻辑需要修改
import numpy as np
import sklearn.preprocessing as preprocessing
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_splitdef sigmoid(x): # 激活函数return 1 / (1 + np.exp(-x))
def dsigmoid(x):#sigmoid的倒数return x*(1-x)class NeuralNetwork:def __init__(self,layers):self.v=np.ones((layers[1],layers[0]+1))self.w=np.ones((layers[2],layers[1]+1))def train(self,x,y,lr=0.1,epochs=10000):xtrain=np.ones((x.shape[0],x.shape[1]+1))#进行权值更新训练for n in range(epochs+1):i=np.random.randint(x_train.shape[0])xtrain=np.atleast_2d(x_train[i]).Tytrain=np.atleast_2d(y_train[i]).TL1=sigmoid(np.dot(self.v,xtrain))L1_hat=np.ones((L1.shape[0]+1,1))L1_hat[0:-1]=L1L2=sigmoid(np.dot(self.w,L1_hat))Delta=(ytrain-L2)*L2*(1-L2)delW=np.dot(Delta,L1_hat.T)delV=np.dot(np.dot(Delta.T,self.w[:,0:-1]).T*L1*(1-L1),xtrain.T)self.w+=delWself.v+=delVif n%1000==0:prediction=[]for j in range(x_test.shape[0]):out=self.predict(x_test[j])prediction.append(np.argmax(out))accuracy=np.mean(np.equal(prediction,y_test))print("epoch:",n,"accurayc",accuracy)def predict(self,x):x=np.atleast_2d(x)L1 = sigmoid(np.dot(self.v, x.T))L1_hat = np.ones((L1.shape[0]+1, 1))L1_hat[0:-1] = L1L2 = sigmoid(np.dot(self.w, L1_hat))return L2data=open("J:\研究生生活\课件\华为云TensorFlow\华为TensorFlow代码及教学文件\day1_exercise\homework\data\car.data")
datas=data.readlines()
x=[]
y=[]
for line in datas:line_list=line.strip().split(',')x.append(line_list[:-1])y.append(line_list[-1])
x=np.array(x)label_encoder=preprocessing.LabelBinarizer()
label_encoder.fit(['unacc','acc','good','vgood'])
y_endoded=label_encoder.transform(y)
x_encoded=np.empty(x.shape)
xlabeltrans=[]
for i,item in enumerate(x[0]):xlabeltrans.append(preprocessing.LabelEncoder())x_encoded[:,i]=xlabeltrans[-1].fit_transform(x[:,i])
x_encoded=np.hstack((x_encoded,np.ones((x_encoded.shape[0],1))))
x=x_encoded[:,:-1].astype(int)
x,y=shuffle(x,y,random_state=0)
x_train,x_test,y_train,y_test=train_test_split(x_encoded,y_endoded,test_size=0.25)
y_test=[np.argmax(i) for i in y_test]nm=NeuralNetwork([6,5,4])
nm.train(x_train,y_train,epochs=20000)
BP神经网络原理及Python实现
BP神经网络及Python实现
- BP神经网网络原理
- BP网络模型
- BP学习算法
- Python算法实现
- 多层感知器基本参数设定
最近刚好在跟着课程一起学TensorFlow,顺道把整个神经网络的理论复习一遍,最后通过Python实现BP算法。
BP神经网网络原理
从个人理解,BP(反向传播)算法主要是一种求解多层“感知器”中连接权重的迭代方法。其基本思想是,学习信号由信号的正向传播和反向传播两个过程组成,输入信号由输入层传入,经过各隐藏层处理后,传出输出层,若输出层的实际输出与期望的输出不符合时,则转入反向传播阶段。误差反穿是将输出误差以某种形式通过隐藏层向输出层主城传递,并将误差分配给各层的所有单元,并以此信号作为修正各单元权值的依据。这个权值调整的过程就是网络学习训练的过程,这个过程可以一直进行到网络输入的误差减少到可接受的程度或者进行到预先设定的学习次数。
BP网络模型
如上图所示的单隐层网络是目前应用最为广泛的多层感知器神经网络。其中包括了最左侧的输入层,中间的隐藏层和最右侧的输出层。
在三层感知器中,输入向量为 X = ( x 1 , x 2 , ⋯   , x i , ⋯   , x n ) T \boldsymbol { X } = \left( x _ { 1 } , x _ { 2 } , \cdots , x _ { i } , \cdots , x _ { n } \right) ^ { \mathrm { T } } X=(x1,x2,⋯,xi,⋯,xn)T,其中 x 0 = − 1 x_{0} = -1 x0=−1是为输出层神经元引入阈值而设置;隐藏层的输出向量为 Y = ( y 1 , y 2 , ⋯   , y i , ⋯   , y m ) T \boldsymbol { Y } = \left( y _ { 1 } , y _ { 2 } , \cdots , y _ { i } , \cdots , y _ { m } \right) ^ { \mathrm { T } } Y=(y1,y2,⋯,yi,⋯,ym)T,其中 y 0 = − 1 y_{0} = -1 y0=−1 是输出层神经元阈值;输出层向量为 O = ( o 1 , o 2 , ⋯   , o i , ⋯   , o l ) T \boldsymbol { O } = \left( o _ { 1 } , o _ { 2 } , \cdots , o _ { i } , \cdots , o _ { l } \right) ^ { \mathrm { T } } O=(o1,o2,⋯,oi,⋯,ol)T:;期望输出向量为 D = ( d 1 , d 2 , ⋯   , d i , ⋯   , d m ) T \boldsymbol { D } = \left( d _ { 1 } , d _ { 2 } , \cdots , d _ { i } , \cdots , d _ { m } \right) ^ { \mathrm { T } } D=(d1,d2,⋯,di,⋯,dm)T。输入层到隐藏层之间的权值矩阵用 V \boldsymbol { V} V表示,其中列向量 V j \mathbf { V } _ { j } Vj为隐藏层第j个神经元对应的权向量;隐层到输出层之间的权值矩阵用 W \boldsymbol { W} W表示,其中 W k \mathbf { W } _ { k } Wk表示输出层第 k k k个神经元对应的权向量。下面分析各层输出的数学关系。
对于输出层,有:
o k = f ( net k ) k = 1 , 2 , ⋯   , l o _ { k } = f \left( \text { net } _ { k } \right) \quad k = 1,2 , \cdots , l ok=f( net k)k=1,2,⋯,l
net k = ∑ j = 0 m w j k y j k = 1 , 2 , ⋯   , l \text { net } _ { k } = \sum _ { j = 0 } ^ { m } w _ { j k } y _ { j } \quad k = 1,2 , \cdots , l net k=∑j=0mwjkyjk=1,2,⋯,l
对于隐藏层,有:
y j = f ( net j ) j = 1 , 2 , ⋯   , m y _ { j } = f \left( \text { net } _ { j } \right) \quad j = 1,2 , \cdots , m yj=f( net j)j=1,2,⋯,m
net j = ∑ i = 0 n ν i j x i j = 1 , 2 , ⋯   , m \text { net } _ { j } = \sum _ { i = 0 } ^ { n } \nu _ { i j } x _ { i } \quad j = 1,2 , \cdots , m net j=∑i=0nνijxij=1,2,⋯,m
以上两式中,转移 f ( x ) f(x) f(x)函数采用单极性函数Sigmoid函数:
f ( x ) = 1 1 + e − x f ( x ) = \frac { 1 } { 1 + e ^ { - x } } f(x)=1+e−x1
由于 f ( x ) f(x) f(x)具有连续,可导的特点,且有:
f ( x ) = f ( x ) [ 1 − f ( x ) ] f(x)=f(x)[1-f(x)] f(x)=f(x)[1−f(x)]
BP学习算法
当网络输出与期望输出不等时,存在输出误差E,定义如下:
E = 1 2 ( d − O ) 2 = 1 2 ∑ k = 1 l ( d k − o k ) 2 E = \frac { 1 } { 2 } ( d - O ) ^ { 2 } = \frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left( d _ { k } - o _ { k } \right) ^ { 2 } E=21(d−O)2=21∑k=1l(dk−ok)2
将上述误差定义展开至隐藏层,有:
E = 1 2 ∑ k = 1 l [ d k − f ( net k ) ] 2 = 1 2 ∑ k = 1 l [ d k − f ( ∑ j = 0 m w j k y j ) ] 2 = 1 2 ∑ k = 1 l { d k − f [ ∑ j = 0 m w j k f ( n e t j ) ] } 2 = 1 2 ∑ k = 1 l { d k − f [ ∑ j = 0 m w j k f ( ∑ i = 0 n v i j x i ) ] } 2 E = \frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left[ d _ { k } - f \left( \text { net } _ { k } \right) \right] ^ { 2 }= \frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left[ d _ { k } - f \left( \sum _ { j = 0 } ^ { m } w _ { j k } y _ { j } \right) \right] ^ { 2 }=\frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left\{ d _ { k } - f \left[ \sum _ { j = 0 } ^ { m } w _ { j k } f \left( \mathrm { net } _ { j } \right) \right] \right\} ^ { 2 }= \frac { 1 } { 2 } \sum _ { k = 1 } ^ { l } \left\{ d _ { k } - f \left[ \sum _ { j = 0 } ^ { m } w _ { j k } f \left( \sum _ { i = 0 } ^ { n } v _ { i j } x _ { i } \right) \right] \right\} ^ { 2 } E=21∑k=1l[dk−f( net k)]2=21∑k=1l[dk−f(∑j=0mwjkyj)]2=21∑k=1l{dk−f[∑j=0mwjkf(netj)]}2=21∑k=1l{dk−f[∑j=0mwjkf(∑i=0nvijxi)]}2
因此,网络误差是各层权值 w j k , v i j w _ { j k } , v _ { i j } wjk,vij的函数,因此调整权值可以改变误差。因此,调整权值的原则是使得误差不断地减小,采用最小梯度下降算法,则权值的调整量为:
Δ w j k = − η ∂ E ∂ w j k = − η ∂ E ∂ n e t k ∂ n e t k ∂ w j k \Delta w _ { j k } = - \eta \frac { \partial E } { \partial w _ { j k } }= - \eta \frac { \partial E } { \partial \mathrm { net } _ { k } } \frac { \partial \mathrm { net } _ { k } } { \partial w _ { j k } } Δwjk=−η∂wjk∂E=−η∂netk∂E∂wjk∂netk
Δ v i j = − η ∂ E ∂ v i j = − η ∂ E ∂ net j ∂ net j ∂ v i j \Delta v _ { i j } = - \eta \frac { \partial E } { \partial v _ { i j } } =- \eta \frac { \partial E } { \partial \text { net } _ { j } } \frac { \partial \text { net } _ { j } } { \partial v _ { i j } } Δvij=−η∂vij∂E=−η∂ net j∂E∂vij∂ net j
在推导过程中,对于输出层,均有 j = 0 , 1 , 2 , ⋯   , m , k = 1 , 2 , ⋯   , l j = 0,1,2 , \cdots , m , k = 1,2 , \cdots , l j=0,1,2,⋯,m,k=1,2,⋯,l,对隐藏层具有 i = 0 , 1 , 2 , ⋯   , n , j = 1 , 2 , ⋯   , m i = 0,1,2 , \cdots , n , j = 1,2 , \cdots , m i=0,1,2,⋯,n,j=1,2,⋯,m
对于输出层和隐藏层定义一个误差信号,令:
δ k ∘ = − ∂ E ∂ n e t k = − ∂ E ∂ o k ∂ o k ∂ n e t k = − ∂ E ∂ o k f ′ ( n e t k ) \delta _ { k } ^ { \circ } = - \frac { \partial E } { \partial \mathrm { net } _ { k } } = - \frac { \partial E } { \partial o _ { k } } \frac { \partial o _ { k } } { \partial \mathrm { net } _ { k } } = - \frac { \partial E } { \partial o _ { k } } f ^ { \prime } \left( \mathrm { net } _ { k } \right) δk∘=−∂netk∂E=−∂ok∂E∂netk∂ok=−∂ok∂Ef′(netk)
δ j y = − ∂ E ∂ n e t j = − ∂ E ∂ y j ∂ y j ∂ n e t j = − ∂ E ∂ y j f ′ ( n e t j ) \delta _ { j } ^ { y } = - \frac { \partial E } { \partial \mathrm { net } _ { j } } = - \frac { \partial E } { \partial y _ { j } } \frac { \partial y _ { j } } { \partial \mathrm { net } _ { j } } = - \frac { \partial E } { \partial y _ { j } } f ^ { \prime } \left( \mathrm { net } _ { j } \right) δjy=−∂netj∂E=−∂yj∂E∂netj∂yj=−∂yj∂Ef′(netj)
则,可以将权值调制为:
Δ w j k = η δ k o y j \Delta w _ { j k } = \eta \delta _ { k } ^ { o } y _ { j } Δwjk=ηδkoyj
Δ v i j = η δ j y x i \Delta v _ { i j } = \eta \delta _ {j } ^ { y } x _ { i } Δvij=ηδjyxi
对于输出层,有:
∂ E ∂ o k = − ( d k − o k ) \frac { \partial E } { \partial o _ { k } } = - \left( d _ { k } - o _ { k } \right) ∂ok∂E=−(dk−ok)
对于隐藏层,有:
∂ E ∂ y j = − ∑ k = 1 l ( d k − o k ) f ′ ( net k ) w j k \frac { \partial E } { \partial y _ { j } } = - \sum _ { k = 1 } ^ { l } \left( d _ { k } - o _ { k } \right) f ^ { \prime } \left( \text { net } _ { k } \right) w _ { j k } ∂yj∂E=−∑k=1l(dk−ok)f′( net k)wjk
将结果带入上式得:
δ k ∘ = ( d k − o k ) o k ( 1 − o k ) \delta _ { k } ^ { \circ } = \left( d _ { k } - o _ { k } \right) o _ { k } \left( 1 - o _ { k } \right) δk∘=(dk−ok)ok(1−ok)
δ j k = [ ∑ k = 1 t ( d k − o k ) f ′ ( net k ) w j k ] f ′ ( net j ) = ( ∑ k = 1 l δ k ∘ w j k ) y j ( 1 − y j ) \begin{aligned} \delta _ { j } ^ {k } & = \left[ \sum _ { k = 1 } ^ { t } \left( d _ { k } - o _ { k } \right) f ^ { \prime } \left( \text { net } _ { k } \right) w _ { j k } \right] f ^ { \prime } \left( \text { net } _ { j } \right) \\ & = \left( \sum _ { k = 1 } ^ { l } \delta _ { k } ^ { \circ } w _ { j k } \right) y _ { j } \left( 1 - y _ { j } \right) \end{aligned} δjk=[k=1∑t(dk−ok)f′( net k)wjk]f′( net j)=(k=1∑lδk∘wjk)yj(1−yj)
因此三层感知器的BP学习算法调整权值公式为:
{ Δ w j k = η δ k o y j = η ( d k − o k ) o k ( 1 − o k ) y j Δ v i j = η δ y ; x i = η ( ∑ k = 1 l δ k ∘ w j k ) y j ( 1 − y j ) x i \left\{ \begin{array} { l } { \Delta w _ { j k } = \eta \delta _ { k } ^ { o } y _ { j } = \eta \left( d _ { k } - o _ { k } \right) o _ { k } \left( 1 - o _ { k } \right) y _ { j } } \\ { \Delta v _ { i j } = \eta \delta ^ { y } ; x _ { i } = \eta \left( \sum _ { k = 1 } ^ { l } \delta _ { k } ^ { \circ } w _ { j k } \right) y _ { j } \left( 1 - y _ { j } \right) x _ { i } } \end{array} \right. {Δwjk=ηδkoyj=η(dk−ok)ok(1−ok)yjΔvij=ηδy;xi=η(∑k=1lδk∘wjk)yj(1−yj)xi
Python算法实现
多层感知器基本参数设定
Python采用Python3.6版本,分析数据采用sklearn库中的car数据集。该数据集共有6个特征,共被分成4类。故n=6,l=4,为防止模型过于复杂,训练时间太长,选定隐藏层的神经元数量m=5.
需要注意的是此代码可以成功运行,但准确率并不是很高,整体代码逻辑需要修改
import numpy as np
import sklearn.preprocessing as preprocessing
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_splitdef sigmoid(x): # 激活函数return 1 / (1 + np.exp(-x))
def dsigmoid(x):#sigmoid的倒数return x*(1-x)class NeuralNetwork:def __init__(self,layers):self.v=np.ones((layers[1],layers[0]+1))self.w=np.ones((layers[2],layers[1]+1))def train(self,x,y,lr=0.1,epochs=10000):xtrain=np.ones((x.shape[0],x.shape[1]+1))#进行权值更新训练for n in range(epochs+1):i=np.random.randint(x_train.shape[0])xtrain=np.atleast_2d(x_train[i]).Tytrain=np.atleast_2d(y_train[i]).TL1=sigmoid(np.dot(self.v,xtrain))L1_hat=np.ones((L1.shape[0]+1,1))L1_hat[0:-1]=L1L2=sigmoid(np.dot(self.w,L1_hat))Delta=(ytrain-L2)*L2*(1-L2)delW=np.dot(Delta,L1_hat.T)delV=np.dot(np.dot(Delta.T,self.w[:,0:-1]).T*L1*(1-L1),xtrain.T)self.w+=delWself.v+=delVif n%1000==0:prediction=[]for j in range(x_test.shape[0]):out=self.predict(x_test[j])prediction.append(np.argmax(out))accuracy=np.mean(np.equal(prediction,y_test))print("epoch:",n,"accurayc",accuracy)def predict(self,x):x=np.atleast_2d(x)L1 = sigmoid(np.dot(self.v, x.T))L1_hat = np.ones((L1.shape[0]+1, 1))L1_hat[0:-1] = L1L2 = sigmoid(np.dot(self.w, L1_hat))return L2data=open("J:\研究生生活\课件\华为云TensorFlow\华为TensorFlow代码及教学文件\day1_exercise\homework\data\car.data")
datas=data.readlines()
x=[]
y=[]
for line in datas:line_list=line.strip().split(',')x.append(line_list[:-1])y.append(line_list[-1])
x=np.array(x)label_encoder=preprocessing.LabelBinarizer()
label_encoder.fit(['unacc','acc','good','vgood'])
y_endoded=label_encoder.transform(y)
x_encoded=np.empty(x.shape)
xlabeltrans=[]
for i,item in enumerate(x[0]):xlabeltrans.append(preprocessing.LabelEncoder())x_encoded[:,i]=xlabeltrans[-1].fit_transform(x[:,i])
x_encoded=np.hstack((x_encoded,np.ones((x_encoded.shape[0],1))))
x=x_encoded[:,:-1].astype(int)
x,y=shuffle(x,y,random_state=0)
x_train,x_test,y_train,y_test=train_test_split(x_encoded,y_endoded,test_size=0.25)
y_test=[np.argmax(i) for i in y_test]nm=NeuralNetwork([6,5,4])
nm.train(x_train,y_train,epochs=20000)