说明
学习深度学习的过程中,遇到了一个用例子讲解反向传播算法的博文,简单粗暴容易理解,很适合我这种小白,所以打算翻译一下分享,英文水平有限,翻译不对的地方请告知。原文地址在这。下面是译文。
背景
反向传播在神经网络的训练中是一种经常被用到的算法。关于反向传播算法网上有很多讲解,但是很少有用真实的数字为大家举例子来解释的。在本篇博文中,我将努力用一个具体的例子来解释反向传播是怎样工作的,为了确定自己理解的是否正确,大家可以先按照自己的理解算一下。
如果这篇博文吸引到了你,你可以注册我的时事通讯,在里面会张贴一些我正在研究的人工智能相关的博文。
在Python中使用反向传播
你也可以用我写的Python脚本玩一玩,程序已经实现了反向传播算法。
反向传播算法可视化
对于展示一个神经网络训练的交互式可视化,大家可以来我的神经网络可视化看一下。
一些其他的资源
如果你觉得这个教程对你是有用的且想继续学习关于神经网络的知识和它们的应用,我强烈推荐Adrian Rosebrock的教程,Getting Started with Deep Learning and Python.
总览
这个教程,我们打算用两个输入节点、两个隐藏节点和两个输出节点。另外,输出节点和隐藏节点将会包含一个偏置。(这个地方,我感觉应该是输入节点和输出节点,但是还是按照原文翻译了。)
下面是一个基本的架构:
为了有些数可以算,下面标注了初始化权重、偏置量和训练集的输入输出:
反向传播算法的目标是优化权重,使神经网络能够学习到怎样正确地在任意的输入输出之间映射。
教程的其他部分都会围绕一个单一样本进行,给定的输入时0.05和0.10,我们想让这个神经网络能够分别对应输出0.01和0.99。
先走一遍前向传播
一开始,先让我们看一下在当前给定值的情况下神经网络预测的怎么样。所以我们先把输入数据喂给神经网络。
我们每个隐藏层节点的总净输入,用一个激活函数(这里使用的逻辑回归)压缩这个总净输入,然后对输出节点重复这个过程。
总净出入也被称为净输入,参考了某些资料。
下面我们计算 h1 的总净输入
然后我们再用逻辑回归函数去获得输出 h1 的输出:
对于 h2 执行同样的过程:
我们将会对输出层的节点重复这个过程,用隐藏层的输出作为输入。
下面是这个输出
o1
:
并且对 o2 执行同样的过程:
outo2=0.772928465
计算总误差
我们现在可以用平方误差函数来计算每个输出节点的误差,并且把它们加起来得到总误差。
Etotal=∑12(target−output)2
一些资料把目标值也叫作理想值,把输出值叫做实际值。
比如说, o1 的目标输出是0.01,但是神经网络的输出是0.75136507,因此误差是:
Eo1=12(targeto1−outo1)2=12(0.01−0.75136507)2=0.274811083
对 o2 重复这个过程(记住目标值为0.99),
Eo2=0.023560026
整个神经网络的总误差是这些误差的和:
Etotal=Eo1+Eo2=0.274811083+0.023560026=0.298371109
走一遍反向传播
反向传播算法的目标是更新神经网络中的每一个权重,以便得到实际输出和目标输出更接近,因此要最小化输出节点和整个网络的误差。
输出层
看一下
w5
,我们想知道
w5
的改变是怎样影响总输出值的,也就是
∂Etotal∂w5
。
通过应用我们熟知的链式法则,有:
可视化我们正在做的工作:
我们需要计算出这个方程式的每块。
首先,总误差相对于输出的梯度是多少呢?
−(target−out) 有时被表达为 out−target
当我们取总误差相对于 outo1 的偏导时, 12(targeto2−outo2)2 将会为0,因为 outo1 不会影响它。
接下来,输出
o1
相对于总净输入的偏导是多少呢?
逻辑回归的偏导是输出乘以1减去输出:
最后,总净输入相对于 w5 的偏导是多少呢?
把它们组织起来:
你会经常看到以delta法则组织计算的式子
∂Etotal∂w5=−(tageto1−outo1)∗outo1∗(1−outo1)∗outh1
另外,我们可以让 ∂Etotal∂outo1∗∂outo1∂neto1 写成 ∂Etotal∂neto1 ,也就是 δo1 。我们可以用这个重写上面的计算式:
δo1=∂Etotal∂outo1∗∂outo1∂neto1=∂Etotal∂neto1
δo1=−(tageto1−outo1)∗outo1∗(1−outo1)
因此:
∂Etotal∂w5=δo1outh1
一些资料抽象出了负号:
∂Etotal∂w5=−δo1outh1
为了减少总误差,我们用当前的权重值减去这个值(可以乘以学习效率,eta,在这里我们设为0.5):
一些资料用 α (alpha)来表示学习效率,有一些资料用 η (eta)来表示,还有一些用 ϵ (epsilon).
我们可以重复这个过程得到 w6,w7,w8 的新权重:
我们在神经网络中实际执行更新的操作是在隐藏层中所有的权重都有更新的动作之后(也就是说,在下面的反向传播过程中,我们使用的是开始的权重,而不是更新后的权重)。 此处翻译不确定!
隐藏层
接下来,我们将会计算
w1,w2,w3,w4
的新值,继续完成这个后向传播算法。
看一下大图,这里面有我们要计算的:
∂Etotal∂w1=∂Etotal∂outh1∗∂outh1∂neth1∗∂neth1∂w1
可视化如下:
我们将会用一个相似的过程来计算,就像对输出层做的那样,但是也会有一些不同, 那就是每个隐藏节点的输出都会对多个输出神经元和误差有影响。我们知道 outh1 影响了 outo1 和 outo2 ,因此 ∂Etotal∂outh1 需要被考虑进去。
以 ∂Etotal∂outh1 的计算开始:
我们可以用之前计算出的值来计算 ∂Eo1∂neto1 :
而 ∂neto1∂outh1 等于 w5 :
插进去:
接下来对 ∂Eo2∂outh1 执行同样的过程:
∂Eo2∂outh1=−0.019049119
因此:
既然我们已经算出了 ∂Etotal∂outh1 , 接下来我们需要计算出 ∂outh1∂neth1 ,接下来再对每一个权重计算 ∂neth1∂w :
我们再计算对 h1 的净输入相对于 w1 的偏导,就像之前我们对输出节点做的那样:
整合在一起:
也能把上面写作:
∂Etotal∂w1=(∑o∂Etotal∂outo∗∂outo∂neto∗∂neto∂outh1)∗∂outh1∂neth1∗∂neth1∂w1
∂Etotal∂w1=(∑oδo∗who)∗outh1(1−outh1)∗i1
∂Etotal∂w1=δh1i1
现在我们就可以更新 w1 :
对 w2,w3,w4 重复这个过程:
最终,我们已经将所有的权重更新了一遍!当我们一开始喂给神经网络初始的输入0.05和0.1之后,神经网络的误差是0.298371109。在第一遍反向传播之后,总误差将为了0.291027924。误差也许看起来没有减少地那么大,但是在重复这个过程10000次之后,比如说,这个误差将会跌到0.000035085。在这个时候,我们的0.05、0.1的输入,在两个输出节点上将会产生 0.015912196 (对比 0.01 的目标值) 和 0.984065734 (对比 0.99 的目标值)。