Recurrent Neural Network

循环神经网络们

Posted by 柠萌 on June 24, 2018

0. 前言

最近在写期末作业,写完了一片小论文,大概就是用一个循环神经网络模型给高光谱影像分类,中间加了一点点小trick之类的。

整个过程中,反而感觉最有价值的是自己总结RNN和他的变体们的结构。在此把论文了的一部分记下来。

循环神经网络(Recurrent Neural Network, RNN)简单来说是指具有循环单元的人工神经网络(Artificial Neural Network)。其实个人感觉RNN并没有很“深度”,所以说RNN是Deep Learning其实有点不太名副其实。而RNN早在上个世纪80年代就已经很多人在做了,而LSTM在90年代也已经被提出了,所以所谓RNN并不是什么新鲜事。

但RNN被认为是有效处理序列数据的模型,他在最主要是在机器翻译中取得的很好的效果,也因此备受关注。

1. RNN

我们说RNN是有循环单元的神经网络,那么什么是循环单元呢?就是像下图所示,那个圈圈就表示一个循环。看不懂?其实他可以展开(unfold)成右边的样子就好懂了。有一个常常听到的说法就是单元在当前时间步的输出不仅和当前输入有关,还和上一次输入有关。

ru 图片来源:零基础入门深度学习(5) - 循环神经网络

说的很玄乎,其实想要理解最好就是看公式啦。

其实下面就是将RNN的循环单元的前向传播过程复述一遍而已啦。

我截一个我写的课程论文里的图来说明。

rnn_math

给定一个序列样本x,这个x其实是一个矩阵,我们将他写出含有m个向量的向量吧,像上面截图说的。 注意这里不是有m个样本哦,而是一个样本就有m个向量,每个向量的先后顺序是固定的,对于一个循环单元他展开后相当于有m个“小单元”,我们不妨称之为时间步(timestep)吧。每个时间步可以有他自己的隐藏状态h。

h怎么算呢?就会式子(1)写得这样。

第0个状态,也就是初始状态要我们自己给定,经验上一般都设定为零向量。然后第t个h可以写成第t个(当前)时间步的输入和第t-1个(上一个)时间步的h的函数。是什么函数?怎么定义都行啦。一般的RNN会把它定义成像式子(3)那样,就是一般的广义线性模型(普通的神经元)。有没有感觉和Markov的感觉很像呢?

但这个h是不输出的,输出的y还会有一个函数对隐藏状态进行处理,其实就是再套一层而已啦,像式子(2)所示,具体到传统RNN就可以写成式子(4)那样。

我们举个例子来再过一次前向传播过程,假设我们观察一个小姐姐,观察她好多天,每天24小时都记下他的表情。我们就可以把每一天当成是一个样本x,这里m=24,xt表示小姐姐今天第t小时的心情。然后我们算h,h0的时候我们就设为0向量,毕竟小姐姐在碎美容觉嘛,然后我们算h1,把1点钟小姐姐的心情x1和h0代入函数h(),算出了h1。然后h1又用来配合x2算出h2,一直算到h24。接下来我想要输出的话,就讲h1到h24代入y(),就可以算出y1到y24,我们不管y到底是表示小姐姐穿的小裙子还是小姐姐的什么,反正算出了个用来输出的值就是了。

把循环单元的结构画成图的话就是像图1这样。是不是很简单?

rnn_graph

如果还不懂,看这张图直接粗暴地画出来传统RNN的整体结构哦。

rnn_3d 图片来源:LSTM神经网络输入输出究竟是怎样的? - Scofield的回答 - 知乎

RNN的求解不是普通的BP算法,用的是BPTT,这里因为懒所以就不写了。

关于RNN的输入输出

一般来说,按照输入输出,RNN解决的问题可以氛围:end2end,end2seq,seq2end,seq2seq。也就是输入输出分别是端(end)和序列(seq)。端就是指单个向量,序列就是只一列向量,但向量与向量之间是有序的。

举几个例子,比如我今天看到一只小姐姐,我把她的皂片(或者是升高,语调等等的特征向量)输入RNN,可以知道这个小姐姐是萝莉还是御姐,这个就是end2end模型。

如果我把她的照片输入RNN,可以知道搭讪这个小姐姐时说什么话最容易勾搭到这个小姐姐,那么这个就是end2seq模型。因为说的话是句子,也就是词语的序列,词语的先后顺序是会影响句子的含义的,所以是一个序列。

如果我把一句话输入到模型得到我能否勾搭上小姐姐得到的就是seq2end模型,同样的,如果我把一句话输入到模型里得到小姐姐回复我会说的话,那就是seq2seq模型。

其实这4个模型对应的应用可以是:图片分类(end2end)、图片概述(对图片生成一句话描述,end2seq)、有序序列分类(如高光谱像元分类,seq2end)、机器翻译与对话机器人(seq2seq)。

四种的输入结构是这样的:

rnn_io

图片截图:[原创翻译]循环神经网络惊人的有效性(上) - 杜客的文章 - 知乎

如果输入是一个序列(seq),我们就在相应时间步输入对应时间的向量,如果输入是一个端(end),我们就在每个时间步都输入同样的向量。如果输出是一个end我们就取最后一次输出(或者是多个时间步输出求平均等),如果输出是一个seq那么我们就将每个时间步的输出做成一个序列就ok了。

2. LSTM

长短时记忆模型(Long Short-Term Memory, LSTM)刚刚提到它在1990年代就被提出了。它最主要就是解决了RNN中的长距离依赖问题(Long-distance Dpendence)。请注意LSTM的英文里,ST是Short-term,而它前面的L代表Long和Short-term是用空格隔开的。

其实我一开始以为LSTM就是又短又长,既能搞定短距离又能记住长距离的,但其实人家的意思是能够持续比较长时间的短期记忆,wiki是这样写的:

The expression long short-term refers to the fact that LSTM is a model for the short-term memory which can last for a long period of time.

LSTM可以解决长距离依赖问题,处理RNN在长序列容易梯度弥散或梯度爆炸的问题,也就是说LSTM能让RNN真正“deep”起来。且不说效果好不好,至少能够“deep”。

所谓长距离依赖就是说当序列变长,RNN就变得无法连接时间步相隔较大的信息,也就是说最开始的输入到了后面就没什么卵用了。

LSTM看似很玄,但只要记住它再强,它始终是一个RNN。他的结构就是下面这样:

lstm

这里的结构和RNN本质是一样的,把黑框看成黑箱子,他们的输入都是前一步的状态h_t-1和当前的输入x_t,只是隐藏状态变成了两个,原来只有一个h,LSTM则有一个c和一个h。c被称为细胞状态,h有点像传统RNN里的y但它同时会参与下一个时间步的输入。

LSTM的内部结构主要是三个“门结构”(gate),包括遗忘门,输入门,输出门。“门”就是一个信息过滤器,也就是选择性地让信息通过一部分,看公式,发现他本质就是一个logistics回归,用了是一个sigmoid函数,其巧妙之处在于它选择性的让过去的信息通过(遗忘门),也选择性地让当前输入进入(输入门)。而sigmoid的值域是0到1,因此,可以把它理解成一个遗忘和记忆的概率。

LSTM的具体理解,请务必看这篇文章,写得实在是太好了:

Understanding LSTM Networks

[译] 理解 LSTM 网络

3. GRU

门循环单元(Gated Recurrent Unit, GRU)是LSTM的变体之一。在实践中,发现GRU参数更少,更容易训练,在某些问题能比LSTM效果更好。至少在高光谱分类中,GRU优于LSTM。

事实上,LSTM那么多变体里面,并没有哪一个是比其他更好,只是各自在不同问题中有不同优势而已。

GRU和LSTM的区别在于,它的隐含状态只有一个h,同时这也是他的对应时间步的输出。对比LSTM的三个门结构,GRU只有更新门和重置门两个门结构,因此其参数也比较少。

gru

4. 双向RNN与多层RNN

RNN往继续拓展的话就有双向RNN和多层RNN。刚刚讲的LSTM和GRU是通过改变循环单元内部结构来改进RNN的。而双向RNN与多层RNN则是堆叠RNN得到一个更大更强的模型。

双向RNN是认为序列信息既与前面的时间步有关,又和后面的时间步有关,因此我正反各输入一次不就可以了吗。至于输出,就是两个RNN的加和。

多层RNN就是有多个隐藏层(隐藏状态h)而已。

下面两图分别是双向RNN和多层RNN的结构图,图源自零基础入门深度学习(5) - 循环神经网络,这篇文章也写得很好,值得一读。

birnn

mulrnn

5. Encoding-Decoding与Attention

Encoding-Decoding在seq2seq的问题中比较有意义。其概念在于用一个编码器(Encoder)给序列编码,得到一个中间向量,再用一个解码器(Decoder)给中间向量解码。

gru

然后有人在Encoding-Decoding中引入了注意力机制(Attention model)。

gru

图片来源:深度学习中的注意力机制

很多时候RNN其实不好计算,因为RNN的输入跟前一时间步有关,因此不好并行,所以很多人开始转向别的模型。如ResNet和Attention模型。

2018.06.24 于广州