6.1 Introduction 简介
- 反向传播算法:一个有效率的计算梯度的方法
- 前提:
- 前馈网络的反向传播
- http://speech.ee.ntu.edu.tw/~tlkagk/courses/MLDS_2015_2/Lecture/DNN%20backprop.ecm.mp4/index.html
- 简单的版本:https://www.youtube.com/watch?v=ibJpTrp5mcE
- RNN的基于时间的反向传播算法:http://speech.ee.ntu.edu.tw/~tlkagk/courses/MLDS_2015_2/Lecture/RNN%20training%20(v6).ecm.mp4/index.html
- 前馈网络的反向传播
- 通过计算图来理解反向传播
- Tensorflow, Theano, CNTK, etc.
6.2 计算图 定义
所谓计算图,就是一种语言,这个语言是用来描述一个函数,我们知道neural network就是一个函数,所以我们需要描述函数的语言。其实graph有很多种定义方法,但是我们通常使用node来表示一个变量,他可以是一个scalar,vector甚至是tensor,这里的每一个edge代表了一个operation。
看图上的例子
那计算图要怎么去画呢?
这个图的好处就是,我们在这个图上算变量的梯度是很容易的。
在去根据这个图算变量的梯度之前,我们需要先了解一下链式法则:
那我们还拿刚才那个为例子,加入链式法则:
把每一个箭头的偏微分都算出来。
如果我们想同时和计算呢(在的情况下)?
如果同时算这两者的话,我们需要一个reverse mode(反向做法),我们刚才看的都是正向的做法,从
这样做的好处就是,如果今天是computational graph,你最终的函数的输出只有一个值,你又需要算大量的不同值的偏微分的时候,用reverse mode会比刚才的forward mode还要更有效率,而在做neural network的时候,我们需要的就是reverse mode。
那为什么呢?因为我们要做neural network的时候,我们需要计算偏微分的对象其实是cost function(loss function),我们要对cost function算偏微分,而cost function的输出就是一个scalar,所以如果你把cost function用computational graph来描述的话,他只有一个输出,那今天我们又要同时算这个network里面所有参数对cost function的偏微分,所以我们从root开始做reverse mode,对cost function算偏微分是比较有效率的。
那另外一个状况是有时候会有parameter sharing:
我们可能会有parameter sharing的状况,也就是同样的变量,他出现在这个graph多个地方。这个时候要怎么计算他的偏微分呢?
这件事情在neural network里面是常常的发生。比如,在CNN里面就有share variable,其实RNN他其实也是share variable,他把同一个function在整个RNN上反复的使用,他也是share variable。
有share variable要怎么去做呢?
举一个例子,假如有一个函数 ,这个式子如果我们用computational graph来描述的话,就是上面图上的样子。接下来计算 ,我们要把graph上的edge上的微分都算出来,我们需要把node上的看成是不同的来看待,就假设这些都是有下标的。
那算出了edge上的所有偏微分,那 的值是什么呢?我们把那三个,当成是不同的变量来看,那实际上 是什么呢?我们这里算出了三个偏微分,它的值并不是一样的,那么实际上 ,意思就是把那算个对的偏微分都加起来。所以今天要考虑share variable的case,我们就要把同样的参数,先当做不一样的参数来看,然后算完以后再加起来。
6.3 前馈网络的计算图
那接下来就说一说neural network的东西,上面讲的都是general的东西,那如果有一个fully connected feedforward network,那用computational graph来算他的微分的话,我们需要怎么去做呢?我们先复习一下,一般的讲法:
一般我们说要算微分就用backpropagation,这个backpropagation里面分成两个阶段,一个是forward pass,一个是back pass。
求算:
那怎么去求error signal(误差信号)呢?
补充一个我的知识盲点:在微积分里面,对多元函数的参数求∂偏导数,把求得的各个参数的偏导数以向量的形式写出来,就是梯度。
- 首先将原来的整个network进行逆转,那这个network的input就是对的偏导,这个network的input是一个vector,这个vector里面存放的是对的梯度;
- 把这个vector丢进一排的neural里面,这个一排的neural他们的激活函数并不是sigmoid,而是一排OPA(放大器),放大的倍数就是原来没有逆转时候的network的那个neural的激活函数的微分值,得到一组output,这个时候的output就是最后一层的error signal,也就是。
- 然后在把这组output乘上一组weight,这一组weight是原来layer L的那组matrix weight的transpose(在forward的时候乘上的是matrix weight [Z = WX+b],在backward乘上的就是weight的transpose)。然后丢到下一组的OPA里面,然后就可以算出error signal的值。
- 红色框框值和绿色框框值相乘就可以得到结果。
那接下来用computational graph来微分,当然在计算微分之前,先来看看network的computational graph,那他长什么样子呢?
那接下来我们要算gradient descent,也就是微分,那我们算微分的对象并不是y,其实是cost function。这儿有另外一个变量
那么,接下来,我们要计算
为了计算gradient,首先,我们把每个edge上的微分都算出来,然后用reverse mode逆向走回来,你就可以把所有的参数对c的偏微分都算出来。
接下来我们的问题就是我的和都是vector,那他是怎么去算微分的呢?
我们把vector对vector做微分其实就是jacobian matrix(雅可比行列式)。
我们现在就从这个地方一路往回走:
我们算
如果
因此可以求出:
再继续往回走:
因为是一个vector,也是一个vector,那么对的偏微分所生成的jacobian matrix是一个方阵(因为他们两个vector的维度一定是相等的)。 如果,他们之间没有关系就是。
如果今天用的不是sigmoid function使用的是softmax,那他还是diagonal matrix(对角阵)吗?
答案:不是了,因为在做softmax的时候,的每一个dimension都会影响到的每一个dimension,那就没有 微分 =的状况。
然后继续算下去,为了简单,下面把biases去掉:
我们把他们(和)的关系写出来,如下图左下所示,因此可以求出偏微分为。
然后我们算 对的jacobian matrix:
先假设
接下来:
然后就可以得到结果:
结果就是最左边的长度是 结果的长度1,最后一个matrix宽是结果的element的数目
好像用computational graph用reverse mode算所有参数的偏微分,感觉好像只有back pass没有forward pass。右边传统的讲法有forward pass和back pass。那右边那个forward pass在哪里?你还是需要forward pass,你想想看,我们要得到这些matrix的真正的值,我们需要是多少,需要知道节点的value是多少,所以你还是需要先算一个forward pass,把所有节点的值都算出来,你才能算出所有的edge上的偏微分,才能够把一路上的东西都算出来,所以你还是先需要forward pass才能够跑reverse mode,所以和右边那个是一样的。
你想要检查一下左边和右边是不是一样的,右边有transpose,左边没有transpose。为什么?我们算出对的偏微分以后还要和对的偏微分相乘。 是一个vector,也是一个vector,你把这两个vector相乘以后,要得到一个matrix,这个matrix的size和weight matrix的哪个size是一样的,这个时候你需要对backward pass得到的 先做transpose,才能和左边的乘在一起,所以做完transpose以后, 里面的transpose就不见了,左边和右边算出的结果会是一样的。
6.4 循环网络的计算图(Computational Graph for Recurrent Network)
前面说的是fully connected feedforward network,接下来要说Recurrent network,其实原理都是一样的:
- 画出computational graph;
- 把偏微分都算出来;
- 然后reverse mode跑一把。
先看一下Recurrent network function:
那如果我们把recurrent network转换为computational graph,他会长什么样子呢?
首先有一个input 与相乘得到(没有在式子中出现)。 这个只是一部分。
如果我们把recurrent network完整的画出来的话(简化):
这是一个时间点,在下一个时间点:
当RNN考虑的是total cost,所以你要把
接下来我们就需要把每一个edge上的偏微分都算出来:
我们从开始reverse mode