Deep Learning基础--随时间反向传播 (BackPropagation Through Time,BPTT)推导
1. 随时间反向传播BPTT(BackPropagation Through Time, BPTT)
RNN(循环神经网络)是一种具有长时记忆能力的神经网络模型,被广泛用于序列标注问题。一个典型的RNN结构图如下所示:

从图中可以看到,一个RNN通常由三小层组成,分别是输入层、隐藏层和输出层。与一般的神经网络不同的是,RNN的隐藏层存在一条有向反馈边,正是这种反馈机制赋予了RNN记忆能力。要理解左边的图可能有点难度,我们将其展开成右边的这种更加直观的形式,其中RNN的每个神经元接受当前时刻的输入$x_t$以及上一时刻隐单元的输出$s_{t-1}$,计算出当前神经元的输入$s_t$。三个权重矩阵$U$, $V$和$W$就是要通过梯度下降来拟合的参数。整个优化过程叫做BPTT(BackPropagation Through Time, BPTT)。
形式化如下:
$$ { s }_{ t }=\tanh \left( U{ x }_{ t }+W{ s }_{ t-1 } \right) \\ { \hat { y } }_{ t }=softmax\left( V{ s }_{ t } \right) \tag{1}$$
同样地,定义交叉熵损失函数如下:
$$ { E }_{ t }\left( { y }_{ t },{ \hat { y } }_{ t } \right) =-{ y }_{ t }log{ \hat { y } }_{ t }\\ { E\left( y,\hat { y } \right) }=\sum _{ t }^{ }{ { E }_{ t }\left( { y }_{ t },{ \hat { y } }_{ t } \right) } \\ =-\sum _{ t }^{ }{ { y }_{ t }log{ \hat { y } }_{ t } } \tag{2}$$
下面我们将举个具体的例子。

我们的目标是通过梯度下降来拟合参数矩阵$U$, $V$和$W$。如同求损失时的加和,有$\frac { \partial E }{ \partial W } =\sum _{ t }^{ }{ \frac { \partial { E }_{ t } }{ \partial W } } $。
为了计算这些梯度,我们使用链式法则。我们将以$E_3$为例,做如下推导。
$$ \frac { \partial { E }_{ 3 } }{ \partial V } =\frac { \partial { E }_{ 3 } }{ \partial { \hat { y } }_{ 3 } } \frac { \partial { \hat { y } }_{ 3 } }{ \partial V } \\ =\frac { \partial { E }_{ 3 } }{ \partial { \hat { y } }_{ 3 } } \frac { \partial { \hat { y } }_{ 3 } }{ \partial { z }_{ 3 } } \frac { \partial { z }_{ 3 } }{ \partial V } \\ =\left( { \hat { y } }_{ 3 }-{ y }_{ 3 } \right) \otimes { s }_{ 3 } \tag{3}$$
在上面式子中,$z_3=V s_3$,$\otimes$表示两个向量的外积。对$V$的偏导是简单的,因为$t=3$时间步的对$V$的偏导只与${ \hat { y } }_{ 3 }$,$y_3$和$s_3$有关。但是,对于$\frac { \partial { E }_{ 3 } }{ \partial W }$就没有这么简单了,如图:

推导过程如下:
$$ \frac { \partial { E }_{ 3 } }{ \partial W } =\frac { \partial { E }_{ 3 } }{ \partial { \hat { y } }_{ 3 } } \frac { \partial { \hat { y } }_{ 3 } }{ \partial { s }_{ 3 } } \frac { \partial { s }_{ 3 } }{ \partial W } \\ =\sum _{ k=0 }^{ 3 }{ \frac { \partial { E }_{ 3 } }{ \partial { \hat { y } }_{ 3 } } \frac { \partial { \hat { y } }_{ 3 } }{ \partial { s }_{ 3 } } \frac { \partial { s }_{ 3 } }{ \partial { s }_{ k } } \frac { \partial { s }_{ k } }{ \partial W } } \tag{4} $$
上式中,我们可以看到,这与标准的BP算法并无太多不同,唯一的区别在于需要对各时间步求和。这也是标准RNN难以训练的原因:序列(句子)可能很长,可能是20个字或更多,因此需要反向传播多个层。在实践中,许多人将时间步进行截断来控制传播层数。
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. 梯度消失问题
标准RNN难以学习到文本的上下文依赖,例如“The man who wore a wig on his head went inside”,句子要表达的是带着假发的男人进去了而不是假发进去了,这一点对于标准RNN的训练很难。为了理解这个问题,我们先看看上面的式子:
$$ \frac { \partial { E }_{ 3 } }{ \partial W } =\sum _{ k=0 }^{ 3 }{ \frac { \partial { E }_{ 3 } }{ \partial { \hat { y } }_{ 3 } } \frac { \partial { \hat { y } }_{ 3 } }{ \partial { s }_{ 3 } } \frac { \partial { s }_{ 3 } }{ \partial { s }_{ k } } \frac { \partial { s }_{ k } }{ \partial W } } \tag{5}$$
注意,其中的$\frac { \partial { s }_{ 3 } }{ \partial { s }_{ k } } $仍然包含着链式法则,例如$\frac { \partial { s }_{ 3 } }{ \partial { s }_{ 1 } } =\frac { \partial { s }_{ 3 } }{ \partial { s }_{ 2 } } \frac { \partial { s }_{ 2 } }{ \partial { s }_{ 1 } } $。
所以上面的式子(5)可以重写为式子(6),即逐点导数的雅克比矩阵:
$$ \frac { \partial { E }_{ 3 } }{ \partial W } =\sum _{ k=0 }^{ 3 }{ \frac { \partial { E }_{ 3 } }{ \partial { \hat { y } }_{ 3 } } \frac { \partial { \hat { y } }_{ 3 } }{ \partial { s }_{ 3 } } \left( \prod _{ j=k+1 }^{ 3 }{ \frac { \partial { s }_{ j } }{ \partial { s }_{ j-1 } } } \right) \frac { \partial { s }_{ k } }{ \partial W } } \tag{6} $$
而tanh函数和其导数图像如下:

可见,tanh函数(sigmoid函数也不例外)的两端都有接近0的导数。当出现这种情况时,我们认为相应的神经元已经饱和。参数矩阵将以指数方式快速收敛到0,最终在几个时间步后完全消失。来自“遥远”的时间步的权重迅速为0,从而不会对现在的学习状态产生贡献:学不到远处上下文依赖。
很容易想象,根据我们的激活函数和网络参数,如果雅可比矩阵的值很大,将会产生梯度爆炸。首先,梯度爆炸是显而易见的,权重将渐变为NaN(不是数字),程序将崩溃。其次,将梯度剪切到预定义的阈值是一种非常简单有效的梯度爆炸解决方案。当然,梯度消失问题影响更加恶劣,因为要知道它们何时发生或如何处理它们并不简单。
目前,已经有几种方法可以解决梯度消失问题。正确初始化$W$矩阵可以减少消失梯度的影响。正规化也是如此。更优选的解决方案是使用Relu代替tanh或S形激活函数。ReLU导数是0或1的常数,因此不太可能遇到梯度消失。更流行的解决方案是使用长短期记忆单元(LSTM)或门控循环单元(GRU)架构。LSTM最初是在1997年提出的,也是今天NLP中使用最广泛的模型。GRU,最初于2014年提出,是LSTM的简化版本。这两种RNN架构都明确地设计用于处理梯度消失并有效地学习远程依赖性。
参考英文博客:http://www.wildml.com/2015/10/recurrent-neural-networks-tutorial-part-3-backpropagation-through-time-and-vanishing-gradients/
Deep Learning基础--随时间反向传播 (BackPropagation Through Time,BPTT)推导的更多相关文章
- Deep Learning基础--CNN的反向求导及练习
前言: CNN作为DL中最成功的模型之一,有必要对其更进一步研究它.虽然在前面的博文Stacked CNN简单介绍中有大概介绍过CNN的使用,不过那是有个前提的:CNN中的参数必须已提前学习好.而本文 ...
- (3)Deep Learning之神经网络和反向传播算法
往期回顾 在上一篇文章中,我们已经掌握了机器学习的基本套路,对模型.目标函数.优化算法这些概念有了一定程度的理解,而且已经会训练单个的感知器或者线性单元了.在这篇文章中,我们将把这些单独的单元按照一定 ...
- Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现(转)
Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现 zouxy09@qq.com http://blog.csdn.net/zouxy09 自己平时看了一些论文, ...
- Deep Learning基础--参数优化方法
1. 深度学习流程简介 1)一次性设置(One time setup) -激活函数(Activation functions) - 数据预处理(Data Preprocessing) ...
- 反向传播BackPropagation
http://www.cnblogs.com/charlotte77/p/5629865.html http://www.cnblogs.com/daniel-D/archive/2013/06/03 ...
- Deep Learning基础--理解LSTM/RNN中的Attention机制
导读 目前采用编码器-解码器 (Encode-Decode) 结构的模型非常热门,是因为它在许多领域较其他的传统模型方法都取得了更好的结果.这种结构的模型通常将输入序列编码成一个固定长度的向量表示,对 ...
- Deep Learning基础--Softmax求导过程
一.softmax函数 softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类! 假设我们有一个数组,V,Vi表示V中的第i个元素,那么这个 ...
- 反向传播 Backpropagation
前向计算:没啥好说的,一层一层套着算就完事了 y = f( ... f( Wlayer2T f( Wlayer1Tx ) ) ) 反向求导:链式法则 单独看一个神经元的计算,z (就是logit)对 ...
- Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现
https://blog.csdn.net/zouxy09/article/details/9993371 自己平时看了一些论文,但老感觉看完过后就会慢慢的淡忘,某一天重新拾起来的时候又好像没有看过一 ...
随机推荐
- 【bzoj1004】[HNOI2008]Cards Burnside引理+背包dp
题目描述 用三种颜色染一个长度为 $n=Sr+Sb+Sg$ 序列,要求三种颜色分别有 $Sr,Sb,Sg$ 个.给出 $m$ 个置换,保证这 $m$ 个置换和置换 ${1,2,3,...,n\choo ...
- 【bzoj4425】[Nwerc2015]Assigning Workstations分配工作站 贪心+堆
题目描述 佩内洛普是新建立的超级计算机的管理员中的一员. 她的工作是分配工作站给到这里来运行他们的计算研究任务的研究人员. 佩内洛普非常懒惰,不喜欢为到达的研究者们解锁机器. 她可以从在她的办公桌远程 ...
- [区分] 1.计算机网络/internet(互联网) 2.Internet(因特网) 3.www/web(万维网)
internet(互联网或互连网)是一个通用名词,泛指由多个计算机网络互联而成的虚拟网络.Inernet(因特网)是一个专用名词,指当前全球最大的.开放的.由众多网络相互连接而成的特定的计算机网络,它 ...
- 【转】NHibernate主键类型介绍
转自:http://blog.163.com/wzx_dd/blog/static/1942850722012828934553/ 最近整合了一下框架,用SSH搭建了一个框架,但是在整合好之后,启动t ...
- elasticsearch 第二篇(配置篇)
配置 在es启动之前可以通过设置启动命令行启动参数.环境变量.文件等方式优化和配置es进行参数 环境变量 名称 示例 说明 ES_MIN_MEM 256M 用于配置java进程分配的最小内存 ES_M ...
- spark(四)
一. spark 2 版本 相对于以前版本的变化 spark core : Accumulators (累加器):性能更好,页面上也可以看到累加器的信息 spark sql: 1. 2.DataS ...
- jq从数组中删除指定元素(根据自定义条件) 超好用的 $.grep() 方法
转: jQuery.grep() 什么是jQuery.grep()? jQuery.grep()是一个查找满足过滤函数的数组元素的函数.原始数组不受影响,返回值为数组. 用法介绍: 写法: jQuer ...
- ibatis中:org.springframework.jdbc.UncategorizedSQLException:异常
SQL 查询语句异常,可能是你的查询语句写错了,或者是你的映射的类和或数据中与表不对应,检查你的映射配置文件.
- 使用gulp进行css、js压缩
var gulp = require('gulp'); var cleanCSS = require('gulp-clean-css'); var concatCss = require('gulp- ...
- Java设计模式の模版方法模式
概述 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的 ...