这两天对RNN循环神经网络进行了学习,由一无所知到现在对什么是RNN以及它的前向传播和反向传播有了认识,尤其是BPTT算法的推导有些繁琐,但是推过一次后,对RNN反向传播求梯度的过程有了更清晰的认识。
下面是朴素的RNN循环神经网络图。(图1)
我在写博客前,自己先手写了一份推导过程。(图2)
为何BPTT更难?
因为多了状态之间的传递(即隐层单元之间的“交流”),根据前向传播算法,我们知道 s∗t=Wst−1+Uxt, 而 st−1=f(s∗t−1)=f(Wst−2+Uxt−1),这说明 st−1也是关于W的式子。
这样层层嵌套下去……就会追溯到s0。可以意识到我们对W、U的梯度求解是繁琐的,而这正是BPTT的难点所在。对于V的梯度求解,并没有受到状态之间传递的影响,因此和我们BP算法求解方式是一样的。
我们用∗表示element-wise, ×表示矩阵乘法。
我们采用交叉熵损失函数,即Lt=−(ytlog(ot)+(1−yt)log(1−ot))
我们定义隐藏层的**函数为sigmoid函数st=f(s∗t),输出层的**函数也为sigmoid函数 ot=g(o∗t)。f′=st∗(1−st),g′=ot∗(1−ot) 。具体求导读者自行证明。
由前向传播可知,ot=g(o∗t)=g(Vst)
那么∂Lt∂V=∂Lt∂ot∗∂ot∂o∗t⋅∂o∗t∂V=−(ytot+yt−1∂1−ot)∗ot∗(1−ot)⋅∂o∗t∂V=(ot−yt)×sTt
不同时刻的∂Lt∂V要相加,得到最后的∂L∂V。
由前向传播可知,对于时刻t而言,st−1也是关于W的式子,因此我们在求∂Lt∂W时,不能简单的将st−1视为常量,因此 ∂Lt∂W=∑tk=0∂Lt∂s∗k×sTk−1(注意,在我这里是把第一个时刻从0开始)。
∂Lt∂s∗t=∂Lt∂o∗t⋅∂o∗t∂s∗t=VT×(ot−yt)∗st∗(1−st)
∂Lt∂s∗k−1=∂Lt∂s∗k⋅∂s∗k∂sk−1∗∂sk−1∂s∗k−1=sk−1∗(1−sk−1)∗WT×∂Lt∂s∗k(k=1,2,3...t)
同理, ∂Lt∂U=∑tk=0∂Lt∂s∗k×xTk。
最后不同时刻的 ∂Lt∂U要相加,得到最终的 ∂L∂U=∑t=nt=0∂Lt∂U
最后不同时刻的 ∂Lt∂W要相加,得到最终的 ∂L∂W=∑t=nt=0∂Lt∂W
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:RNN循环神经网络里的BPTT算法 - Python技术站