在咱们开始DL的研究以前,须要把ANN—人工神经元网络以及bp算法作一个简单解释。
关于ANN的结构,我再也不多说,网上有大量的学习资料,主要就是搞清一些名词:
输入层/输入神经元,输出层/输出神经元,隐层/隐层神经元,权值,偏置,激活函数
接下来咱们须要知道ANN是怎么训练的,假设ANN网络已经搭建好了,在全部应用问题中(无论是网络结构,训练手段如何变化)咱们的目标是不会变的,那就是网络的权值和偏置最终都变成一个最好的值,这个值可让咱们由输入能够获得理想的输出,因而问题就变成了y=f(x,w,b)(x是输入,w是权值,b为偏置,全部这些量均可以有多个,好比多个x1,x2,x3……最后f()就比如咱们的网络它必定能够用一个函数来表示,咱们不须要知道f(x)具体是怎样的函数,从小咱们就认为只要是函数就必定要是可表示的,像f(x)=sin(x)同样,可是请摈弃这样的错误观念,咱们只须要知道一系列的w和b决定了一个函数f(x),这个函数让咱们由输入能够计算出合理的y)
最后的目标就变成了尝试不一样的w,b值,使得最后的y=f(x)无限接近咱们但愿获得的值t
可是这个问题依然很复杂,咱们把它简化一下,让(y-t)^2的值尽量的小。因而原先的问题化为了C(w,b)=(f(x,w,b)-t)^2取到一个尽量小的值。这个问题不是一个困难的问题,不论函数如何复杂,若是C下降到了一个没法再下降的值,那么就取到了最小值(假设咱们不考虑局部最小的状况)html
如何降低?数学告诉咱们对于一个多变量的函数f(a,b,c,d,……)而言,咱们能够求得一个向量,它称做该函数的梯度,要注意的是,梯度是一个方向向量,它表示这个函数在该点变化率最大的方向(这个定理不详细解释了,能够在高等数学教材上找到)因而C(w,b)的变化量ΔC就能够表示成算法
其中网络
是该点上的微小变化,咱们能够随意指定这些微小变化,只须要保证ΔC<0就能够了,可是为了更快的降低,咱们为什么不选在梯度方向上作变化呢?函数
事实上,梯度降低的思想就是这样考虑的,咱们使得从而保证C一直递减,而对于w来讲只要每次更新
便可。
ok,到这里,彷佛全部的问题都解决了,让咱们从新整理一下思绪,咱们将问题转化了不少步:
网络权值偏置更新问题 ==> f(x,w,b)的结果逼近t ==> C(w,b)=(f(x,w,b)-t)^2取极小值问题 ==> C(w,b)按梯度降低问题 ==>取到极小值,网络达到最优
千万别忘了一点!!推导基于一个前提:咱们已经提早知道了当前点的梯度。然而事实并不是如此!!
这个问题困扰了NN研究者多年,1969年M.Minsky和S.Papert所著的《感知机》一书出版,它对单层神经网络进行了深刻分析,而且从数学上证实了这种网络功能有限,甚至不能解决象"异或"这样的简单逻辑运算问题。同时,他们还发现有许多模式是不能用单层网络训练的,而对于多层网络则没有行之有效的低复杂度算法,最后他们甚至认为神经元网络没法处理非线性问题。然而于1974年,Paul Werbos首次给出了如何训练通常网络的学习算法—back propagation。这个算法能够高效的计算每一次迭代过程当中的梯度,让以上咱们的推导得以实现!!
不巧的是,在当时整我的工神经网络社群中无人知晓Paul所提出的学习算法。直到80年代中期,BP算法才从新被David Rumelhart、Geoffrey Hinton及Ronald Williams、David Parker和Yann LeCun独立发现,并得到了普遍的注意,引发了人工神经网络领域研究的第二次热潮。学习
上面已经提到,所谓反向传播,就是计算梯度的方法。对于反向传播,先不急着介绍它的原理,不少文章直接引入公式,反而使得咱们很难去理解。这里先引入知乎上某位大神的回答。spa
来源:知乎https://www.zhihu.com/question/27239198?rf=24827633.net
假设输入a=2,b=1,在这种状况下,咱们很容易求出相邻节点之间的偏导关系3d
利用链式法则:htm
以及
blog
的值等于从a到e的路径上的偏导值的乘积,而
的值等于从b到e的路径1(b-c-e)上的偏导值的乘积加上路径2(b-d-e)上的偏导值的乘积。也就是说,对于上层节点p和下层节点q,要求得
,须要找到从q节点到p节点的全部路径,而且对每条路径,求得该路径上的全部偏导数之乘积,而后将全部路径的 “乘积” 累加起来才能获得
的值。
这种状况下偏导很容易求得,由于咱们已经知道网络的函数关系式,e=(a+b)*(b+1),这是一个没有权值干预,已知输入与输出之间关系的网络。实际当中咱们只是知道e与输出之间的关系,就是上面说的C=(y-t)^2,并且会有成千上万的权值和偏置干预求导的过程。那么换个思路,能不能求输出对结果的偏导呢?
再利用上图的关系。节点c对e偏导2并将结果堆放起来,节点d对e偏导3并将结果堆放起来,至此第二层完毕,求出各节点总堆放量并继续向下一层发送。节点c向a发送2*1并对堆放起来,节点c向b发送2*1并堆放起来,节点d向b发送3*1并堆放起来,至此第三层完毕,节点a堆放起来的量为2,节点b堆放起来的量为2*1+3*1=5, 即顶点e对b的偏导数为5。简要的归纳,就是从最上层的节点e开始,以层为单位进行处理。对于e的下一层的全部子节点,将1乘以e到某个节点路径上的偏导值,并将结果“堆放”在该子节点中。等e所在的层按照这样传播完毕后,第二层的每个节点都“堆放"些值,而后咱们针对每一个节点,把它里面全部“堆放”的值求和,就获得了顶点e对该节点的偏导。而后将这些第二层的节点各自做为起始顶点,初始值设为顶点e对它们的偏导值,以"层"为单位重复上述传播过程,便可求出顶点e对每一层节点的偏导数。
假设,你有这样一个网络层:
第一层是输入层,包含两个神经元i1,i2,和截距项b1;第二层是隐含层,包含两个神经元h1,h2和截距项b2,第三层是输出o1,o2,每条线上标的wi是层与层之间链接的权重,激活函数咱们默认为sigmoid函数。
如今对他们赋上初值,以下图:
其中,输入数据 i1=0.05,i2=0.10;
输出数据 o1=0.01,o2=0.99;
初始权重 w1=0.15,w2=0.20,w3=0.25,w4=0.30;
w5=0.40,w6=0.45,w7=0.50,w8=0.88
目标:给出输入数据i1,i2(0.05和0.10),使输出尽量与原始输出o1,o2(0.01和0.99)接近。
Step 1 前向传播
1.输入层---->隐含层:
计算神经元h1的输入加权和:
神经元h1的输出o1:(此处用到激活函数为sigmoid函数):
同理,可计算出神经元h2的输出o2:
2.隐含层---->输出层:
计算输出层神经元o1和o2的值:
这样前向传播的过程就结束了,咱们获得输出值为[0.75136079 , 0.772928465],与实际值[0.01 , 0.99]相差还很远,如今咱们对偏差进行反向传播,更新权值,从新计算输出。
Step 2 反向传播
1.计算总偏差
总偏差:(square error)
可是有两个输出,因此分别计算o1和o2的偏差,总偏差为二者之和:
2.隐含层---->输出层的权值更新:
以权重参数w5为例,若是咱们想知道w5对总体偏差产生了多少影响,能够用总体偏差对w5求偏导求出:(链式法则)
下面的图能够更直观的看清楚偏差是怎样反向传播的:
如今咱们来分别计算每一个式子的值:
计算:
计算:
(这一步实际上就是对sigmoid函数求导,比较简单,能够本身推导一下)
计算:
最后三者相乘:
这样咱们就计算出总体偏差E(total)对w5的偏导值。
回过头来再看看上面的公式,咱们发现:
为了表达方便,用来表示输出层的偏差:
所以,总体偏差E(total)对w5的偏导公式能够写成:
若是输出层偏差计为负的话,也能够写成:
最后咱们来更新w5的值:
(其中,是学习速率,这里咱们取0.5)
同理,可更新w6,w7,w8:
3.隐含层---->隐含层的权值更新:
方法其实与上面说的差很少,可是有个地方须要变一下,在上文计算总偏差对w5的偏导时,是从out(o1)---->net(o1)---->w5,可是在隐含层之间的权值更新时,是out(h1)---->net(h1)---->w1,而out(h1)会接受E(o1)和E(o2)两个地方传来的偏差,因此这个地方两个都要计算。
计算:
先计算:
同理,计算出:
二者相加获得总值:
再计算:
再计算:
最后,三者相乘:
为了简化公式,用sigma(h1)表示隐含层单元h1的偏差:
最后,更新w1的权值:
同理,额可更新w2,w3,w4的权值:
这样偏差反向传播法就完成了,最后咱们再把更新的权值从新计算,不停地迭代,在这个例子中第一次迭代以后,总偏差E(total)由0.298371109降低至0.291027924。迭代10000次后,总偏差为0.000035085,输出为[0.015912196,0.984065734](原输入为[0.01,0.99]),证实效果仍是不错的
以上4个方程中,第一个方程其实不难理解,就是求输出对估价函数C的偏导。
惟一比较困难的,就是第二个方程,它给出了根据下一层的错误量δl+1计算δl的等式。为证实该等式,咱们先依据δkl+1=∂C/∂zkl+1从新表达下等式δlj =∂C/∂zlj。这里能够应用链式法则:
在最后一行,咱们互换了下表达式右侧的两项,并取代了 δkl+1的定义。为了对最后一行的第一项求值,注意:
做微分,咱们获得
代回 (42) 咱们获得
这就是以份量形式呈现的 (BP2)。后两式在完成了BP2证实以后就不太难了,留给读者来证实。