《吴恩达深度学习》深度学习笔记014_序列模型(Sequence Models)

http://www.ai-start.com/dl2017/html/lesson5-week1.html

序列模型(Sequence Models)

为什么选择序列模型?(Why Sequence Models?)

数学符号(Notation)

在这里插入图片描述
这个输入数据是9个单词组成的序列,所以最终我们会有9个特征集和来表示这9个单词,并按序列中的位置进行索引, x < 1 > x^{<1>} x<1> x < 2 > x^{<2>} x<2> x < 3 > x^{<3>} x<3>等等一直到 x < 9 > x^{<9>} x<9>来索引不同的位置,我将用 x x^{} x来索引这个序列的中间位置。 t t t意味着它们是时序序列,但不论是否是时序序列,我们都将用 t t t来索引序列中的位置。

输出数据也是一样,我们还是用 y < 1 > y^{<1>} y<1> y < 2 > y^{<2>} y<2> y < 3 > y^{<3>} y<3>等等一直到 y < 9 > y^{<9>} y<9>来表示输出数据。同时我们用 T x T_{x} Tx来表示输入序列的长度,这个例子中输入是9个单词,所以 T x = 9 T_{x}= 9 Tx=9。我们用 T y T_{y} Ty来表示输出序列的长度。在这个例子里 T x = T y T_{x} =T_{y} Tx=Ty,上个视频里你知道 T x T_{x} Tx T y T_{y} Ty可以有不同的值。

你应该记得我们之前用的符号,我们用 x ( i ) x^{(i)} x(i)来表示第 i i i个训练样本,所以为了指代第 t t t个元素,或者说是训练样本i的序列中第 t t t个元素用 x ( i ) x^{\left(i \right) } x(i)这个符号来表示。如果 T x T_{x} Tx是序列长度,那么你的训练集里不同的训练样本就会有不同的长度,所以 T x ( i ) T_{x}^{(i)} Tx(i)就代表第 i i i个训练样本的输入序列长度。同样 y ( i ) < t > y^{\left( i \right) < t>} y(i)<t>代表第 i i i个训练样本中第 t t t个元素, T y ( i ) T_{y}^{(i)} Ty(i)就是第 i i i个训练样本的输出序列的长度。

所以在这个例子中, T x ( i ) = 9 T_{x}^{(i)}=9 Tx(i)=9,但如果另一个样本是由15个单词组成的句子,那么对于这个训练样本, T x ( i ) = 15 T_{x}^{(i)}=15 Tx(i)=15

既然我们这个例子是NLP,也就是自然语言处理,这是我们初次涉足自然语言处理,一件我们需要事先决定的事是怎样表示一个序列里单独的单词,你会怎样表示像Harry这样的单词, x < 1 > x^{<1>} x<1>实际应该是什么?

接下来我们讨论一下怎样表示一个句子里单个的词。想要表示一个句子里的单词,第一件事是做一张词表,有时也称为词典,意思是列一列你的表示方法中用到的单词。这个词表(下图所示)中的第一个词是a,也就是说词典中的第一个单词是a,第二个单词是Aaron,然后更下面一些是单词and,再后面你会找到Harry,然后找到Potter,这样一直到最后,词典里最后一个单词可能是Zulu。
在这里插入图片描述
因此a是第一个单词,Aaron是第二个单词,在这个词典里,and出现在367这个位置上,Harry是在4075这个位置,Potter在6830,词典里的最后一个单词Zulu可能是第10,000个单词。所以在这个例子中我用了10,000个单词大小的词典,这对现代自然语言处理应用来说太小了。对于商业应用来说,或者对于一般规模的商业应用来说30,000到50,000词大小的词典比较常见,但是100,000词的也不是没有,而且有些大型互联网公司会用百万词,甚至更大的词典。许多商业应用用的词典可能是30,000词,也可能是50,000词。不过我将用10,000词大小的词典做说明,因为这是一个很好用的整数。

如果你选定了10,000词的词典,构建这个词典的一个方法是遍历你的训练集,并且找到前10,000个常用词,你也可以去浏览一些网络词典,它能告诉你英语里最常用的10,000个单词,接下来你可以用one-hot表示法来表示词典里的每个单词。
在这里插入图片描述
举个例子,在这里 x < 1 > x^{<1>} x<1>表示Harry这个单词,它就是一个第4075行是1,其余值都是0的向量(上图编号1所示),因为那是Harry在这个词典里的位置。

同样 x < 2 > x^{<2>} x<2>是个第6830行是1,其余位置都是0的向量(上图编号2所示)。

and在词典里排第367,所以 x < 3 > x^{<3>} x<3>就是第367行是1,其余值都是0的向量(上图编号3所示)。如果你的词典大小是10,000的话,那么这里的每个向量都是10,000维的。

因为a是字典第一个单词, x < 7 > x^{<7>} x<7>对应a,那么这个向量的第一个位置为1,其余位置都是0的向量(上图编号4所示)。

所以这种表示方法中, x x^{} x指代句子里的任意词,它就是个one-hot向量,因为它只有一个值是1,其余值都是0,所以你会有9个one-hot向量来表示这个句中的9个单词,目的是用这样的表示方式表示 X X X,用序列模型在 X X X和目标输出 Y Y Y之间学习建立一个映射。我会把它当作监督学习的问题,我确信会给定带有 ( x , y ) (x,y) (xy)标签的数据。

那么还剩下最后一件事,我们将在之后的视频讨论,如果你遇到了一个不在你词表中的单词,答案就是创建一个新的标记,也就是一个叫做Unknow Word的伪造单词,用作为标记,来表示不在词表中的单词,我们之后会讨论更多有关这个的内容。

循环神经网络模型(Recurrent Neural Network Model)

在这里插入图片描述
要开始整个流程,在零时刻需要构造一个激活值 a < 0 > a^{<0>} a<0>,这通常是零向量。有些研究人员会随机用其他方法初始化 a < 0 > a^{<0>} a<0>,不过使用零向量作为零时刻的伪激活值是最常见的选择,因此我们把它输入神经网络。

在一些研究论文中或是一些书中你会看到这类神经网络,用这样的图形来表示(上图编号2所示),在每一个时间步中,你输入 x x^{} x然后输出 y y^{} y。然后为了表示循环连接有时人们会像这样画个圈,表示输回网络层,有时他们会画一个黑色方块,来表示在这个黑色方块处会延迟一个时间步。我个人认为这些循环图很难理解,所以在本次课程中,我画图更倾向于使用左边这种分布画法(上图编号1所示)。不过如果你在教材中或是研究论文中看到了右边这种图表的画法(上图编号2所示),它可以在心中将这图展开成左图那样。

循环神经网络是从左向右扫描数据,同时每个时间步的参数也是共享的,所以下页幻灯片中我们会详细讲述它的一套参数,我们用 W ax W_{\text{ax}} Wax来表示管理着从 x < 1 > x^{<1>} x<1>到隐藏层的连接的一系列参数,每个时间步使用的都是相同的参数 W ax W_{\text{ax}} Wax。而激活值也就是水平联系是由参数 W a a W_{aa} Waa决定的,同时每一个时间步都使用相同的参数 W a a W_{aa} Waa,同样的输出结果由 W ya W_{\text{ya}} Wya决定。下图详细讲述这些参数是如何起作用。

在这里插入图片描述
在这个循环神经网络中,它的意思是在预测 y ^ < 3 > {\hat{y}}^{< 3 >} y^<3>时,不仅要使用 x < 3 > x^{<3>} x<3>的信息,还要使用来自 x < 1 > x^{<1>} x<1> x < 2 > x^{<2>} x<2>的信息,因为来自 x < 1 > x^{<1>} x<1>的信息可以通过这样的路径(上图编号1所示的路径)来帮助预测 y ^ < 3 > {\hat{y}}^{<3>} y^<3>。这个循环神经网络的一个缺点就是它只使用了这个序列中之前的信息来做出预测,尤其当预测 y ^ < 3 > {\hat{y}}^{<3>} y^<3>时,它没有用到 x < 4 > x^{<4>} x<4> x < 5 > x^{<5>} x<5> x < 6 > x^{<6>} x<6>等等的信息。所以这就有一个问题,因为如果给定了这个句子,“Teddy Roosevelt was a great President.”,为了判断Teddy是否是人名的一部分,仅仅知道句中前两个词是完全不够的,还需要知道句中后部分的信息,这也是十分有用的,因为句子也可能是这样的,“Teddy bears are on sale!”。因此如果只给定前三个单词,是不可能确切地知道Teddy是否是人名的一部分,第一个例子是人名,第二个例子就不是,所以你不可能只看前三个单词就能分辨出其中的区别。

所以这样特定的神经网络结构的一个限制是它在某一时刻的预测仅使用了从序列之前的输入信息并没有使用序列中后部分的信息,我们会在之后的双向循环神经网络(BRNN)的视频中处理这个问题。但对于现在,这个更简单的单向神经网络结构就够我们来解释关键概念了,之后只要在此基础上作出修改就能同时使用序列中前面和后面的信息来预测 y ^ < 3 > {\hat{y}}^{<3>} y^<3>,不过我们会在之后的视频讲述这些内容,接下来我们具体地写出这个神经网络计算了些什么。
在这里插入图片描述
这里是一张清理后的神经网络示意图,和我之前提及的一样,一般开始先输入 a < 0 > a^{<0>} a<0>,它是一个零向量。接着就是前向传播过程,先计算激活值 a < 1 > a^{<1>} a<1>,然后再计算 y < 1 > y^{<1>} y<1>

a < 1 > = g 1 ( W a a a < 0 > + W a x x < 1 > + b a ) a^{<1>} = g_{1}(W_{{aa}}a^{< 0 >} + W_{{ax}}x^{< 1 >} + b_{a}) a<1>=g1(Waaa<0>+Waxx<1>+ba)

y ^ < 1 > = g 2 ( W y a a < 1 > + b y ) \hat y^{< 1 >} = g_{2}(W_{{ya}}a^{< 1 >} + b_{y}) y^<1>=g2(Wyaa<1>+by)

我将用这样的符号约定来表示这些矩阵下标,举个例子 W ax W_{\text{ax}} Wax,第二个下标意味着 W ax W_{\text{ax}} Wax要乘以某个 x x x类型的量,然后第一个下标 a a a表示它是用来计算某个 a a a类型的变量。同样的,可以看出这里的 W ya W_{\text{ya}} Wya乘上了某个 a a a类型的量,用来计算出某个 y ^ \hat {y} y^类型的量。

循环神经网络用的激活函数经常是tanh,不过有时候也会用ReLU,但是tanh是更通常的选择,我们有其他方法来避免梯度消失问题,我们将在之后进行讲述。选用哪个激活函数是取决于你的输出 y y y,如果它是一个二分问题,那么我猜你会用sigmoid函数作为激活函数,如果是 k k k类别分类问题的话,那么可以选用softmax作为激活函数。不过这里激活函数的类型取决于你有什么样类型的输出 y y y,对于命名实体识别来说 y y y只可能是0或者1,那我猜这里第二个激活函数 g g g可以是sigmoid激活函数。

更一般的情况下,在 t t t时刻,

a < t > = g 1 ( W a a a < t − 1 > + W a x x < t > + b a ) a^{< t >} = g_{1}(W_{aa}a^{< t - 1 >} + W_{ax}x^{< t >} + b_{a}) a<t>=g1(Waaa<t1>+Waxx<t>+ba)

y ^ < t > = g 2 ( W y a a < t > + b y ) \hat y^{< t >} = g_{2}(W_{{ya}}a^{< t >} + b_{y}) y^<t>=g2(Wyaa<t>+by)

所以这些等式定义了神经网络的前向传播,你可以从零向量 a < 0 > a^{<0>} a<0>开始,然后用 a < 0 > a^{<0>} a<0> x < 1 > x^{<1>} x<1>来计算出 a < 1 > a^{<1>} a<1> y ^ < 1 > \hat y^{<1>} y^<1>,然后用 x < 2 > x^{<2>} x<2> a < 1 > a^{<1>} a<1>一起算出 a < 2 > a^{<2>} a<2> y ^ < 2 > \hat y^{<2>} y^<2>等等,像图中这样,从左到右完成前向传播。

现在为了帮我们建立更复杂的神经网络,我实际要将这个符号简化一下,我在下一张幻灯片里复制了这两个等式(上图编号1所示的两个等式)。
在这里插入图片描述
接下来为了简化这些符号,我要将这部分( W aa a < t − 1 > + W ax x W_{\text{aa}}a^{<t -1>} +W_{\text{ax}}x^{} Waaa<t1>+Waxx)(上图编号1所示)以更简单的形式写出来,我把它写做 a = g ( W a [ a < t − 1 > , x ] + b a ) a^{} =g(W_{a}\left\lbrack a^{< t-1 >},x^{} \right\rbrack +b_{a}) a=g(Wa[a<t1>,x]+ba)(上图编号2所示),那么左右两边划线部分应该是等价的。所以我们定义 W a W_{a} Wa的方式是将矩阵 W a a W_{aa} Waa和矩阵 W a x W_{{ax}} Wax水平并列放置, [ W a a ⋮ W a x ] = W a [ {{W}{aa}}\vdots {{W}{ax}}]=W_{a} [WaaWax]=Wa(上图编号3所示)。举个例子,如果 a a a是100维的,然后延续之前的例子, x x x是10,000维的,那么 W a a W_{aa} Waa就是个 ( 100 , 100 ) (100,100) 100100维的矩阵, W a x W_{ax} Wax就是个 ( 100 , 10 , 000 ) (100,10,000) 10010,000维的矩阵,因此如果将这两个矩阵堆起来, W a W_{a} Wa就会是个 ( 100 , 10 , 100 ) (100,10,100) 10010,100维的矩阵。

用这个符号( [ a < t − 1 > , x < t > ] \left\lbrack a^{< t - 1 >},x^{< t >}\right\rbrack [a<t1>,x<t>])的意思是将这两个向量堆在一起,我会用这个符号表示,即KaTeX parse error: Expected & or \\ or \cr or \end at end of input: … \\end{bmatrix}(上图编号4所示),最终这就是个10,100维的向量。你可以自己检查一下,用这个矩阵乘以这个向量,刚好能够得到原来的量,因为此时,矩阵 [ W a a ⋮ W a x ] [ {{W}{aa}}\vdots {{W}{ax}}] [WaaWax]乘以 [ a < t − 1 >   x < t >   ] \begin{bmatrix} a^{< t - 1 >} \ x^{< t >} \ \end{bmatrix} [a<t1> x<t> ],刚好等于 W a a a + W a x x W_{{aa}}a^{} + W_{{ax}}x^{} Waaa+Waxx,刚好等于之前的这个结论(上图编号5所示)。这种记法的好处是我们可以不使用两个参数矩阵 W a a W_{{aa}} Waa W a x W_{{ax}} Wax,而是将其压缩成一个参数矩阵 W a W_{a} Wa,所以当我们建立更复杂模型时这就能够简化我们要用到的符号。

同样对于这个例子( y ^ = g ( W y a a + b y ) \hat y^{} = g(W_{ya}a^{} +b_{y}) y^=g(Wyaa+by)),我会用更简单的方式重写, y ^ < t > = g ( W y a < t > + b y ) \hat y^{< t >} = g(W_{y}a^{< t >} +b_{y}) y^<t>=g(Wya<t>+by)(上图编号6所示)。现在 W y W_{y} Wy b y b_{y} by符号仅有一个下标,它表示在计算时会输出什么类型的量,所以 W y W_{y} Wy就表明它是计算 y y y类型的量的权重矩阵,而上面的 W a W_{a} Wa b a b_{a} ba则表示这些参数是用来计算 a a a类型或者说是激活值的。

RNN前向传播示意图:
在这里插入图片描述

通过时间的反向传播(Backpropagation through time)

在这里插入图片描述
在之前你已经见过对于前向传播(上图蓝色箭头所指方向)怎样在神经网络中从左到右地计算这些激活项,直到输出所有地预测结果。而对于反向传播,我想你已经猜到了,反向传播地计算方向(上图红色箭头所指方向)与前向传播基本上是相反的。
在这里插入图片描述
我们来分析一下前向传播的计算,现在你有一个输入序列, x < 1 > x^{<1>} x<1> x < 2 > x^{<2>} x<2> x < 3 > x^{<3>} x<3>一直到 x < T x > x^{< T_{x} >} x<Tx>,然后用 x < 1 > x^{<1>} x<1>还有 a < 0 > a^{<0>} a<0>计算出时间步1的激活项,再用 x < 2 > x^{<2>} x<2> a < 1 > a^{<1>} a<1>计算出 a < 2 > a^{<2>} a<2>,然后计算 a < 3 > a^{<3>} a<3>等等,一直到 a < T x > a^{< T_{x} >} a<Tx>

为了真正计算出 a < 1 > a^{<1>} a<1>,你还需要一些参数, W a W_{a} Wa b a b_{a} ba,用它们来计算出 a < 1 > a^{<1>} a<1>。这些参数在之后的每一个时间步都会被用到,于是继续用这些参数计算 a < 2 > a^{<2>} a<2> a < 3 > a^{<3>} a<3>等等,所有的这些激活项都要取决于参数 W a W_{a} Wa b a b_{a} ba。有了 a < 1 > a^{<1>} a<1>,神经网络就可以计算第一个预测值 y ^ < 1 > \hat y^{<1>} y^<1>,接着到下一个时间步,继续计算出 y ^ < 2 > \hat y^{<2>} y^<2> y ^ < 3 > \hat y^{<3>} y^<3>,等等,一直到 y ^ < T y > \hat y^{<T_{y}>} y^<Ty>。为了计算出 y ^ {\hat{y}} y^,需要参数 W y W_{y} Wy b y b_{y} by,它们将被用于所有这些节点。
在这里插入图片描述
然后为了计算反向传播,你还需要一个损失函数。我们先定义一个元素损失函数(上图编号1所示)

L ( y ^ , y ) = − y log ⁡ y ^ − ( 1 − y ) l o g ( 1 − y ^ ) L^{}( \hat y^{},y^{}) = - y^{}\log\hat y^{}-( 1- y^{})log(1-\hat y^{}) L(y^,y)=ylogy^(1y)log(1y^)

它对应的是序列中一个具体的词,如果它是某个人的名字,那么 y y^{} y的值就是1,然后神经网络将输出这个词是名字的概率值,比如0.1。我将它定义为标准逻辑回归损失函数,也叫交叉熵损失函数(Cross Entropy Loss),它和之前我们在二分类问题中看到的公式很像。所以这是关于单个位置上或者说某个时间步 t t t上某个单词的预测值的损失函数。

现在我们来定义整个序列的损失函数,将 L L L定义为(上图编号2所示)

L ( y ^ , y ) =   ∑ t = 1 T x L < t > ( y ^ < t > , y < t > ) L(\hat y,y) = \ \sum_{t = 1}^{T_{x}}{L^{< t >}(\hat y^{< t >},y^{< t >})} L(y^,y)= t=1TxL<t>(y^<t>,y<t>)

在这个计算图中,通过 y ^ < 1 > \hat y^{<1>} y^<1>可以计算对应的损失函数,于是计算出第一个时间步的损失函数(上图编号3所示),然后计算出第二个时间步的损失函数,然后是第三个时间步,一直到最后一个时间步,最后为了计算出总体损失函数,我们要把它们都加起来,通过下面的等式(上图编号2所示的等式)计算出最后的 L L L(上图编号4所示),也就是把每个单独时间步的损失函数都加起来。

这就是完整的计算图,在之前的例子中,你已经见过反向传播,所以你应该能够想得到反向传播算法需要在相反的方向上进行计算和传递信息,最终你做的就是把前向传播的箭头都反过来,在这之后你就可以计算出所有合适的量,然后你就可以通过导数相关的参数,用梯度下降法来更新参数。

在这个反向传播的过程中,最重要的信息传递或者说最重要的递归运算就是这个从右到左的运算,这也就是为什么这个算法有一个很别致的名字,叫做**“通过(穿越)时间反向传播**(backpropagation through time)”。取这个名字的原因是对于前向传播,你需要从左到右进行计算,在这个过程中,时刻 t t t不断增加。而对于反向传播,你需要从右到左进行计算,就像时间倒流。“通过时间反向传播”,就像穿越时光,这种说法听起来就像是你需要一台时光机来实现这个算法一样。

RNN反向传播示意图:
在这里插入图片描述

不同类型的循环神经网络(Different types of RNNs)

在这里插入图片描述
为了完整性,还要补充一个“一对一”(one-to-one)的结构(上图编号3所示),这个可能没有那么重要,这就是一个小型的标准的神经网络,输入 x x x然后得到输出 y y y,我们这个系列课程的前两个课程已经讨论过这种类型的神经网络了。
在这里插入图片描述
除了“多对一”的结构,也可以有“一对多”(one-to-many)的结构。对于一个“一对多”神经网络结构的例子就是音乐生成(上图编号1所示),事实上,你会在这个课后编程练习中去实现这样的模型,你的目标是使用一个神经网络输出一些音符。对应于一段音乐,输入 x x x可以是一个整数,表示你想要的音乐类型或者是你想要的音乐的第一个音符,并且如果你什么都不想输入, x x x可以是空的输入,可设为0向量。

这样这个神经网络的结构,首先是你的输入 x x x,然后得到RNN的输出,第一个值,然后就没有输入了,再得到第二个输出,接着输出第三个值等等,一直到合成这个音乐作品的最后一个音符,这里也可以写上输入 a < 0 > a^{<0>} a<0>(上图编号3所示)。有一个后面才会讲到的技术细节,当你生成序列时通常会把第一个合成的输出也喂给下一层(上图编号4所示),所以实际的网络结构最终就像这个样子。

我们已经讨论了“多对多”、“多对一”、“一对一”和“一对多”的结构,对于“多对多”的结构还有一个有趣的例子值得详细说一下,就是输入和输出长度不同的情况。你刚才看过的多对多的例子,它的输入长度和输出长度是完全一样的。而对于像机器翻译这样的应用,输入句子的单词的数量,比如说一个法语的句子,和输出句子的单词数量,比如翻译成英语,这两个句子的长度可能不同,所以还需要一个新的网络结构,一个不同的神经网络(上图编号2所示)。首先读入这个句子,读入这个输入,比如你要将法语翻译成英语,读完之后,这个网络就会输出翻译结果。有了这种结构 T x T_{x} Tx T y T_{y} Ty就可以是不同的长度了。同样,你也可以画上这个 a < 0 > a^{<0>} a<0>。这个网络的结构有两个不同的部分,这(上图编号5所示)是一个编码器,获取输入,比如法语句子,这(上图编号6所示)是解码器,它会读取整个句子,然后输出翻译成其他语言的结果。
在这里插入图片描述
这就是一个“多对多”结构的例子,到这周结束的时候,你就能对这些各种各样结构的基本构件有一个很好的理解。严格来说,还有一种结构,我们会在第四周涉及到,就是“注意力”(attention based)结构,但是根据我们现在画的这些图不好理解这个模型。

总结一下这些各种各样的RNN结构,这(上图编号1所示)是“一对一”的结构,当去掉 a < 0 > a^{<0>} a<0>时它就是一种标准类型的神经网络。还有一种“一对多”的结构(上图编号2所示),比如音乐生成或者序列生成。还有“多对一”,这(上图编号3所示)是情感分类的例子,首先读取输入,一个电影评论的文本,然后判断他们是否喜欢电影还是不喜欢。还有“多对多”的结构(上图编号4所示),命名实体识别就是“多对多”的例子,其中 T x = T y T_{x}=T_{y} Tx=Ty。最后还有一种“多对多”结构的其他版本(上图编号5所示),对于像机器翻译这样的应用, T x T_{x} Tx T y T_{y} Ty就可以不同了。

语言模型和序列生成(Language model and sequence generation)

对新序列采样(Sampling novel sequences)

循环神经网络的梯度消失(Vanishing gradients with RNNs)

在这里插入图片描述
你已经知道了RNN的样子,现在我们举个语言模型的例子,假如看到这个句子(上图编号1所示),“The cat, which already ate ……, was full.”,前后应该保持一致,因为cat是单数,所以应该用was。“The cats, which ate ……, were full.”(上图编号2所示),cats是复数,所以用were。这个例子中的句子有长期的依赖,最前面的单词对句子后面的单词有影响。但是我们目前见到的基本的RNN模型(上图编号3所示的网络模型),不擅长捕获这种长期依赖效应,解释一下为什么。

你应该还记得之前讨论的训练很深的网络,我们讨论了梯度消失的问题。比如说一个很深很深的网络(上图编号4所示),100层,甚至更深,对这个网络从左到右做前向传播然后再反向传播。我们知道如果这是个很深的神经网络,从输出 y ^ \hat y y^得到的梯度很难传播回去,很难影响靠前层的权重,很难影响前面层(编号5所示的层)的计算。

对于有同样问题的RNN,首先从左到右前向传播,然后反向传播。但是反向传播会很困难,因为同样的梯度消失的问题,后面层的输出误差(上图编号6所示)很难影响前面层(上图编号7所示的层)的计算。这就意味着,实际上很难让一个神经网络能够意识到它要记住看到的是单数名词还是复数名词,然后在序列后面生成依赖单复数形式的was或者were。而且在英语里面,这中间的内容(上图编号8所示)可以任意长,对吧?所以你需要长时间记住单词是单数还是复数,这样后面的句子才能用到这些信息。也正是这个原因,所以基本的RNN模型会有很多局部影响,意味着这个输出 y ^ < 3 > \hat y^{<3>} y^<3>(上图编号9所示)主要受 y ^ < 3 > \hat y^{<3>} y^<3>附近的值(上图编号10所示)的影响,上图编号11所示的一个数值主要与附近的输入(上图编号12所示)有关,上图编号6所示的输出,基本上很难受到序列靠前的输入(上图编号10所示)的影响,这是因为不管输出是什么,不管是对的,还是错的,这个区域都很难反向传播到序列的前面部分,也因此网络很难调整序列前面的计算。这是基本的RNN算法的一个缺点,我们会在下几节视频里处理这个问题。如果不管的话,RNN会不擅长处理长期依赖的问题。
在这里插入图片描述
尽管我们一直在讨论梯度消失问题,但是,你应该记得我们在讲很深的神经网络时,我们也提到了梯度爆炸,我们在反向传播的时候,随着层数的增多,梯度不仅可能指数型的下降,也可能指数型的上升。事实上梯度消失在训练RNN时是首要的问题,尽管梯度爆炸也是会出现,但是梯度爆炸很明显,因为指数级大的梯度会让你的参数变得极其大,以至于你的网络参数崩溃。所以梯度爆炸很容易发现,因为参数会大到崩溃,你会看到很多NaN,或者不是数字的情况,这意味着你的网络计算出现了数值溢出。如果你发现了梯度爆炸的问题,一个解决方法就是用梯度修剪。梯度修剪的意思就是观察你的梯度向量,如果它大于某个阈值,缩放梯度向量,保证它不会太大,这就是通过一些最大值来修剪的方法。所以如果你遇到了梯度爆炸,如果导数值很大,或者出现了NaN,就用梯度修剪,这是相对比较鲁棒的,这是梯度爆炸的解决方法。然而梯度消失更难解决,这也是我们下几节视频的主题。

总结一下,在前面的课程,我们了解了训练很深的神经网络时,随着层数的增加,导数有可能指数型的下降或者指数型的增加,我们可能会遇到梯度消失或者梯度爆炸的问题。加入一个RNN处理1,000个时间序列的数据集或者10,000个时间序列的数据集,这就是一个1,000层或者10,000层的神经网络,这样的网络就会遇到上述类型的问题。梯度爆炸基本上用梯度修剪就可以应对,但梯度消失比较棘手。我们下节会介绍GRU,门控循环单元网络,这个网络可以有效地解决梯度消失的问题,并且能够使你的神经网络捕获更长的长期依赖,我们去下个视频一探究竟吧。

GRU单元(Gated Recurrent Unit(GRU))

长短期记忆(LSTM(long short term memory)unit)

双向循环神经网络(Bidirectional RNN)

深层循环神经网络(Deep RNNs)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值