循环神经网络(RNN)的工作方式(二)


本篇文章是吴恩达《深度学习》序列模型部分第一周课程的笔记,前面的小节的笔记见 循环神经网络(RNN)的工作方式(一)

1.7 对新序列采样

在你训练一个序列模型之后,要想了解这个模型学到了什么,一种非正式的方法就是进行一次新序列采样,具体见如下ppt。
pic_1
上述ppt中印刷的循环神经网络是训练阶段的结构,也就是我们上一节所说的结构,手写的是采样阶段采用的结构。
通过之前的讲解,我们知道一个序列模型模拟了任意特定单词组成序列的概率。现在我们要做的是对这个概率分布进行采样来生成一个新的单词序列。
采样的过程和上一节所说的训练过程是不同的。第一步要做的是对你想要模型生成的第一个词进行采样,于是输入 x &lt; 1 &gt; x^{&lt;1&gt;} x<1> a &lt; 0 &gt; a^{&lt;0&gt;} a<0>(它们都是零向量)。现在第一个timestep得到的经过softmax层后的所有可能输出结果的概率,然后根据这个softmax的概率分布,进行随机采样。这里,softmax分布给出的信息是第一个词是xxx的概率是多少,其中xxx是你用训练集创建的词典中的某个单词,比如第一个softmax的输出可以是 P ( a ) P ( a r o w ) . . . P ( z u l u ) P ( &lt; u n k &gt; ) P(a)P(arow)...P(zulu)P(&lt;unk&gt;) P(a)P(arow)...P(zulu)P(<unk>)等。
然后我们对这个由词表中单词出现概率构成的向量进行随机采样,可以使用比如 n p . r a n d o m . c h o i c e np.random.choice np.random.choice函数,这样就能对第一个词进行采样了,这一步我们得到 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} y^<1>
然后继续下一个timestep,第二个timestep需要 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} y^<1>作为输入,也就是第一个timestep的输出作为第二个timestep的输入,然后softmax层就会预测 y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} y^<2>是什么。
第二个timestep采样的过程可以用一个例子说明。假如说对第一个词进行采样后得到的词是the,然后把the当成 x &lt; 2 &gt; x^{&lt;2&gt;} x<2>,现在 x &lt; 2 &gt; x^{&lt;2&gt;} x<2>就是 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} y^<1>,现在需要计算出在第一个词是the的情况下第二个词应该是什么(即条件概率),然后得到一个 y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} y^<2>的概率分布,最后再次用这个采样函数 n p . r a n d o m . c h o i c e np.random.choice np.random.choice来对 y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} y^<2>进行采样就得到第二个timestep的输出。
然后再到下一个timestep,无论你上一个timestep得到什么样的用one-hot编码表示的选择结果,都把它传到下一个timestep,然后对第三个词进行采样,不管得到什么都把它传递下去,一直这样直到最后一个timestep。
那么我们怎么才能知道一个句子结束了呢?方法之一就是,如果代表句子结尾的标识EOS在你的词典中,你可以一直进行采样,直到得到EOS标志,这代表着你已经抵达结尾,可以停止采样了。另一种方法是,如果你的词典中没有设置EOS,你可以决定从20个或100个或其他个数个词中进行采样,然后将采样一直进行下去直到达到所设定的timestep。
在采样过程中有时候会产生一些<UNK>标识,如果要确保算法不会输出这种标识,我们可以做的是,拒绝采样过程中产生任何未知的标识,一旦出现就继续在剩下的词中进行重采样,直到得到一个不是未知标识的词。当然,我们也可以完全不管它们,任由未知标识产生。
这就是我们如何从RNN语言模型中生成一个随机选择的句子的过程。
前面所讲的模型都是基于词语的模型,下面我们看一下基于字符的模型。
pic_2
如上述ppt所示,基于词语的模型的词典中是一个个单词,而基于字符的模型的词典中是一个个字符,这个词典可以包含大小写英文字母(如果需要区分大小写),标点符号,空格等。
基于字符的模型中训练数据 y &lt; 1 &gt; y &lt; 2 &gt; y &lt; 3 &gt; y^{&lt;1&gt;}y^{&lt;2&gt;}y^{&lt;3&gt;} y<1>y<2>y<3>是字符序列不再是词语序列,比如“Cat average”的前四个字符C a t 就是 y &lt; 1 &gt; y &lt; 2 &gt; y &lt; 3 &gt; y &lt; 4 &gt; y^{&lt;1&gt;}y^{&lt;2&gt;}y^{&lt;3&gt;}y^{&lt;4&gt;} y<1>y<2>y<3>y<4>
相比于基于词语的模型,基于字符的模型的优点在于:不用担心会出现未知标识(unknown words token)。比如在基于词语的模型中Mau是未知标识,但在基于字符的模型中Mau是一个可能性非零的序列,因为它被拆解成了M a u三个字符了,这三个字符在词典中。
但基于字符的模型也有缺点:主要的缺点是它最终会得到太多太长的序列。比如大多数英语句子只有10到20个单词,但却可能包含很多很多字符。因为序列太长,基于字符的语言模型在捕捉句子中的依赖关系(句子较前部分如何影响较后部分)时不如基于词汇的语言模型那样可以捕捉长范围的关系,并且基于字符的语言模型训练起来计算成本比较高昂。
除了一些比较专门需要处理大量未知文本或者未知词汇的应用,或者一些要面对很多专有词汇的应用,或者在有充足的计算资源的情况下,现在采用基于字符的模型的应用并不是那么普遍。
下面的ppt展示了序列采样的结果,左侧是生成的新闻,右侧是莎士比亚小说。
pic_3

1.8 循环神经网络的梯度消失

我们看下述ppt中的句子,一个是The cat, which already ate … , was full.,另外一个是The cats, which already ate … , were full. 两句话的差别在于主语和谓语动词的单复数。这两个句子中的主语和谓语动词有着长期依赖关系,序列中最前面的单词对序列中后面的单词有影响,我们之前讲到过的基本RNN(ppt中上方的网络)是无法捕捉这种长期依赖关系的。
pic_4
当我们训练一个神经网络时,是对这个网络从左到右做前向传播然后再做反向传播。如果这个网络很深,比如有100层甚至更多,那么从网络的输出 y ^ \hat y y^(ppt中下方的网络)得到的梯度是很难传播回去的,也就是说它很难影响靠前层的权重,难以影响前面层的计算。
在RNN中,这就意味着很难让网络长时间记住它看到的主语是单数名词还是复数名词,然后在序列后面生成依赖这个主语的谓语动词(was或were)。因为这种问题,基本的RNN受到很多局部影响,比如 y ^ &lt; 3 &gt; \hat y^{&lt;3&gt;} y^<3>主要受 y ^ &lt; 3 &gt; \hat y^{&lt;3&gt;} y^<3>附近的或者说它之前的几个输入的影响。这实际上是RNN算法的一个缺点,因为不管输出是什么,无论对的或错的,它的梯度都很难反向传播到前面以调整前面序列的计算。
对于反向传播,当层数增多时,梯度不仅可能呈指数级上升,也有可能呈指数级下降。尽管梯度爆炸也可能在RNN中出现,但梯度消失在训练RNN时才是首要的问题。梯度爆炸(指数级上升)很容易被发现,因为指数级大的梯度会让参数变得极其大以至于网络参数崩溃,这时我们能看到网络出现很多NaN(Not a Number)情况,这意味着网络计算出现了数值溢出(导数值很大)。如果我们发现网络出现梯度爆炸,一种解决方法是使用梯度修剪(gradient clipping),意思是监视梯度向量,如果它大于某个阈值,则缩放梯度向量保证它不会太大,也就是通过一些最大值的限制来修剪梯度,这是相对鲁棒的解决梯度爆炸的方法。
梯度消失比较难以解决,后面的小节中我们会讲解几种方法。

1.9 GRU单元

GRU即Gated Recurrent Unit(门控循环单元)改变了RNN的隐藏层,使其可以更好地捕捉深层连接并改善了梯度消失问题。
在了解GRU单元时,我们先一起回顾一下RNN的隐层单元。
pic_5
如上述ppt右侧公式, a &lt; t − 1 &gt; a^{&lt;t-1&gt;} a<t1>表示上一个timestep的激活值, x &lt; t &gt; x^{&lt;t&gt;} x<t>表示当前timestep的输入值, W a W_a Wa为权重, b a b_a ba为偏置项, g g g为激活函数tanh, a &lt; t &gt; a^{&lt;t&gt;} a<t>为当前timestep的激活值。
ppt中左侧就是这个RNN单元的可视化绘图,先是 a &lt; t − 1 &gt; a^{&lt;t-1&gt;} a<t1> x &lt; t &gt; x^{&lt;t&gt;} x<t>进行连接,左乘权重再加上偏置项后被tanh激活,tanh的输出被复制成两份,一份就是当前timestep的激活值 a &lt; t &gt; a^{&lt;t&gt;} a<t>,还有一份输入到softmax,softmax的输出就是 y ^ &lt; t &gt; \hat y^{&lt;t&gt;} y^<t>
下面,我们先看一个简化版本的GRU单元。
pic_6
我们先看ppt右侧的几个公式。首先,GRU单元使用一个新的变量c,该变量代表cell,即记忆细胞(memory cell)。记忆细胞提供了记忆的能力,比如记住猫是单数cat还是复数cats,这样当它看到句子之后的部分的时候,就仍能够判断句子的主语是单数还是复数。在timestep t处,记忆细胞有关于t的值 c &lt; t &gt; c^{&lt;t&gt;} c<t>,而我们实际看到的是,GRU输出了激活值 a &lt; t &gt; a^{&lt;t&gt;} a<t>,它和 c &lt; t &gt; c^{&lt;t&gt;} c<t>是相等的。虽然现在

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值