基于时间的反向传播算法BPTT(Backpropagation through time)
2017-11-29 19:49
633 查看
本文是读“Recurrent Neural Networks Tutorial, Part 3 – Backpropagation Through Time and Vanishing Gradients”的读书笔记,加入了自己的一些理解,有兴趣可以直接阅读原文。
其中x为输入,s为隐藏层状态,o为输出,按时间展开
为了与文献中的表示一致,我们用y^来代替o,则
st=tanh(Uxt+Wst−1)y^=softmat(Vst)
使用交叉熵(cross entropy)作为损失函数
Et(y,y^)=−ytlogy^E(y,y^)=∑tEt(yt,y^t)=−∑tytlogy^
我们使用链式法则来计算后向传播时的梯度,以网络的输出E3为例,
y^3=ez3∑ieziE3=−y3logy^3=−y3(z3−log∑iezi)z3=Vs3s3=tanh(Ux3+Ws2)
因此可以求V的梯度
∂E3∂V=∂E3∂z^3∂z3∂V=y3(y^3−1)∗s3
这里求导时将y^3带入消去了,求导更直观,这里给出的是标量形式,改成向量形式应该是y^−13,也就是输出概率矩阵中,对应结果的那个概率-1,其他不变,而输入y恰好可以认为是对应结果的概率是1,其他是0,因此原文中写作
∂E3∂V=(y^3−y3)⊗s3
相对V的梯度,因为st是W,U的函数,而且含有的st−1在 求导时,不能简单的认为是一个常数,因此在求导时,如果不加限制,需要对从t到0的所有状态进行回溯,在实际中一般按照场景和精度要求进行截断。
∂E3∂W=∂E3∂z^3∂z3∂s3∂s3∂sk∂sk∂W
其中s3对W的求导是一个分部求导
∂st∂W=(1−st)2(st−1+W∗∂st−1∂sW)
U的梯度类似
∂st∂U=(1−st)2(xt+W∗∂st−1∂sU)
[[a0∗b0a0∗b1...a0∗bN][a1∗b0a1∗b1...a1∗bN]...[aM∗b0aM∗b1...aM∗bN]]
结果是M*N维的
1. 算法介绍
这里引用原文中的网络结构图其中x为输入,s为隐藏层状态,o为输出,按时间展开
为了与文献中的表示一致,我们用y^来代替o,则
st=tanh(Uxt+Wst−1)y^=softmat(Vst)
使用交叉熵(cross entropy)作为损失函数
Et(y,y^)=−ytlogy^E(y,y^)=∑tEt(yt,y^t)=−∑tytlogy^
我们使用链式法则来计算后向传播时的梯度,以网络的输出E3为例,
y^3=ez3∑ieziE3=−y3logy^3=−y3(z3−log∑iezi)z3=Vs3s3=tanh(Ux3+Ws2)
因此可以求V的梯度
∂E3∂V=∂E3∂z^3∂z3∂V=y3(y^3−1)∗s3
这里求导时将y^3带入消去了,求导更直观,这里给出的是标量形式,改成向量形式应该是y^−13,也就是输出概率矩阵中,对应结果的那个概率-1,其他不变,而输入y恰好可以认为是对应结果的概率是1,其他是0,因此原文中写作
∂E3∂V=(y^3−y3)⊗s3
相对V的梯度,因为st是W,U的函数,而且含有的st−1在 求导时,不能简单的认为是一个常数,因此在求导时,如果不加限制,需要对从t到0的所有状态进行回溯,在实际中一般按照场景和精度要求进行截断。
∂E3∂W=∂E3∂z^3∂z3∂s3∂s3∂sk∂sk∂W
其中s3对W的求导是一个分部求导
∂st∂W=(1−st)2(st−1+W∗∂st−1∂sW)
U的梯度类似
∂st∂U=(1−st)2(xt+W∗∂st−1∂sU)
2. 代码分析
首先我们给出作者自己实现的完整的BPTT,再各部分分析def bptt(self, x, y): T = len(y) # Perform forward propagation o, s = self.forward_propagation(x) # We accumulate the gradients in these variables dLdU = np.zeros(self.U.shape) dLdV = np.zeros(self.V.shape) dLdW = np.zeros(self.W.shape) delta_o = o delta_o[np.arange(len(y)), y] -= 1. # For each output backwards... for t in np.arange(T)[::-1]: dLdV += np.outer(delta_o[t], s[t].T) # Initial delta calculation: dL/dz delta_t = self.V.T.dot(delta_o[t]) * (1 - (s[t] ** 2)) # Backpropagation through time (for at most self.bptt_truncate steps) for bptt_step in np.arange(max(0, t-self.bptt_truncate), t+1)[::-1]: # print "Backpropagation step t=%d bptt step=%d " % (t, bptt_step) # Add to gradients at each previous step dLdW += np.outer(delta_t, s[bptt_step-1]) dLdU[:,x[bptt_step]] += delta_t # Update delta for next step dL/dz at t-1 delta_t = self.W.T.dot(delta_t) * (1 - s[bptt_step-1] ** 2) return [dLdU, dLdV, dLdW]
2.1. 初始化
结合完整的代码,我们可知梯度的维度#100*8000 dLdU = np.zeros(self.U.shape) #8000*100 dLdV = np.zeros(self.V.shape) #100*100 dLdW = np.zeros(self.W.shape)
2.2. 公共部分
对照上面的理论可知,无论是V,还是U,W,都有∂E3∂z^3,这部分可以预先计算出来,也就是代码中的delta_o#o是forward的输出,T(句子的实际长度)*8000维,每一行是8000维的,就是词表中所有词作为输入x中每一个词的后一个词的概率 delta_o = o #[]中是索引操作,对y中的词对应的索引的概率-1 delta_o[np.arange(len(y)), y] -= 1.
2.3. V的梯度
s[t].T是取s[t]的转置,numpy.outer是将第一个参数和第二个参数中的所有元素分别按行展开,然后拿第一个参数中的数因此乘以第二个参数的每一行,例如a=[a0,a1,...,aM], b=[b0,b1,...,bN],则相乘后变成[[a0∗b0a0∗b1...a0∗bN][a1∗b0a1∗b1...a1∗bN]...[aM∗b0aM∗b1...aM∗bN]]
结果是M*N维的
#delta_o是1*8000维向量,s[t]是1*100的向量,转不转置对outer并没有什么区别,其实和delta_o[t].T * s[t]等价,*是矩阵相乘,结果是8000*100维的矩阵 dLdV += np.outer(delta_o[t], s[t].T)
2.4. W和U的梯度
对比W和U的梯度公式,我们可以看到,两者+号的第二部分前面的系数是一样的,也就是(1−st)2∗W,这部分可以存起来减少计算量,也就是代码中的delta_tdelta_t = self.V.T.dot(delta_o[t]) * (1 - (s[t] ** 2)) # Backpropagation through time (for at most self.bptt_truncate steps) #截断 for bptt_step in np.arange(max(0, t-self.bptt_truncate), t+1)[::-1]: # print "Backpropagation step t=%d bptt step=%d " % (t, bptt_step) # Add to gradients at each previous step #计算+号的第一部分,第二部分本次还没得到,下次累加进来 dLdW += np.outer(delta_t, s[bptt_step-1]) #x为单词的位置向量,与delta_t相乘相当于dLdU按x取索引(对应的词向量)直接与delta_t相加 dLdU[:,x[bptt_step]] += delta_t # Update delta for next step dL/dz at t-1 #更新第二部分系数 delta_t = self.W.T.dot(delta_t) * (1 - s[bptt_step-1] ** 2)
相关文章推荐
- 基于时间的反向传播算法BPTT(Back Propagation Trough Time)
- BPTT(BackPropagation Through Time)
- 循环神经网络教程3-BP算法和梯度消失问题, Part 3 – Backpropagation Through Time and Vanishing Gradients
- BackPropagation Through Time
- 吴恩达Deeplearning.ai 第五课 Sequence Model 第一周------Backpropagation through time
- 代码片段:基于 JDK 8 time包的时间工具类 TimeUtil
- 7.5 Point-in-Time (Incremental) Recovery Using the Binary Log 使用binay log 基于时间点恢复
- TOTP:Time-based One-time Password Algorithm(基于时间的一次性密码算法)
- 神经网络和深度学习(二)——BP(Backpropagation Algorithm, 反向传播算法)
- 基于 JDK 8 time包的时间工具类
- 基于时间的反向传播算法和梯度消失 -part3
- BP反向传播算法浅谈(Error Back-propagation)
- 神经网络二:浅谈反向传播算法(backpropagation algorithm)为什么会很快
- TOTP:Time-based One-time Password Algorithm(基于时间的一次性密码算法)
- 对反向传播算法(Back-Propagation)的推导与一点理解
- 9-2 backpropagation algorithm 反向传播算法
- SQL Server时间粒度系列----第6节基于当前日的小时数和分钟数与mysql unix_timestamp和from_unixtime的mssql实现
- BP反向传播算法是如何工作的How the backpropagation algorithm works
- 基于clock()和time()函数的时间复杂度计时
- Scripts:基于时间显示闪回日志中redo的脚本fdb_redo_time_matrix.sql