反向传播(back propagation)_神经网络中的运用

反向传播(back propagation)_神经网络中的运用

   反向传播(back propagation)实际上是梯度降低的延伸, 当神经网络超过2层的时候, 须要求解中间层的偏差项 δ \delta 就须要用到反向传播了. 本文将经过简单的例子, 讲解反向传播在神经网络中的运用.
   上一篇博文: 梯度降低_神经网络中的运用 经过简单的2层神经网络,对梯度降低进行了讲解.当明白了梯度降低以后, 就能够进一步了解它的延伸:反向传播(back propagation)了.html

基础知识

   为了便于理解, 咱们依然用简单的3层网络来说解, 好比下面的网络. 输入单元被标注为 x 1 , x 2 , x 3 , x_{1},x_{2},x_{3},​ ,隐藏层节点是 h 1 , h 2 h_{1},h_{2} ​.web

   在梯度降低博文中咱们研究的是只有一个输出节点网络,代码也很直观。可是如今咱们有多个输入单元和多个隐藏单元,它们的权重须要有两个索引 w i j w_{ij} ,其中 i i 表示输入单元, j j 表示隐藏单元。好比: w 12 w_{12} 就表示 x 1 x_{1} h 2 h_{2} 的权重.算法

   权重被储存在矩阵中,由 w i j w_{ij} 来索引。矩阵中的每一行对应从同一个输入节点发出的权重,每一列对应传入同一个隐藏节点的权重。这里咱们有三个输入节点,两个隐藏节点,权重矩阵表示为:网络

   从上图中咱们能够获得隐藏节点 h 1 h_{1} 的输入:
h 1 = x 1 w 11 + x 2 w 21 + x 3 w 31 h_{1}=x_{1}w_{11}+x_{2}w_{21}+x_{3}w_{31} app

   由此类推, 因此对每个隐藏层节点 h j h_{j} ​,其计算公式为:
h j = j w i j x i h_{j}=\sum _{j}w_{ij}x_{i} svg

   其矩阵运算直观展现以下:函数

   有了上面的基础知识后, 就能够介绍反向传播到底怎么工做的了.学习

反向传播

   如何让多层神经网络学习呢?咱们已了解了使用梯度降低来更新权重,反向传播算法则是它的一个延伸。以一个两层神经网络为例,可使用链式法则计算输入层-隐藏层间权重的偏差。spa

   要使用梯度降低法更新隐藏层的权重,你须要知道各隐藏层节点的偏差对最终输出的影响。每层的输出是由两层间的权重决定的,两层之间产生的偏差,按权重缩放后在网络中向前传播, 这就是反向传播。既然咱们知道输出偏差,即可以用权重来反向传播到隐藏层。.net

   例如,输出节点的偏差是: δ o \delta ^{o} ,则隐藏节点的偏差既为输出偏差 δ o \delta ^{o} 乘以输出层-隐藏层间的权重 w j w_{j} ,即 w j δ 0 w_{j}\delta ^{0} .
   隐藏节点的偏差项 δ j h \delta ^{h}_{j} 隐藏节点的偏差 f ( h j ) *f'\left( h_{j}\right) , 结果以下公式所示:

δ j h = w j δ 0 f ( h j ) \delta ^{h}_{j}=w_{j}\delta ^{0}f'\left( h_{j}\right)

   而后,梯度降低与上一篇博文: 梯度降低_神经网络中的运用 中的梯度降低相同,只是偏差项 δ \delta 变为新的偏差项 δ j h \delta ^{h}_{j}
Δ w i j = η δ j h x i \Delta w_{ij}=\eta \delta ^{h}_{j}x_{i}

   若是神经网络有不少层,道理也是同样的,从输出层逐渐向里反向传播就行了.逐一获得个层的偏差项,而后采用梯度降低的方法跟新对应层的权重就行了.

来个实例

import numpy as np

#定义sigmoid函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

x = np.array([0.5, 0.1, -0.2])   #定义输入.x1,x2,x3
target = 0.6                     #定义输出
learnrate = 0.5                  #学习率

weights_input_hidden = np.array([[0.5, -0.6],          #初始化输入层到中间层的权重wij
                                 [0.1, -0.2],
                                 [0.1, 0.7]])

weights_hidden_output = np.array([0.1, -0.3])          #初始化中间层到输出层的权重wj

## 前向传播
hidden_layer_input = np.dot(x, weights_input_hidden)   #中间层的输入hj
hidden_layer_output = sigmoid(hidden_layer_input)      #中间层的输出f(hj)

output_layer_in = np.dot(hidden_layer_output, weights_hidden_output)      #输出层的输入oj
output = sigmoid(output_layer_in)                                         #输出层的输出f(oj)

## 反向传播
error = target - output                                 #输出层的偏差

output_error_term = error * output * (1 - output)       #输出层的偏差项

hidden_error_term = np.dot(output_error_term, weights_hidden_output) * \
                    hidden_layer_output * (1 - hidden_layer_output)       #中间层偏差项

#中间层到输出层的权重更新步长
delta_w_h_o = learnrate * output_error_term * hidden_layer_output

#输入层到中间层的权重更新步长
delta_w_i_h = learnrate * hidden_error_term * x[:, None]

print('中间层到输出层的权重更新步长:')
print(delta_w_h_o)
print('输入层到中间层的权重更新步长:')
print(delta_w_i_h)

中间层到输出层的权重更新步长:
[0.00804047 0.00555918]
输入层到中间层的权重更新步长:
[[ 1.77005547e-04 -5.11178506e-04]
 [ 3.54011093e-05 -1.02235701e-04]
 [-7.08022187e-05  2.04471402e-04]]