计算图(Computational Graph)笔记-BPTT

来源:互联网 发布:会计在职研究生 网络 编辑:程序博客网 时间:2024/06/06 17:38

计算图(Computational Graph)笔记

最近在学习Tensorflow,而Tensorflow的写法和一般的Python好像不太一样,不是很容易上手。后来看到Tensorflow是基于Computational Graph,那么就先来学习一下,参考的资料A Primer on Neural Network Models for Natural Language Processing
目录如下

  • 计算图Computational Graph笔记
    • 什么是计算图Computational Graph
      • 一些表示
      • Forward
      • Backward
    • 例子
      • Backpropagation Through Time BPTT

什么是计算图(Computational Graph)

简单来说就是,就是一个有向图,

计算图范例

上图来源是 这样子的图就代表(ab+1)(ab+2)
图的来源是A Primer on Neural Network Models for Natural Language Processing

一些表示

为了清楚期间,用圆来表示运算符号(tensorflow中的各种op,加减乘除,sigmoid…),用无色的长方形表示输入(tensorflow中的placeholder),用有颜色的长方形表示变量(tensorflow中的Variable)
例如:
这里写图片描述
要说一下的是,这边图上是看不出来node_1node_2 具体的运算是什么(由于空间问题,我就定义在外边了),定义如下:

node_1=Wxnode_2=node_1+bnode_3=[node_2y]2

此外,元素 A 指向元素 B 就说明 AB 的参数(argument),用符号表示就是

Aπ1(B)

其中 π1(B) 表示 B 的所有arguments

Forward

非常简单,就是把手头有的资料yx 就是把所有的leaves的值一层层往上根据各个node的定义去计算就好了.

Backward

BP的部分也很简单,第一步是将上面那种图中各个node对于他的参数的偏微分。论文上写起来大概就是这样

node_ieeπ1(node_i)

(当然关于x关于y的不必求了即关于placeholder的不用求),得到下图:
这里写图片描述

第二步是找到所有从你希望优化的node你希望调整的参数的路径,然后每一条路径上的偏微分乘在一起,所有路径加在一起。
举个例子假如我们的目标是让node_3 最小,并且我们希望调整参数W 来达到这个目的,怎么办呢?首先我们算出所有(这种情况显然b的就不用,简单起见就说所有的)node对于他们的参数的偏微分,如上图表示。然后对于W ,找到所有从node_3W 的路径,(这边只有一条),如下

node_3node_2node_1W

再将一条路径上的偏微分乘在一起:
node_3W=node_3node_2node_2node_1node_1W

在上面的例子中,
node_3node_2=2(node_2y)

node_2node_1=1

node_2W=x

所以
node_3W=2(node_2y)x

注意,这边node_2 在forward的时候已经算过了,不必再算一次。

由于这边的例子非常简单,其实就是非常基础的chain rule的应用,实在看不到这样做有什么好处显得多此一举,那么不妨看看下面的例子吧

例子

Backpropagation Through Time (BPTT)

前面的例子在一般的DNN上已经非常清楚了,无非就是图大一点,你要做的就是把图画出来,定义清楚需要的运算,然后算清楚每一个元素对他的所有参数的偏微分,然后就OK了。

但是在我学习的过程中,最头疼的情况是RNN,由于时间的关系,RNN并不都是一次输入一次输出这样的求解gradient,而是使用 unfold 这个过程:如果不用图而用纯粹的数学表达式的推导对我来说有点吓人,而且看到最后的求导公式比较难有直觉,那么我们不妨来看看怎么用computational graph来轻易解决BPTT的吧。

(这边假设读者已经知道RNN和unfold是在做啥啦)

下面是例子,下图是forward的图

这里写图片描述

简单来说就是在t=1input(t=1) 喂给网络,然后算算算得到node_3 这个值,戒指吧node_1 得到的结果当作参数传给下一期的node_1 这边简单表示成 node_1(t=2) (图上依旧是node_1)而图中各个node 的输入和输出的关系如下所示:

对于node_1,输入是 W_h , h , W_i 以及 input

node_1=W_hh+W_iinput  node_1W_h=h,node_1W_i=input,node_1h=W_h

对于node_2,输入是 node_1
node_2=sigmoid(node_1)  node_2node_1=node_1(1node_1)

对于node_3,输入是 ansnode_2
node_3=[node_2ans]2  node_3node_2=2(node_22)

此外,图中表示 h(t=2)=node_1(t=1)

那根据前面讲的内容,我们可以得到下面这张backward的图

这里写图片描述

这边所有诸如(t=1) 这样的只是为了告诉我们当在前面求导结果需要input 或者 ans 的时候选择哪一个时间点的数据,例如node_3(t=2) 的输出就是[node_2(t=2)ans(t=2)]2
有了上面这张backward的图,我们就可以很轻易的计算出此时W_hW_i 的梯度啦!
我这边写一个W_h,为了节省空间,将t=1 用下标表示, 即node_1(t=1) 就相当于 node_11

node_31node_21node_21node_11node_11W_h+node_32node_22node_22node_12node_12node_11node_11W_h

接下来将前面的每个node 的梯度代入上式即可。举个例子,
node_12node_11=node_12h2=W_h

其他的就很简单啦!