作者:Evan Hoo
链接:http://www.zhihu.com/question/27239198/answer/89853077
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
我觉得理解BP算法原理最直接与清晰的就是根据computation graph了,话不多说,直接上图。这里举了一个三层神经网络(一个输入层、一个隐层和一个输出层)的例子,使用了softmax输出层,损失函数使用交叉熵。训练神经网络可以使用梯度下降的方法,重点是计算…
显示全部
直接上干货,
Neural networks and deep learning(深度学习在线书chap2),把这一篇看完然后可以看看torch7的nn里面随便一个层的写法,或者caffe的Backward的实现,这两种框架都是按照layer-by-layer的方法设计的。另外比较灵活的一种方式是通过定义computa…
显示全部
链接:http://www.zhihu.com/question/27239198/answer/89853077
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
BackPropagation算法是多层神经网络的训练中举足轻重的算法。
简单的理解,它的确就是复合函数的链式法则,但其在实际运算中的意义比链式法则要大的多。
要回答题主这个问题“如何直观的解释back propagation算法?” 需要先直观理解多层神经网络的训练。
机器学习可以看做是数理统计的一个应用,在数理统计中一个常见的任务就是拟合,也就是给定一些样本点,用合适的曲线揭示这些样本点随着自变量的变化关系。
深度学习同样也是为了这个目的,只不过此时,样本点不再限定为(x, y)点对,而可以是由向量、矩阵等等组成的广义点对(X,Y)。而此时,(X,Y)之间的关系也变得十分复杂,不太可能用一个简单函数表示。然而,人们发现可以用多层神经网络来表示这样的关系,而多层神经网络的本质就是一个多层复合的函数。借用网上找到的一幅图[1],来直观描绘一下这种复合关系。
上面式中的Wij就是相邻两层神经元之间的权值,它们就是深度学习需要学习的参数,也就相当于直线拟合y=k*x+b中的待求参数k和b。
上面式中的Wij就是相邻两层神经元之间的权值,它们就是深度学习需要学习的参数,也就相当于直线拟合y=k*x+b中的待求参数k和b。
和直线拟合一样,深度学习的训练也有一个目标函数,这个目标函数定义了什么样的参数才算一组“好参数”,不过在机器学习中,一般是采用成本函数(cost function),然后,训练目标就是通过调整每一个权值Wij来使得cost达到最小。cost函数也可以看成是由所有待求权值Wij为自变量的复合函数,而且基本上是非凸的,即含有许多局部最小值。但实际中发现,采用我们常用的梯度下降法就可以有效的求解最小化cost函数的问题。
梯度下降法需要给定一个初始点,并求出该点的梯度向量,然后以负梯度方向为搜索方向,以一定的步长进行搜索,从而确定下一个迭代点,再计算该新的梯度方向,如此重复直到cost收敛。那么如何计算梯度呢?
假设我们把cost函数表示为
, 那么它的梯度向量[2]就等于
, 其中
表示正交单位向量。为此,我们需求出cost函数H对每一个权值Wij的偏导数。而
BP算法正是用来求解这种多层复合函数的所有变量的偏导数的利器。
我们以求e=(a+b)*(b+1)的偏导[3]为例。
它的复合关系画出图可以表示如下:
在图中,引入了中间变量c,d。
在图中,引入了中间变量c,d。
为了求出a=2, b=1时,e的梯度,我们可以先利用偏导数的定义求出不同层之间相邻节点的偏导关系,如下图所示。
利用链式法则我们知道:
利用链式法则我们知道:
以及
。
链式法则在上图中的意义是什么呢?其实不难发现,
的值等于从a到e的路径上的偏导值的乘积,而
的值等于从b到e的路径1(b-c-e)上的偏导值的乘积加上路径2(b-d-e)上的偏导值的乘积。也就是说,对于上层节点p和下层节点q,要求得
,需要找到从q节点到p节点的所有路径,并且对每条路径,求得该路径上的所有偏导数之乘积,然后将所有路径的 “乘积” 累加起来才能得到
的值。
大家也许已经注意到,这样做是十分冗余的,因为很多 路径被重复访问了。比如上图中,a-c-e和b-c-e就都走了路径c-e。对于权值动则数万的深度模型中的神经网络,这样的冗余所导致的计算量是相当大的。
同样是利用链式法则,BP算法则机智地避开了这种冗余,它对于每一个路径只访问一次就能求顶点对所有下层节点的偏导值。
正如反向传播(BP)算法的名字说的那样,BP算法是反向(自上往下)来寻找路径的。
从最上层的节点e开始,初始值为1,以层为单位进行处理。对于e的下一层的所有子节点,将1乘以e到某个节点路径上的偏导值,并将结果“堆放”在该子节点中。等e所在的层按照这样传播完毕后,第二层的每一个节点都“堆放"些值,然后我们针对每个节点,把它里面所有“堆放”的值求和,就得到了顶点e对该节点的偏导。然后将这些第二层的节点各自作为起始顶点,初始值设为顶点e对它们的偏导值,以"层"为单位重复上述传播过程,即可求出顶点e对每一层节点的偏导数。
以上图为例,节点c接受e发送的1*2并堆放起来,节点d接受e发送的1*3并堆放起来,至此第二层完毕,求出各节点总堆放量并继续向下一层发送。节点c向a发送2*1并对堆放起来,节点c向b发送2*1并堆放起来,节点d向b发送3*1并堆放起来,至此第三层完毕,节点a堆放起来的量为2,节点b堆放起来的量为2*1+3*1=5, 即顶点e对b的偏导数为5.
举个不太恰当的例子,如果把上图中的箭头表示欠钱的关系,即c→e表示e欠c的钱。以a, b为例,直接计算e对它们俩的偏导相当于a, b各自去讨薪。a向c讨薪,c说e欠我钱,你向他要。于是a又跨过c去找e。b先向c讨薪,同样又转向e,b又向d讨薪,再次转向e。可以看到,追款之路,充满艰辛,而且还有重复,即a, b 都从c转向e。
而BP算法就是主动还款。e把所欠之钱还给c,d。c,d收到钱,乐呵地把钱转发给了a,b,皆大欢喜。
------------------------------------------------------------------
【参考文献】
[1] 技术向:一文读懂卷积神经网络CNN
[2] Gradient
[3] http://colah.github.io/posts/2015-08-Backprop/
其他推荐网页:
1. tensorflow.org 的页面
2. Neural networks and deep learning
简单的理解,它的确就是复合函数的链式法则,但其在实际运算中的意义比链式法则要大的多。
要回答题主这个问题“如何直观的解释back propagation算法?” 需要先直观理解多层神经网络的训练。
机器学习可以看做是数理统计的一个应用,在数理统计中一个常见的任务就是拟合,也就是给定一些样本点,用合适的曲线揭示这些样本点随着自变量的变化关系。
深度学习同样也是为了这个目的,只不过此时,样本点不再限定为(x, y)点对,而可以是由向量、矩阵等等组成的广义点对(X,Y)。而此时,(X,Y)之间的关系也变得十分复杂,不太可能用一个简单函数表示。然而,人们发现可以用多层神经网络来表示这样的关系,而多层神经网络的本质就是一个多层复合的函数。借用网上找到的一幅图[1],来直观描绘一下这种复合关系。
![](https://i-blog.csdnimg.cn/blog_migrate/0e97036486c7088602d1edf1d9ad7746.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0e97036486c7088602d1edf1d9ad7746.png)
其对应的表达式如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8185ff54244e7bf6950e92257008076d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8185ff54244e7bf6950e92257008076d.png)
和直线拟合一样,深度学习的训练也有一个目标函数,这个目标函数定义了什么样的参数才算一组“好参数”,不过在机器学习中,一般是采用成本函数(cost function),然后,训练目标就是通过调整每一个权值Wij来使得cost达到最小。cost函数也可以看成是由所有待求权值Wij为自变量的复合函数,而且基本上是非凸的,即含有许多局部最小值。但实际中发现,采用我们常用的梯度下降法就可以有效的求解最小化cost函数的问题。
梯度下降法需要给定一个初始点,并求出该点的梯度向量,然后以负梯度方向为搜索方向,以一定的步长进行搜索,从而确定下一个迭代点,再计算该新的梯度方向,如此重复直到cost收敛。那么如何计算梯度呢?
假设我们把cost函数表示为
我们以求e=(a+b)*(b+1)的偏导[3]为例。
它的复合关系画出图可以表示如下:
![](https://i-blog.csdnimg.cn/blog_migrate/86a95b798a76750cb205895fe5a82ab3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/86a95b798a76750cb205895fe5a82ab3.png)
为了求出a=2, b=1时,e的梯度,我们可以先利用偏导数的定义求出不同层之间相邻节点的偏导关系,如下图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/d065528268a0417aa2d94d92fe1bb7f3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d065528268a0417aa2d94d92fe1bb7f3.png)
链式法则在上图中的意义是什么呢?其实不难发现,
大家也许已经注意到,这样做是十分冗余的,因为很多 路径被重复访问了。比如上图中,a-c-e和b-c-e就都走了路径c-e。对于权值动则数万的深度模型中的神经网络,这样的冗余所导致的计算量是相当大的。
同样是利用链式法则,BP算法则机智地避开了这种冗余,它对于每一个路径只访问一次就能求顶点对所有下层节点的偏导值。
正如反向传播(BP)算法的名字说的那样,BP算法是反向(自上往下)来寻找路径的。
从最上层的节点e开始,初始值为1,以层为单位进行处理。对于e的下一层的所有子节点,将1乘以e到某个节点路径上的偏导值,并将结果“堆放”在该子节点中。等e所在的层按照这样传播完毕后,第二层的每一个节点都“堆放"些值,然后我们针对每个节点,把它里面所有“堆放”的值求和,就得到了顶点e对该节点的偏导。然后将这些第二层的节点各自作为起始顶点,初始值设为顶点e对它们的偏导值,以"层"为单位重复上述传播过程,即可求出顶点e对每一层节点的偏导数。
以上图为例,节点c接受e发送的1*2并堆放起来,节点d接受e发送的1*3并堆放起来,至此第二层完毕,求出各节点总堆放量并继续向下一层发送。节点c向a发送2*1并对堆放起来,节点c向b发送2*1并堆放起来,节点d向b发送3*1并堆放起来,至此第三层完毕,节点a堆放起来的量为2,节点b堆放起来的量为2*1+3*1=5, 即顶点e对b的偏导数为5.
举个不太恰当的例子,如果把上图中的箭头表示欠钱的关系,即c→e表示e欠c的钱。以a, b为例,直接计算e对它们俩的偏导相当于a, b各自去讨薪。a向c讨薪,c说e欠我钱,你向他要。于是a又跨过c去找e。b先向c讨薪,同样又转向e,b又向d讨薪,再次转向e。可以看到,追款之路,充满艰辛,而且还有重复,即a, b 都从c转向e。
而BP算法就是主动还款。e把所欠之钱还给c,d。c,d收到钱,乐呵地把钱转发给了a,b,皆大欢喜。
------------------------------------------------------------------
【参考文献】
[1] 技术向:一文读懂卷积神经网络CNN
[2] Gradient
[3] http://colah.github.io/posts/2015-08-Backprop/
其他推荐网页:
1. tensorflow.org 的页面
2. Neural networks and deep learning
知乎用户、知乎用户、Zhaoyang Shao
等人赞同
就是一个求导的链式法则嘛。。。
就是一个求导的链式法则嘛。。。
不是归人
赞同
拿纸和笔,定个最简单的三层网络,分别对各权值求偏导.
拿纸和笔,定个最简单的三层网络,分别对各权值求偏导.
剑桥桥头
赞同
可以理解为误差分配。对应于强化学习中的信度分配问题。……
可以理解为误差分配。对应于强化学习中的信度分配问题。……
哪个结点对“我”有贡献,反过来要回报它→_→
哪个结点对“我”有贡献,反过来要回报它→_→
神经网络用图来表示复合函数。所以对复合函数求导时,链式法则这一代数运算就能被表示成图上的消息传递。
神经网络用图来表示复合函数。所以对复合函数求导时,链式法则这一代数运算就能被表示成图上的消息传递。
知乎用户
赞同
![](https://i-blog.csdnimg.cn/blog_migrate/785efaed3d1cd8fca62943143ae402c6.png)
我觉得理解BP算法原理最直接与清晰的就是根据computation graph了,话不多说,直接上图。
这里举了一个三层神经网络(一个输入层、一个隐层和一个输出层)的例子,使用了softmax输出层,损失函数使用交叉熵。训练神经网络可以使用梯度下降的方法,重点是计算梯度,也就是损失函数对参数的导数,在图中可以表示为dloss/dW1,dloss/dW2,dloss/db1和dloss/db2。如何计算这些梯度,使用的就是BP算法,其实也就是求导的链式法则。
这里举了一个三层神经网络(一个输入层、一个隐层和一个输出层)的例子,使用了softmax输出层,损失函数使用交叉熵。训练神经网络可以使用梯度下降的方法,重点是计算梯度,也就是损失函数对参数的导数,在图中可以表示为dloss/dW1,dloss/dW2,dloss/db1和dloss/db2。如何计算这些梯度,使用的就是BP算法,其实也就是求导的链式法则。
在每一轮迭代中,首先进行forward propagation,也就是计算computation graph中每个节点的状态:
之后进行back propagation,也就是计算computation graph中每个节点相对于损失函数(这里表示为loss)的导数,这里面应用了链式法则。对于dloss/dtanh2, dloss/dadd2等导数,下面省略分子直接表示为dtanh2等。
上面的变量都可以用矩阵表示,直接进行矩阵运算。其中dW1,dW2,db1和db2就是我们需要求的参数的梯度。
在编程实现上,每一个计算节点都可以定义两个函数,一个是forward,用于给定输入计算输出;一个是backward,用于给定反向梯度,计算整个表达式(相当于损失函数)相对于这个节点的输入的梯度,应用链式法则就是:这个节点相对于其输入的梯度(直接对输入求导)乘以这个节点接受的反向梯度。
我有一个tutorial,使用Python如何一步一步的实现神经网络,而且可以自定义网络的层数和每层的维度,扩展性很强。其中,抽象出来了gate(AddGate,MulGate),layer(Tanh,Sigmoid)和output(Softmax),你也可以自己实现不同的layer比如ReLu,或不同的output(比如Hinge)。
感兴趣的请移步
GitHub - pangolulu/neural-network-from-scratch: Implementing Multiple Layer Neural Network from Scratch
![](https://i-blog.csdnimg.cn/blog_migrate/07c9d1c60e483891ae62f47c9b7e637e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/07c9d1c60e483891ae62f47c9b7e637e.png)
在每一轮迭代中,首先进行forward propagation,也就是计算computation graph中每个节点的状态:
mul1 = X * W1
add1 = mul1 + b1
tanh1 = tanh(add1)
mul2 = tanh1 * W2
add2 = mul2 + b2
tanh2 = tanh(add2)
loss = softmax_loss(tanh2)
dloss = 1
dtanh2 = softmax_loss_diff(tanh2) * dloss
dadd2 = tanh_diff(add2) * dtanh2
db2 = 1 * dadd2
dmul2 = 1 * dadd2
dW2 = tanh1 * dmul2
dtanh1 = W2 * dmul2
dadd1 = tanh_diff(add1) * dtanh1
db1 = 1 * dadd1
dmul1 = 1 * dadd1
dW1 = X * dmul1
在编程实现上,每一个计算节点都可以定义两个函数,一个是forward,用于给定输入计算输出;一个是backward,用于给定反向梯度,计算整个表达式(相当于损失函数)相对于这个节点的输入的梯度,应用链式法则就是:这个节点相对于其输入的梯度(直接对输入求导)乘以这个节点接受的反向梯度。
我有一个tutorial,使用Python如何一步一步的实现神经网络,而且可以自定义网络的层数和每层的维度,扩展性很强。其中,抽象出来了gate(AddGate,MulGate),layer(Tanh,Sigmoid)和output(Softmax),你也可以自己实现不同的layer比如ReLu,或不同的output(比如Hinge)。
感兴趣的请移步
GitHub - pangolulu/neural-network-from-scratch: Implementing Multiple Layer Neural Network from Scratch
知乎用户、thomas yin、赵小姐
等人赞同
Apply the chain rule to compute the gradient of the lossfunction with respect to the inputs.---cs231n
Apply the chain rule to compute the gradient of the lossfunction with respect to the inputs.
---cs231n
---cs231n
知乎用户
赞同
斯坦福的Andrew的公开课中对BP算法的直观演示。
Coursera - Free Online Courses From Top Universities
斯坦福的Andrew的公开课中对BP算法的直观演示。
Coursera - Free Online Courses From Top Universities
Coursera - Free Online Courses From Top Universities
我感觉最直观的理解不就是它的名字么,误差回传播嘛,不知道你想要多直观啊...
我感觉最直观的理解不就是它的名字么,误差回传播嘛,不知道你想要多直观啊...
俞造廷
赞同
![](https://i-blog.csdnimg.cn/blog_migrate/5fdc679a249aacb24db449c20039526c.png)
直接上干货,
Neural networks and deep learning(深度学习在线书chap2),把这一篇看完然后可以看看torch7的nn里面随便一个层的写法,或者caffe的Backward的实现,这两种框架都是按照layer-by-layer的方法设计的。另外比较灵活的一种方式是通过定义computation graph,通过定义节点上基本操作的梯度,然后利用auto differentiation的思路就可以进行BP了(Tensorflow和MXNet的采用的思路)。
z为没经过激活函数的输出,a是经过激活函数的输出。
z为没经过激活函数的输出,a是经过激活函数的输出。
定义损失函数(Cost)关于 l 层输出z的偏导为:
则可以得到BP的4个基本方程:
则可以得到BP的4个基本方程:
该在线书上有关于前两个公式的证明的推导,仿照着利用chain rule,后两个公式也可以很简单地证明出来。
该在线书上有关于前两个公式的证明的推导,仿照着利用chain rule,后两个公式也可以很简单地证明出来。
另外贴一下BP算法和mini-batch SGD的算法:
BP:
----
----
mini-batch SGD:
BP算法最开始的发现是基于每个权重(weight)或者偏置(bias)的微小改变都能引起输出的改变,于是就进一步产生了用Cost对于这些参数的导数来更新w,b,进而达到改进输出的目的。
这里一种很直接的思路就是直接求Cost关于每个参数的导数(比如 [C(w+dw)-C(w)]/dw 这种数值微分),但是这种方法需要进行参数个数量次的Backward过程,计算代价很大。BP算法的提出就是为了优雅地解决这一问题,它只需要一次Backward就能将误差传到每一个可学的参数(w,b)。
(以上,该在线书的部分搬运,如需进一步阅读,直接戳原网址。以及进一步可参见相关框架的源码和实现细节)
PS:最近才比较深入理解BP,欢迎批评指正。
![](https://i-blog.csdnimg.cn/blog_migrate/c0d407c2226176de059495c893f2cc1d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c0d407c2226176de059495c893f2cc1d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2108d590d7303d586fc5221a466f7736.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2108d590d7303d586fc5221a466f7736.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d4ffd2a06e6c99fac8f7e51c2467297b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d4ffd2a06e6c99fac8f7e51c2467297b.png)
定义损失函数(Cost)关于 l 层输出z的偏导为:
![](https://i-blog.csdnimg.cn/blog_migrate/6ccb6f3257ad29a3264b2fa1fdb434ce.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6ccb6f3257ad29a3264b2fa1fdb434ce.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2dfcf4506b08cbb56e7452e91ac69d1a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2dfcf4506b08cbb56e7452e91ac69d1a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/45cd6f008e5db53839fc1bb003a832fa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/45cd6f008e5db53839fc1bb003a832fa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/092e74c579bc3bd8b9d4709dc84b6a49.png)
![](https://i-blog.csdnimg.cn/blog_migrate/092e74c579bc3bd8b9d4709dc84b6a49.png)
![](https://i-blog.csdnimg.cn/blog_migrate/33fdcd3137f498aa2d65f0d6bd68c2cd.png)
![](https://i-blog.csdnimg.cn/blog_migrate/33fdcd3137f498aa2d65f0d6bd68c2cd.png)
另外贴一下BP算法和mini-batch SGD的算法:
BP:
![](https://i-blog.csdnimg.cn/blog_migrate/85b406f5921a2cd1ac6d961a6a5443e6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/85b406f5921a2cd1ac6d961a6a5443e6.png)
mini-batch SGD:
![](https://i-blog.csdnimg.cn/blog_migrate/3c37ca9a929bce960f4e3594e11e8924.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3c37ca9a929bce960f4e3594e11e8924.png)
BP算法最开始的发现是基于每个权重(weight)或者偏置(bias)的微小改变都能引起输出的改变,于是就进一步产生了用Cost对于这些参数的导数来更新w,b,进而达到改进输出的目的。
这里一种很直接的思路就是直接求Cost关于每个参数的导数(比如 [C(w+dw)-C(w)]/dw 这种数值微分),但是这种方法需要进行参数个数量次的Backward过程,计算代价很大。BP算法的提出就是为了优雅地解决这一问题,它只需要一次Backward就能将误差传到每一个可学的参数(w,b)。
(以上,该在线书的部分搬运,如需进一步阅读,直接戳原网址。以及进一步可参见相关框架的源码和实现细节)
PS:最近才比较深入理解BP,欢迎批评指正。
BP算法的思想是:将训练误差E看作以权重向量每个元素为变量的高维函数,通过不断更新权重,寻找训练误差的最低点,按误差函数梯度下降的方向更新权值。
BP算法的思想是:将训练误差E看作以权重向量每个元素为变量的高维函数,通过不断更新权重,寻找训练误差的最低点,按误差函数梯度下降的方向更新权值。
反向传播其主要目的是通过将输出误差反传,将误差分摊给各层所有单元,从而获得各层单元的误差信号,进而修正各单元的权值(其过程,是一个权值调整的过程)。忘记出处了 我是看到这句才突然清晰了许多。
反向传播
其主要目的是通过将输出误差反传,将误差分摊给各层所有单元,从而获得各层单元的误差信号,进而修正各单元的权值(其过程,是一个权值调整的过程)。
忘记出处了 我是看到这句才突然清晰了许多。
其主要目的是通过将输出误差反传,将误差分摊给各层所有单元,从而获得各层单元的误差信号,进而修正各单元的权值(其过程,是一个权值调整的过程)。
忘记出处了 我是看到这句才突然清晰了许多。
误差函数关于模型参数的偏导数,在神经网络里逆向逐一求解。wiki上有非常简练的推导。
误差函数关于模型参数的偏导数,在神经网络里逆向逐一求解。wiki上有非常简练的推导。
匿名用户
没有办法更直观了,除非你没有学过微积分想要理解一个算法,用1+1=2的方式去理解1+1,我想是不行的,希望对你有用
没有办法更直观了,除非你没有学过微积分
想要理解一个算法,用1+1=2的方式去理解1+1,我想是不行的,希望对你有用
想要理解一个算法,用1+1=2的方式去理解1+1,我想是不行的,希望对你有用