循环序列模型(RNN)

为什么选择序列模型

序列模型可以用于处理序列数据。序列数据的例子有
循环序列模型(RNN)
在语音识别中,输入的是语音序列,输出的是对应的句子。
在音乐生成中,输入的是音乐风格或者无,输出的是音乐序列。
在感情分类中,输入的是带有感情的句子,输出的是个人对电影的评价。
在DNA序列分析中,输入DNA片段,输出的是DNA片段对应的名字。
在机器翻译中,输入翻译内容,输出翻译结果。
在视频动作识别中,输入视频序列,输出人物动作。
在名字实体识别中,输入一句话,输出句子中的名字实体。

可以看到许多应用的数据都是序列数据,序列模型有许多广泛的应用。

数学符号

首先设定序列模型中使用的数学符号。

有一个自然语言处理的例子:识别出句子中的人名。输入x为:”Harry Potter and Hermione Granger invented a new spell.”。输出y应该是:1 1 0 1 1 0 0 0 0。1表示单词是人名,0表示单词不是人名。对于”Harry”和”Potter”,要识别出这两个人名单词是连在一起的。使用上标<t>来表示句子中第t个单词。例如x<1>表示”Harry”,y<1>表示”Harry”是人名单词。Tx表示句子的单词数量,在这个例子中是9。

表示句子中的单词的方式是,首先建立一个词典,记录数据中所有出现的单词,该词典可以组成一个词典向量,单词所处的位置置为1,其他元素置为0,这样每个单词可以使用一个向量表示,如下图所示
循环序列模型(RNN)
这个词典的数据比较大,可能有10000个单词。一般词典的单词数能够到达30000到50000,商用的词典可能达到百万级以上。如果某个单词没有收录到词典中,就设置词典的UNK标志为1(未知单词)。

循环神经网络RNN模型

对于上述的名字实体识别例子,使用标准神经网络是不可行的,因为直接输入x=(x<1>,,x<9>),输出y=(y<1>,,y<9>),9不是固定的,不适合所有的样本。每个样本中的单词数不同,输出的结果也就不同。而且,标准神经网络不能够共享文本在不同位置的特征。

循环神经网络可以解决上面的两个缺点。循环神经网络的结构如下
循环序列模型(RNN)
在第1时间步,首先输入x<1>,判断x<1>是否是人名,输出y<1>。然后第2时间步,输入x<2>,同时输入上一时间步中计算的a<1>,计算出y<2>。如此类推,直到计算最后一个x<Ty>。循环神经网络是根据输入的x<t>和上一时间步计算的a<t1>来判断单词x<t>是否是人名。这相当于通过上下文的上文来判断单词是否是人名。开始的a<0>是一个全0的向量,x的参数是Wax,a的参数是Waa,计算y的参数是Wya。在每个时间步,参数都是相同的。

循环神经网络结构的另外一种画法是
循环序列模型(RNN)
可以看出循环神经网络有循环的结构。

前向传播

循环序列模型(RNN)
计算第1时间步的a<1>

a<1>=g1(Waaa<0>+Waxx<1>+ba)

其中**函数g1一般是tanh函数。

计算y<1>

y<1>=g2(Wyaa<1>+by)

其中**函数g2一般是ReLU函数。

一般化后

a<t>=g1(Waaa<t1>+Waxx<t>+ba)y<t>=g2(Wyaa<t>+by)

简化上述的公式,把WaaWax合并起来
循环序列模型(RNN)
所以

a<t>=g1(Wa[a<t1>,x<t>]+ba)y<t>=g2(Wya<t>+by)

损失函数

循环神经网络的损失函数就是softmax的损失函数,公式如下

l(y^<t>,y<t>)=iyi<t>log(y^i<t>)

一个样本的损失函数为
l(y^,y)=t=1Tyl(y^<t>,y<t>)

不同类型的循环神经网络

前面所说的名字实体识别例子Tx=Ty,但是其他序列数据应用TxTy。循环神经网络就分为多种类型。
第一种,多对多类型。多对多类型又分为两种情况,第一种情况Tx=Ty
循环序列模型(RNN)
第二种情况TxTy
循环序列模型(RNN)

第二种,一对一类型。
循环序列模型(RNN)

第三种,多对一类型。
循环序列模型(RNN)

第四种,一对多类型。
循环序列模型(RNN)

语言模型和序列生成

什么是语言模型?在语言识别中,输入一句话,语言模型输出语言的内容是”The apple and pair salad.”的概率是多少,是”The apple and pair salad.”的概率是多少。

假设有一个很大的语料库,对于其中一个样本”Cats average 15 hours of sleep a day.”,首先对其进行标志化。在样本的末尾添加一个语句结束符<EOS>。然后把每个单词映射成词典向量,即”Cats average 15 hours of sleep a day. <EOF>”映射成y<1>,,y<9>

在RNN模型中
循环序列模型(RNN)
在第1时间步,输入的x<1>是0向量,这一时间步是用来预测词典中每个单词是句子开头的概率。接着第2时间步,输入的是第一个单词,然后预测词典中每个单词是第二个单词的概率。第一时间步输出的是第一个单词,所以在第二时间步中x<2>=y<1>。到最后一个时间时间步,输入的是最后一个单词x<9>=y<8>,计算句子的结束符的概率。在语言识别RNN中,损失函数和名字实体识别一样使用softmax损失函数。

新序列采样

为了理解语言模型RNN学习了什么,我们在训练得到的模型进行采样,观察最后采样得到什么结果。
循环序列模型(RNN)
这是一个训练好的RNN模型,把x<1>=0输入到第1时间步中,得到y^<1>y^<1>表示词典中每个单词作为句子开头的概率。我们根据y^<1>的概率分布从词典中采样(np.random.choice),采集作为句子开头的单词,比如说”the”。然后把x<2>=y^<1>输入到第2时间步中,得到y^<2>y^<2>表示在第一个单词是”the”的情况下词典的单词出现的概率。同样根据y^<2>在词典中采样。直到最后采样得到<EOF>时结束采样。如果要避免采样得到的单词中出现<UNK>,可以在采样到<UNK>时,在剩下的单词中重新采样。

最后把采样得到的单词按照顺序组合成句子。这些句子表示这个RNN模型序列学习到了什么。下图是对一个从新闻库中训练得到的语言模型进行采样后得到的句子。
循环序列模型(RNN)
这些句子很像新闻报道的风格。

上面演示的是基于单词的序列模型,还有基于字符的序列模型。基于字符的序列模型的词典中的项数量少,包括所有大小写字母、空格和标点符号等。但是基于字符的序列模型能够组成的序列比基于单词的序列模型要多得多。

RNN的梯度消失

有两个句子,”The cat, which …, was full”和”The cats, which …, were full”。要根据”cat”的单复数形式选择”was”还是”were”,但是RNN很难做到这一点。
循环序列模型(RNN)
这两个句子中间一段可能很长,在RNN模型,句子末尾的”was/were”很难通过反向传播反馈到前面的”cat”。因此,在RNN中,首要解决的问题是梯度消失和梯度爆炸问题。梯度爆炸问题可以使用梯度修剪来解决,梯度消失问题可以使用GPU或LSTM来解决。

梯度修剪是把梯度限制在一定的范围之内[N,N],N是设置的最大值。梯度修剪的效果如下图所示
循环序列模型(RNN)

GRU

门控循环单元(Gated Recurrent Unit, GRU)可以解决RNN的梯度消息问题。

GRU使用记忆细胞(用c表示)来记忆RNN靠前的时间序上的知识,比如记忆”cat”是单数还是复数,这个记忆一直保存到靠后的时间序中,可以让后面的时间步从较前的时间步中学习到东西。这里记忆细胞c<t>作为a<t>

在每个时间步中,计算一个新的记忆细胞c~<t>

c~<t>=tanh(Wc[c<t1>,x<t>]+bc)

使用一个门控开关Γu,控制是否更新记忆细胞
Γu=σ(Wu[c<t1>,x<t>]+bu)

其中σ表示sigmoid函数。更新记忆细胞
c<t>=Γuc~<t>+(1Γu)c<t1>

如果Γu=1,表示更新记忆细胞;如果Γu=0,表示保留旧的记忆细胞。

GRU的结构如下图所示
循环序列模型(RNN)

对于”The cat, which …, was full”这个句子,GRU的RNN可以记住cat是单数还是复数了。
循环序列模型(RNN)
只要Γu=0,记忆cat的单复数形式的记忆细胞c就可以传递到”was”的位置。

当然,Γu数值上不可能为0或1,但是可以非常接近0或1。当Γu=0.00001时,c<t>c<t1>,这时梯度不会衰减,这就可以解决梯度消失的问题。

完全的RGU还有一个参数Γr,表示新的记忆细胞和旧的记忆细胞的相关性。完全RGU公式如下

Γr=σ(Wr[c<t1>,x<t>]+br)c~<t>=tanh(Wc[Γrc<t1>,x<t>]+bc)Γu=σ(Wu[c<t1>,x<t>]+bu)c<t>=Γuc~<t>+(1Γu)c<t1>

LSTM

长短期记忆(long short term memory, LSTM)是比GRU更加常用,更加经典的RNN构件。
LSTM单元的结构如下:
循环序列模型(RNN)

具体过程如下:
计算新记忆细胞

c~<t>=tanh(Wc[a<t1>,x<t>]+bc)

计算更新门
Γu=σ(Wu[a<t1>,x<t>]+bu)

计算忘记门
Γf=σ(Wf[a<t1>,x<t>]+bf)

计算输出门
Γo=σ(Wo[a<t1>,x<t>]+bo)

更新记忆细胞
c<t>=Γuc~<t>+Γfc<t1>

计算输出
a<t>=Γotanh(c<t>)

把几个LSTM单元连在一起
循环序列模型(RNN)
可以看到,记忆细胞可以顺着红线传递下去。

BRNN

BRNN(Bidirectional RNN)比RNN多了循环一个方向,如下图
循环序列模型(RNN)
在名字实体识别应用中,RNN是从句子的开头开始识别单词,RNN能够通过上文来识别单词是否是名字。但是有些时候,判断单词是否是名字需要下文的知识。BRNN是一个双向网络,它即会从头到尾扫描句子,也会从尾到头扫描句子,这样相当于从句子的上下文来判断单词是否是名字,这样判断的效果更加精确。

BRNN首先计算前向循环的所有a值,接着计算反向循环的所有a值,接着,使用aa计算y^值,公式如下

y^<t>=g(Wy[a<t>,a<t>]+by)

在BRNN中同样可以使用GRU和LSTM构件。

深层RNN

像深层神经网络,RNN也可以有更深的网络层
循环序列模型(RNN)
上图的RNN在时间维上使用3层网络层,考虑到RNN有时间步数,3层网络层对于RNN已经非常大了,足以用来学习非常复杂的函数。也可以加深y^的输出,注意,为y^加深的网络层在时间上没有联系。