深度学习(9):循环神经网络

随深度学习技术的发展,使用循环神经网络(Recurrent Neural Network,RNN)建立的各种序列模型,使语音识别、机器翻译及自然语言理解等应用成为可能。

表示与类型

自然语言、音频等数据都是前后相互关联的数据,比如理解一句话要通过一整句而不是其中的几个词,分析一段音频要通过连续的片段而不是其中的几帧。前面所学的DNN以及CNN处理的都是前后毫无关联的一个个单独数据,对于这些序列数据则需要采用RNN进行处理。

序列

用循环神经网络处理时间序列时,首先要对时间序列进行标记化。对一个序列数据$x$,用符号$x^{\langle t\rangle}$来表示这个序列数据中的第$t$个元素。这个元素的类型因数据类型而异,对一段音频,它可能其中的几帧,对一句话,它可能是一个或几个单词,如下图所示。

Harry Potter

第$i$个序列数据的第$t$个元素用符号$x^{(i)\langle t\rangle}$表示,其标签用符号$y^{(i)\langle t\rangle}$表示。

序列中的每个元素有相应的标签,一般需要先建立一个包含序列中所有类型的元素的字典(Dictionary)。例如对上图中的句子,建立一个含有10000个单词的列向量词典,单词顺序以A~Z排列,然后根据单词在列向量中的位置,用one—hot向量来表示该单词的标签,部分表示如下图:

字典

标记化完成后,将训练数据输入网络中。一种循环神经网络的结构如下图:
RNN结构

左边的网络可简单表示为右图的结构,其中元素$x^{\langle t\rangle}$输入对应时间步(TIme Step)的隐藏层的同时,该隐藏层也会接收上一时间步的隐藏层激活$a^{\langle t-1\rangle}$,其中$a^{\langle 0\rangle}$一般直接初始化为零向量。一个时间步输出一个对应的预测结果${\hat y}^{\langle t\rangle}$,输入、激活、输出有对应的参数$W_{ax}$、$W_{aa}$、$W_{y}$。

以上结构的前向传播过程,有:$$a^{\langle 0\rangle} = \vec 0$$ $$a^{\langle t\rangle} = g_1(W_{aa} a^{\langle t-1\rangle} + W_{ax} x^{\langle t\rangle} + b_a)$$ $${\hat y}^{\langle t\rangle} = g_2(W_{y} a^{\langle t\rangle} + b_y)$$

其中$b_a$、$b_y$是两个偏差参数,激活函数$g_1$通常选择tanh,有时也用ReLU,$g_2$的选择取决于需要的输出类型,可选sigmoid或Softmax。

具体计算中以上的式子还可以进一步简化,以方便运算。将$W_{ax}$和$W_{aa}$堆叠成一个矩阵$W_a$,$a^{\langle t-1\rangle}$和$x^{\langle t\rangle}$也堆叠成一个矩阵,有:$$ W_a = [W_{ax}, W_{aa}] $$ $$a^{\langle t\rangle} = g_1(W_{a}[a^{\langle t-1\rangle},x^{\langle t\rangle}] + b_a)$$

反向传播的过程类似于深度神经网络,如下图所示:
RNN反向传播

这种结构的一个缺陷是,某一时刻的预测结果仅使用了该时刻之前输入的序列信息。根据所需的输入及输出数量,循环神经网络可分为“一对一”、“多对一”、“多对多”等结构:

类型

这些网络结构可在不同的领域中得到应用。

RNN应用:语言模型

语言模型(Language Model)是根据语言客观事实而进行的语言抽象数学建模。例如对一个语音识别系统,输入的一段语音可能表示下面两句话:
English

其中的“pair”和“pear”读音相近,但是在日常表达及语法上显然这段语音是第二句的可能性要大,要使这个语音识别系统能够准确判断出第二句话为正确结果,就需要语言模型的支持。这个语言模型能够分别计算出语音表示以上两句话的概率,以此为依据做出判断。

建立语言模型所采用的训练集是一个大型的语料库(Corpus)。建立过程中,如之前所述,需要先建立一个字典,之后将语料库中每个词表示为对应的one-hot向量。此外需要额外定义一个标记EOS(End Of Sentence)表示一个句子的结尾,也可以将其中的标点符号加入字典后也用one=hot向量表示。对于语料库中部分(英语)人名、地名等特殊的不包含在字典中的词汇,可在词典中加入再用一个UNK(Unique Token)标记来表示。

将标志化后的训练集输入网络中的训练过程,如下例所示:

语言模型

第一个时间步中输入的$a^{\langle 0\rangle}$和$x^{\langle 1\rangle}$都是零向量,${\hat y}^{\langle 1\rangle}$是通过softmax预测出的字典中每一个词作为第一个词出现的概率;第二个时间步中输入的$x^{\langle 2\rangle}$是下面的训练数据中第一个单词“cats”的标签$y^{\langle 1\rangle}$和上一层的激活$a^{\langle 1\rangle}$,输出的$y^{\langle 2\rangle}$表示的是单词“cats”后面出现字典中的其他词,特别是“average”的条件概率。后面的时间步与第二步类似,到最后就可以得到整个句子出现的概率。

这样,损失函数将表示为:$$ \mathcal{L}({\hat y}^{\langle t\rangle},y^{\langle t\rangle})=-\sum_t y^{\langle t\rangle}_i log\ {\hat y}^{\langle t\rangle}$$

成本函数表示为:$$ \mathcal{J} = \sum_t \mathcal{L}^{\langle t\rangle}({\hat y}^{\langle t\rangle},y^{\langle t\rangle})$$

训练好一个这个语言模型后,可通过采样(Sample)新的序列,来了解这个模型中都学习到了一些什么。从模型中采样出新序列的过程如下:
采样新序列

第一个时间步中输入的$a^{\langle 0\rangle}$和$x^{\langle 1\rangle}$还是零向量,依据softmax预测出的字典中每一个词作为第一个词出现的概率,选取一个词${\hat y}^{\langle 1\rangle}$作为第二个时间步的输入。后面与此类似,模型将自动生成一些句子,从这些句子中可发现模型通过语料库学习到的知识。

以上是基于词汇构建的语言模型,也就是所用的字典中包含的是一个个单词。实际应用中,还可以构建基于字符的语言模型,不过这种方法的结果中将得到过多过长的序列,计算成本也较大,在当今的NLP领域也用得较少。

GRU与LSTM

如下图中的句子时,后面的动词用“was”还是“were”取决于前面的名词“cat”是单数还是复数。
grammer
一般的循环神经网络不擅于捕捉这种序列中存在的长期依赖关系,其中的原因是,一般的循环神经网络也会出现类似于深度神经网络中的梯度消失问题,而使后面输入的序列难以受到早先输入序列的影响。梯度爆炸的问题也会出现,不过可以采用梯度修剪(Gradient Clipping)应对,相比之下梯度消失问题更难以解决。

GRU

GRU(Gated Recurrent Units, 门控循环单元)网络改进了循环神经网络的隐藏层,从而使梯度消失的问题得到改善。GRU的结构如下图:
GRU

其中的$c$代表记忆细胞(Memory Cell),用它来“记住”类似前面例子中“cat”的单复数形式,且这里的记忆细胞$c^{\langle t\rangle}$直接等于输出的激活$a^{\langle t\rangle}$;$\tilde{c}$代表下一个$c$的候选值;$\Gamma_u$代表更新门(Update Gate),用它来控制记忆细胞的更新与否。上述结构的具体表达式有:$$\tilde{c}^{\langle t \rangle} = \tanh(W_c[c^{\langle t-1 \rangle}, x^{\langle t \rangle}] + b_c)$$ $$\Gamma_u = \sigma(W_u[c^{\langle t-1 \rangle}, x^{\langle t \rangle}] + b_u)$$ $$c^{\langle t \rangle} = \Gamma_u \times \tilde{c}^{\langle t \rangle} + (1 - \Gamma_u) \times c^{\langle t-1 \rangle}$$ $$a^{\langle t\rangle} = c^{\langle t\rangle}$$
$\tilde{c}$的计算中以tanh作为激活函数,使用simgoid作为激活函数得到的$\Gamma_u$值将在0到1的范围内。当$\Gamma_u=1$时,输出的$c$值被更新为$\tilde{c}$,否者保持为输入的$c$值。

上面所述的是简化后的GRU,完整的GRU结构如下:
GRU-FULL
其中相关门(Relevance Gate)$\Gamma_r$表示上一个$c$值与下一个$c$的候选值的相关性。与简化的GRU相比,表达式发生如下变化:$$\Gamma_r = \sigma(W_r[c^{\langle t-1 \rangle}, x^{\langle t \rangle}] + b_r)$$ $$\tilde{c}^{\langle t \rangle} = \tanh(W_c[\Gamma_r \times c^{\langle t-1 \rangle}, x^{\langle t \rangle}] + b_c)$$
GRU其实只是一种LSTM的流行变体,其相关概念来自于2014年Cho等人发表的论文[On the properties of neural machine translation: Encoder-decoder approaches]以及Chung等人的[Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling]

LSTM

1997年Hochreiter和Schmidhuber共同在论文[Long short-term memory ]中提出的LSTM(Long Short Term Memory,长短期记忆)网络比GRU更加通用及强大,其结构如下:
LSTM

相比之前的简化版GRU,LSTM中多了遗忘门(Forget Gate)$\Gamma_f$和输出门(Output Gate)$\Gamma_o$,具体表达式如下:$$\tilde{c}^{\langle t \rangle} = \tanh(W_c[a^{\langle t-1 \rangle}, x^{\langle t \rangle}] + b_c)$$ $$\Gamma_u = \sigma(W_u[a^{\langle t-1 \rangle}, x^{\langle t \rangle}] + b_u)$$ $$\Gamma_f = \sigma(W_f[a^{\langle t-1 \rangle}, x^{\langle t \rangle}] + b_f)$$ $$\Gamma_o= \sigma(W_o[a^{\langle t-1 \rangle}, x^{\langle t \rangle}] + b_o)$$ $$c^{\langle t \rangle} = \Gamma_f^{\langle t \rangle} \times c^{\langle t-1 \rangle} + \Gamma_u^{\langle t \rangle} \times \tilde{c}^{\langle t \rangle}$$ $$a^{\langle t \rangle} = \Gamma_o^{\langle t \rangle}\times \tanh(c^{\langle t \rangle})$$

更为常用的LSTM版本中,几个门值的计算不只取决于输入$x$和$a$值,有时也可以偷窥上一个细胞输入的$c$值,这叫窥视孔连接(Peephole Connection)

多个LSTM单元连接在一起,形成一个LSTM网络:
LSTM网络

BRNN与DRNN

前面介绍的循环神经网络在结构上都是单向的,也提到过它们具有某一时刻的预测结果仅使用了该时刻之前输入的序列信息的缺陷,而双向循环神经网络(Bidirectional RNN)弥补了这一缺陷。BRNN的结构图如下所示:
BRNN

此外,循环神经网络的每个时间步上也可以包含多个隐藏层,形成深度循环神经网络(Deep RNN),如下图:
DRNN

参考资料

  1. 吴恩达-序列模型-网易云课堂
  2. Andrew Ng-Sequence Model-Coursera
  3. deeplearning.ai
  4. 零基础入门深度学习-循环神经网络
  5. 课程代码与资料-GitHub

注:本文涉及的图片及资料均整理翻译自Andrew Ng的Deep Learning系列课程,版权归其所有。翻译整理水平有限,如有不妥的地方欢迎指出。


更新历史:

  • 2018.02.27 完成初稿
文章作者: Hugsy
文章链接: http://binweber.top/2018/02/20/deep_learning_9/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Weber
支付宝打赏~
微信打赏~