吴恩达序列模型————循环序列模型

数学符号(输出y也是类似)

$x ^ { ( i ) }$:表示第i个样本

$x ^ { ( i ) < t > }$:第i个样本第t个输入

$T _ { x } ^ { ( i ) }$:表示第i个样本的序列长度

循环神经网络

为什么不用标准的神经网络

  • 输入和输出数据在不同的例子中可以有不同的长度;
  • 这种朴素的神经网络结果并不能共享从文本不同位置所学习到的特征。(如卷积神经网络中学到的特征的快速地推广到图片其他位置)

循环神经网络

对于每个时间步,输入一个$x ^{< t >}$,输出一个$y^{ < t >}$,

$a^{<0>}$表示的是0向量,每个时间步的输出既取决于该时间步的输入,还取决于上一个时间步中隐藏层的输出,这样可以充分利用前面所有步的信息,但缺点就是不能够利用后面步数的信息

公式表达

$a ^ { < t > } = g _ { 1 } \left( w _ { a x } \times x ^ { < t > } + w _ { a a } \times a ^ { < t - 1 > } + b _ { a } \right)$

$y ^ { < t > } = g _ { 2 } \left( w _ { y a } \times a ^ { < t > } + b _ { y } \right)$

通常第一个g函数是$tanh(x)$函数,第二个g函数为$Sigmoid(x)$函数

反向传播

循环神经网络的唯一区别在于因为它每个时刻都有一个输出,所以循环神经网络的总损失为所有时刻(或者部分时刻)上的损失函数的总和。定义好损失函数,通过交叉熵损失函数定义。计算过程是通过计算图,一步步通过反向传递的思想找出损失函数关于参数的偏导。

不同类型的循环神经网络

1、many to many:命名实体标记(输入序列和输出序列的长度相等)

2、one to many:音乐序列的生成

3、many to many:机器翻译(将法语翻译成英语),这种的是用encode进行输入,用decode进行输出,后面会利用attention机制来进行

4、one to one:

5、many to one:情感分类(五星评价)

语言模型和序列生成

什么是语言模型

很通俗地将,就是一句话更像是人话,那么这句话就是我们需要的句子序列。

语言模型的任务就是预测每个句子在语言中出现的概率。对于语言中常见的句子,应该给与比较高的概率;而对于不合语法的句子,计算出的概率则应该接近于0.把句子看成单词的序列,语言模型可以表示为一个计算$p(w_1w_2w_3,…,w_m)$的模型。语言仅仅对句子出现的概率进行建模,并不尝试去“理解”句子的内容含义。比如说,语言模型能告诉我们什么样的句子是常见的句子,但无法告诉我们两句话的意思是否相似或者相反。

基于语言模型的序列生成

训练集:一个很大语料库

训练集处理:未出现在字典库中的词使用“UNK”来表示;Tokenize:将句子使用字典库标记化;

模型:通过RNN循环计算当前对于当前时间步,给定前一个单词,预测该时间步的输出单词

模型训练:损失函数使用交叉熵函数,对于每一个时间步,其输入是,输出是,对应的标签是,叠加每一个时间步关于输出和真实值的误差大小来进行参数的更新。

对新样本进行采样

目的:在训练好一个序列模型后,我们要想了解整个模型学习到了什么,一个方法就是对这个模型进行采样

过程:首先我们输入$a ^ { < 0 > } = 0 , x ^ { < 0 > } = 0$ ,在经过softmax层后会输出每一个词的概率,这个时候我们利用np.random.choice()进行随机采样,随机选择一个词作为t=1的输出$y ^{< 1 >}$,然后将上一个时间步的输出$y ^{< 1 >}$作为t=2的输入,我们就可以得到基于第一个词的条件下第二个词的条件概率分布,然后也可以进行随机选择

梯度消失和梯度下降

梯度消失

梯度消失指的是在反向传播的过程中,后面的输入的梯度很难通过反向传播传递到前面的单元,也即前面的单词很难影响后面的单词,RNN模型不擅长于捕捉这种长期的依赖关系,但在序列模型中我们要经常性地利用到这种长期的依赖关系

梯度爆炸

梯度爆炸一般容易发现,程序一般会返回NAN,提示数值溢出,我们可以通过梯度裁剪的方法,给定一个阈值,使得梯度不会超过这个阈值。所以相对而言,梯度消失更难以发现并难以解决。

门控循环单元

重置门和更新门

门控循环单元中的重置门(reset gate)和更新门(update gate)的输入均为当前时间步输$X ^ { }$ 与上一时间步隐藏状态 $H^ { }$,输出由激活函数为$sigmoid$函数的全连接层计算得到。

假设隐藏单元个数为 h,给定时间步 t 的小批量输入$X ^{< t> } \in \mathbb { R } ^ { n \times d }$(样本数为 n,输入个数为 d)和上一时间步隐藏状态$H ^{< t> } \in \mathbb { R } ^ { n \times h}$。重置门$R ^{< t> } \in \mathbb { R } ^ { n \times h}$和更新门$Z ^{< t> } \in \mathbb { R } ^ { n \times h }$的计算如下:

$\boldsymbol { R } _ { t } = \sigma \left( \boldsymbol { X } _ { t } \boldsymbol { W } _ { x r } + \boldsymbol { H } _ { t - 1 } \boldsymbol { W } _ { h r } + \boldsymbol { b } _ { r } \right)$

$Z _ { t } = \sigma \left( \boldsymbol { X } _ { t } \boldsymbol { W } _ { x z } + \boldsymbol { H } _ { t - 1 } \boldsymbol { W } _ { h z } + \boldsymbol { b } _ { z } \right)$

候选隐藏状态

门控循环单元将计算候选隐藏状态来辅助稍后的隐藏状态计算。如图所示我们将当前时间步重置门的输出与上一时间步隐藏状态做按元素乘法(符号为 ⊙)。如果重置门中元素值接近 0,那么意味着重置对应隐藏状态元素为 0,即丢弃上一时间步的隐藏状态。如果元素值接近 1,那么表明保留上次时间步的隐藏状态。然后,将按元素乘法的结果与当前时间步的输入连结,再通过含激活函数 tanh 的全连接层计算出候选隐藏状态,其所有元素的值域为 [−1, 1]。

具体来说,时间步 t 的候选隐藏状态$\tilde { H } _ { t } \in \mathbb { R } ^ { n \times h }$的计算为

$\tilde { H } _ { t } = \tanh \left( \boldsymbol { X } _ { t } \boldsymbol { W } _ { x h } + \left( \boldsymbol { R } _ { t } \odot \boldsymbol { H } _ { t - 1 } \right) \boldsymbol { W } _ { h h } + b _ { h } \right)$

重置门控制了上一时间步的隐藏状态如何流入当前时间步的候选隐藏状态。而上一时间步的隐藏状态可能包含了时间序列截至上一时间步的全部历史信息。因此,重置门可以用来丢弃与预测无关的历史信息。

隐藏状态

最后,时间步 t 的隐藏状态$\boldsymbol { H } ^ { } \in \mathbb { R } ^ { n \times h }$的计算使用当前时间步的更新$Z^ {}$来对上一时间步的隐藏状态$H^ {}$和当前时间步的候选隐藏状态$\tilde { H } _ { t }$做组合:

$H ^ { } = Z ^ { } \odot H ^ { } + \left( 1 - Z ^ { } \right) \odot \tilde { H } ^ { }$

值得注意的是,更新门可以控制隐藏状态应该如何被包含当前时间步信息的候选隐藏状态所更新,如图所示假设更新门在时间步 t′ 到 t(t′ < t)之间一直近似 1。那么,在时间步 t′ 到t 之间的输入信息几乎没有流入时间步 t 的隐藏状态$H^{}$。实际上,这可以看作是较早时刻的隐藏状态$H ^ { t ^ { \prime } - 1 }$一直通过时间保存并传递至当前时间步 t。这个设计可以应对循环神经网络中的梯度衰减问题,并更好地捕捉时间序列中时间步距离较大的依赖关系。

我们对门控循环单元的设计稍作总结:

重置门有助于捕捉时间序列里短期的依赖关系。
更新门有助于捕捉时间序列里长期的依赖关系。

长短期记忆(LSTM)

LSTM 中引入了三个门:输入门(input gate)、遗忘门(forget gate)和输出门(output gate),以及与隐藏状态形状相同的记忆细胞(某些文献把记忆细胞当成一种特殊隐藏状态),从而记录额外的信息。

输入门、遗忘门和输出门

同门控循环单元中的重置门和更新门一样,如图所示,长短期记忆的门的输入均为当前时间步输入$X^{}$与上一时间步隐藏状态$H^{}$,输出由激活函数为$sigmoid$函数的全连接层计算得到。如此一来,这三个门元素的值域均为 [0, 1]。

具体来说,假设隐藏单元个数为$h$,给定时间步$t$的小批量输入$X ^ {< t> } \in \mathbb { R } ^ { n \times d }$(样本数为 n,输入个数为 d)和上一时间步隐藏状态$H ^ { } \in \mathbb { R } ^ { n \times h }$。时间步 t 的输入门$I ^ { } \in \mathbb { R } ^ { n \times h }$、遗忘门$F ^ { } \in \mathbb { R } ^ { n \times h }$和输出门$O^ { } \in \mathbb { R } ^ { n \times h }$分别计算如下:

$\boldsymbol { I } ^ { } = \sigma \left( \boldsymbol { X } ^ { } \boldsymbol { W } _ { x i } + \boldsymbol { H } ^ { } \boldsymbol { W } _ { h i } + b _ { i } \right)$

$\boldsymbol { F } ^ { } = \sigma \left( \boldsymbol { X } ^ { } \boldsymbol { W } _ { x f } + \boldsymbol { H } ^ { } \boldsymbol { W } _ { h f } + \boldsymbol { b } _ { f } \right)$

$O ^ { } = \sigma \left( \boldsymbol { X } ^ { } \boldsymbol { W } _ { x o } + \boldsymbol { H } ^ { } \boldsymbol { W } _ { h o } + \boldsymbol { b } _ { o } \right)$

候选记忆细胞

接下来,长短期记忆需要计算候选记忆细胞 $\tilde { C } _ { t }$。它的计算同上面介绍的三个门类似,但使用了值域在 [−1, 1] 的 $tanh$函数做激活函数,如图所示:

具体来说,时间步 t 的候选记忆细胞 $\tilde { C } _ { t }$的计算为:

$\tilde { C } _ { t } = \tanh \left( \boldsymbol { X } _ { t } \boldsymbol { W } _ { x c } + \boldsymbol { H } _ { t - 1 } \boldsymbol { W } _ { h c } + \boldsymbol { b } _ { c } \right)$

记忆细胞

我们可以通过元素值域在[0; 1] 的输入门、遗忘门和输出门来控制隐藏状态中信息的流动:这一般也是通过使用按元素乘法(符号为⊙)来实现。当前时间步记忆细胞$C ^ { } \in \mathbb { R } ^ { n \times h }$的计算组合了上一时间步记忆细胞和当前时间步候选记忆细胞的信息,并通过遗忘门和输入门来控制信息的流动:

$C ^ { } = F ^ { } \odot C ^ { } + I ^ { } \odot \tilde { C } ^ { }$

遗忘门控制上一时间步的记忆细胞$C^{}$中的信息是否传递到当前时间步,而输入门则可以控制当前时间步的输入$X^{}$通过候选记忆细胞$\tilde{C}^{}$如何流入当前时间步的记忆细胞。如果遗忘门直近似 1 且输入门一直近似 0,过去的记忆细胞将一直通过时间保存并传递至当前时间步。这个设计可以应对循环神经网络中的梯度衰减问题,并更好地捕捉时间序列中时间步距离较大的依赖关系。

隐藏状态

有了记忆细胞以后,接下来我们还可以通过输出门来控制从记忆细胞到隐藏状态$H ^ { } \in \mathbb { R } ^ { n \times h }$的信息的流动:

$H ^ { } = O ^ { } \odot \tanh \left( C ^ { } \right)$

这里的tanh 函数确保隐藏状态元素值在-1到1 之间。需要注意的是,当输出门近似1 时,记忆细胞信息将传递到隐藏状态供输出层使用;当输出门近似0时,记忆细胞信息只自己保留。图展示了长短期记忆中隐藏状态的计算。

理解

遗忘门的作用是让循环神经网络“忘记”之前没有用的信息。比如一段文章先介绍了某地原来是绿水蓝天,但后来被污染了。于是在看到被污染了之后,循环神经网络应该“忘记”之前绿水蓝天的状态。这个工作是通过遗忘门来完成的。

在循环神经网络“忘记”了部分之前的状态后,它还需要从当前的输入补充最新的记忆。比如当看到文章中提到环境被污染之后,模型需要将这个信息写入到新的状态中。这个过程就是输入门完成的。

LSTM结构在计算得到新的状态$c^{t}$ 后需要产生当前时刻的输出,这个过程是通过“输出门”完成的。输出门会根据最新的状态$c^{}$ 、上一时刻的输出$h^{}$ 和当前的输入$x^{}$ 来决定该时刻的输出$h^{}$ 。比如当前的状态被污染,那么“天空的颜色”后面的单词就很可能就是“灰色的”

双向循环神经网络

之前介绍的循环神经网络模型都是假设当前时间步是由前面的较早时间步的序列决定,因此它们都将信息通过隐藏状态从前往后传递。有时候,当前时间步也可能由后面时间步决定。例如,当我们写下一个句子时,可能会根据句子后面的词来修改句子前面的用词。双向循环神经网络通过增加从后往前传递信息的隐藏层来更灵活地处理这类信息。下图演示了一个含单隐藏层的双向循环神经网络的架构。

下面我们来介绍具体的定义。给定时间步t 的小批量输入$X ^ { } \in \mathbb { R } ^ { n \times d }​$(样本数为n,输入个数为d)和隐藏层激活函数为$ϕ​$。在双向架构中,设该时间步正向隐藏状态为$\overrightarrow { H } ^ { } \in \mathbb { R } ^ { n \times h }​$(正向隐藏单元个数为h),反向隐藏状态为$\overleftarrow {H } ^ { } \in \mathbb { R } ^ { n \times h }​$h(反向隐藏单元个数为h)。我们可以分别计算正向和反向隐藏状态:

$\vec { H } ^ { } = \phi \left( X ^ { } W _ { x h } ^ { ( f ) } + \vec { H } ^{ } W _ { h h } ^ { ( f ) } + b _ { h } ^ { ( f ) } \right)$
$\overrightarrow { H } ^ { } = \phi \left( X ^ { } W _ { x h } ^ { ( b ) } + \overrightarrow { H } ^ { } W _ { h h } ^ { ( b ) } + b _ { h } ^ { ( b ) } \right)$

然后我们连结两个方向的隐藏状态$\vec { H } ^ { }$和$\overrightarrow { H } ^ { }$ 来得到隐藏状态$H^ { } \in \mathbb { R } ^ { n \times 2 h }$,并将其输入到输出层。输出层计算输出$O ^ { t } \in \mathbb { R } ^ { n \times q }$(输出个数为q):

$O ^ { } = H ^ { } W _ { h q } + b _ { q }$

深度循环神经网络

到目前为止介绍的循环神经网络只有一个单向的隐藏层,在深度学习应用,我们通常会到含用有多个隐藏层的循环神经网络,也称作深度循环神经网络。图演示了一个有L 个隐藏层的深度循环神经网络,每个隐藏状态不断传递至当前层的下一时间步和当前时间步的下一层。

具体来说,在时间步t 里,设小批量输入$X ^ { } \in \mathbb { R } ^ { n \times d }​$(样本数为n,输入个数为d),第$ℓ​$ 隐藏层$(ℓ = 1; …;T)​$的隐藏状态为$\boldsymbol { H } ^ { ( \ell ) } \in \mathbb { R } ^ { n \times h }​$(隐藏单元个数为h),输出层变量为$O ^ { } \in \mathbb { R } ^ { n \times q }​$(输出个数为q),且隐藏层的激活函数为$ϕ​$。第1 隐藏层的隐藏状态和之前的计算一样:

$H ^ { ( 1 ) } = \phi \left( X ^ { } W _ { x h } ^ { ( 1 ) } + H ^ { ( 1 ) } W _ { h h } ^ { ( 1 ) } + b _ { h } ^ { ( 1 ) } \right)$

当$1 < ℓ <L$ 时,第ℓ 隐藏层的隐藏状态的表达式为

$H ^ { ( \ell ) } = \phi \left( H ^ { ( \ell - 1 ) } \boldsymbol { W } _ { x h } ^ { ( \ell ) } + H ^ { ( \ell ) } \boldsymbol { W } _ { h h } ^ { ( \ell ) } + b _ { h } ^ { ( \ell ) } \right)$

最终,输出层的输出只需基于第L 隐藏层的隐藏状态:

$O ^ {< t> } = H ^ { ( L ) } W _ { h q } + b _ { q }$

同多层感知机⼀样,隐藏层个数L 和隐藏单元个数h 都是超参数。此外,如果将隐藏状态的计算换成门控循环单元或者长短期记忆的计算,我们可以得到深度门控循环神经网络。