专栏名称: 待字闺中
深度分析大数据、深度学习、人工智能等技术,切中实际应用场景,为大家授业解惑。间或,也会介绍国内外相关领域有趣的面试题。
目录
相关文章推荐
中国能源报  ·  75年,何以破解“缺油少气”难题 ·  2 天前  
中国能源报  ·  75年,何以破解“缺油少气”难题 ·  2 天前  
OSC开源社区  ·  InnerSource Asia ... ·  5 天前  
分享迷  ·  全新的接口,以及全新的0.4.2版本 ·  1 周前  
分享迷  ·  全新的接口,以及全新的0.4.2版本 ·  1 周前  
51好读  ›  专栏  ›  待字闺中

神经网络的BP算法学习

待字闺中  · 公众号  · 程序员 科技自媒体  · 2016-09-23 02:25

正文

作者简介:周细洞,架构师,现在就职于国内某著名的P2P互联网金融公司,从事大数据和机器学习研究。待字闺中特约作者。也欢迎大家投稿。


首先用图来表达函数,对于以下的函数:



令:




则相应的图表示为:



 图-1


上图中,圆形框是函数表达式,边表示圆形框的输入和输出来源。将图r节点的输出记为r, 则r节点的输入为p节点和q节点的输出,记为 p,q。


那么如何求z(z节点的输出)关于图中任意节点输出的梯度呢?



图-2


对于任意的x节点,找到所有与x节点直接关联的节点p,q,x 只能通过p,q去影响z。那么z和x的关系可以表示如下z=z(p,q),p=p(x),q=q(x),根据复合函数求导法则:




这就是BP算法的核心公式。


在实际使用中,有前向和后向两个流程,以图-1为例:


在前向流程中,依次计算:





在后向计算过程中,计算过程如下:





可见当某一节点的后续节点都走完回传过程后,那么该节点的梯度就计算出来了,然后轮到该节点,直接做回传就可以了。


在BP过程中,最重要的事情就是维护梯度回传的先后顺序。在TensorFlow中,每个tensor就表示了一个函数节点,tensor之间的运算,例如mat、add这些都会生成新的tensor,这种关系最终都在记在graph中,在梯度求导的时候,根据图中节点的顺序,从后至前计算梯度,只要确保:回传某节点的梯度时,该节点的后续依赖节点已经回传完毕就行了。


需要注意的几个地方:


1)梯度的计算可能引起歧义,如下:


 

根据上面的求导法则




假设:


p=x*x,

q=p*x,

z=p+q,


显然z=x*x+(x*x)*x,则∂z/∂x实际为2*x+3*x*x。


在这个公式中(∂q/∂x)为q对x_2这个输入的导数,x_2的值正好为x,即(∂q/(∂(x_2)))=p=x*x。(∂z/∂p)是z关于p节点输出的导数,即(∂z/∂p=∂z/∂z*∂z/(∂(p_1))+∂z/∂q  ∂q/(∂(p_2)))=(1*1+1*x)=(1+x),则(∂z/∂x)=(1+x)*(2*x)+(1)*(x*x)=2*x+3*x*x。所以计算导数的时候一定要分清楚,是要对某节点的输入求导还是对某节点的输出求导。


为方便起见,在loss节点后增加一个节点C=loss,如下:

 


记(∂C/∂w)表示C关于w节点输出的导数,这是回传算法要求的。其他的,例如:(∂q/∂x)表示q关于x到q的输入端上的导数,这在建立节点的时候前向的时候就能算出来。


则上图的求导过程如下:




2)对于某些RNN,unroll之后,可能具有以下的形式,其求导过程如下:


 




3)上图中所有的节点是以标量为例的,实际上也可以为向量,特别注意下面两种向量的求导形式:


(a)矩阵形式

 





(b)点乘形式





有了上面的基础后,就可以看看几种常见的神经网络的推导


1)普通的神经网络





2)LSTM的BPTT推导,一个典型的LSTM示意图如下:

 

 

将其中的函数块都变为节点,一个典型的seq2seq网络就如下图所示:



 

依赖关系如下:

lstm_cell[t-1]->lstm_cell[t]->logits[t]->prob[t]

prob[0],…,prob[T-1]->loss


基本的前向过程如下:

对任意t:

几个控制门的输出:

c_hat=W_c x_(t-1)+U_c h_(t-1)+b_c

c=tanh(c_hat)

i_hat=W_i x_(t-1)+U_i h_(t-1)+b_i

i=sigmoid(i_hat)

f_hat=W_f x_(t-1)+U_f h_(t-1)+b_f

f=sigmoid(f_hat)

o_hat=W_o x_(t-1)+U_o h_(t-1)+b_o

o=sigmoid(o_hat)


状态S的更新:

S[t]=c⊙i+S[t-1]⊙f


输出H的计算:

H[t]=o⊙tan⁡h(S[t-1])


未归一化的概率计算:

logits[t]=W_p H[t]+b_p


归一化的概率计算:

prob[t]=softmax(logits[t])


损失函数的计算:

loss+=Y_t⊙(-log⁡(prob[t])


按照之前BP的法则,计算loss关于各个节点输出的梯度,如下:




其余节点的计算都很简单,就不列出计算公式了。BP的时候,需要从T步向第1步计算。具体的代码参见:


http://git.oschina.net/bamuyy/lstm/blob/master/lstm.py?dir=0&filepath=lstm.py&oid=7dfd64de7ca2ab53ae79008ac9bbc054dcba2f5d&sha=5fd268b98baf62fc4ec3ebd3cadcc130f85894e2



----- The End -----


大家可能还感兴趣:



谢谢。