1、为什么要使用RNN?
如果你翻开任何一本介绍RNN的书籍,他一定会提及RNN是一种用来处理序列数据的神经网络,但是为什么RNN适合用于处理序列类型的数据而一般的神经网络不适合呢?
让我们先看个例子:现在我们要设计一个实体命名识别系统,输入语句为:"Harry Potter and Herminoe Granger invented a new spell.",现在要从中识别出人名。
如果使用一般的神经网络,常用的做法是先将各个单词转化为onehot向量,然后将其输入神经网络中对各个单词进行预测。这种做法虽然可行,但是有两个问题:
(1)输入和输出在不同例子中可以有不同的长度,不是所有的例子都有着同样的输入长度Tx或是同样的输出长度Ty。而且即便每个句子都有最大长度,你能够通过填充来使得每个输入句子都达到最佳长度,这看起来仍然不够优雅。
(2)一个简单的神经网络不能共享从文本不同位置上学到的特征。具体来说,如果神经网络已经学习到了在位置1出现的Harry可能是人名的一部分,那么如果Harry出现在其他位置,网络也能自动将其识别为人名的一部分的话,就非常好了。这可能与卷积神经网络中的参数共享有些许相似。使用(循环神经网络)这样一种更好地方式能有效地减少模型中的参数数量。
2、从RNN说起
一个简单的循环神经网络(RNN)如下图所示:
继续以上面的例子来讲,上图中RNN网络的输入x1,x2,x3, ... 便是对应着各个单词的onehot向量,每个单词输入网络后都可以有一个输出,预测此单词是否是人名。此外,上图所展示的只是RNN中的一种多对多,即多个输入对多个输出,除这种方式的RNN外,还有多对一(如情感分类),一对多(如音乐生成)等多种RNN形式,但这不在本文的讨论范围内,若有兴趣,可自行查找资料。
在上面RNN网络图中原始数据x和网络前面的输出a输入到黑框内先与对应系数相乘然后经过一个激活函数,常见的激活函数为tanh,当然sigmoid函数也是可以的。而每个黑框的输出y是由黑框输出a在经过一个激活函数得到的,这个激活函数可以是sigmoid,也可以是softmax。
3、GRU
在上面的一般RNN中,其每个单元都是一个简单的激活函数单元(如下图),这样的话,RNN就会出现一个一般神经网络都存在的问题——梯度消失和梯度爆炸。
梯度爆炸比较好解决,我们可以通过梯度裁剪来将过大的梯度限制到特定大小。如果学过卷积神经网络(CNN)的话,那你一定了解过CNN中的解决梯度消失的一个经典单元——Resnet中的跳跃连接(skip connection),通过一根支线将一个block的输入直接与输出相加,以解决梯度消失问题。那么在RNN中是否可以采用类似的方式来避免梯度消失呢,答案是肯定的。GRU便是一个具有如此结构单元的网络。
一个简化的GRU单元如下所示:
如上,相比于传统的RNN基础单元,GRU单元多了个激活函数(这里称之为更新们 ),更新门 决定是否要使用这个单元的输入(x)来更新输出c(或a):当 =0时,c(t)=c(t-1), 也即不更新输入,而当 =1时,这时候其实就是相当于传统的RNN单元了。简单说就是 越小,代表本单元输入所得结果占的比例越小,表示不更新;而 越大表示此单元之前的所有RNN的输出c(t-1)所占的比例越大,表示更新。
当然在实际应用中不会真的等于 0 或者 1,有时候它是 0 到 1 的一个中间值(上图编号 5 所示),但是这对于直观思考是很方便的,就把它当成确切的 0,完全确切的 0 或者就是确切的 1。元素对应的乘积做的就是告诉 GRU 单元哪个记忆细胞的向量维度在每个时间步要做更新,所以你可以选择保存一些比特不变,而去更新其他的比特。比如说你可能需要一个比特来记忆猫是单数还是复数,其他比特来理解你正在谈论食物,因为你在谈论吃饭或者食物, 然后你稍后可能就会谈论“The cat was full.”, 你可以每个时间点只改变一些比特。
上面的图表示的是一个简化的GRU单元,对于完整的 GRU 单元我要做的一个改变就是在我们计算的第一个式子中给记忆细胞的新候选值加上一个新的项,我要添加一个门(下图编号 1 所示),你可以认为代表相关性( relevance)。这个门告诉你计算出的下一个<>的候选值̃<>跟<−1>有多大的相关性 。
4、LSTM
在上面我们看到GRU单元比传统RNN单元多了两个门即更新门和相关门。而LSTM即长短时记忆网络(long short term memory)是比GRU更加强大和通用的版本。
从上面可以看出,相比于GRU单元,LSTM单元更为复杂,它包括两个传给后面单元的输出和三个门。
LSTM中每个单元传给后面单元的两个输出中的c(t)与GRU的c(t)计算非常相似,只是一个门变成了两个门。而a(t)则是由c(t)与输出门相乘得到。
更新门,遗忘门,以及输出门。由c(t)的计算式可看出,GRU的更新门的功能在LSTM中由更新门和遗忘门进行了替代,更新门决定了本单元输入x计算所得值占本单元输出的比例,而遗忘门则是决定了前面单元输出在本单元输出中的比例。而输出门则是c(t)的系数,决定了a(t)的大小。此外,LSTM没有了GRU中的相关门。最后,可以看到,无论是GRU还是LSTM中的各个门的计算公式都是一样的,只是其系数大小不同(系数矩阵维度都相同)。
参考:
Andrew Ng的深度学习课程.