一、前言
1.为什么需要RNN?
以订票系统的填空(slot filling)为例,比如一个智慧订票系统,往往需要slot filling技术。
假设订票系统需要根据人说的话得到两个slot:目的地
和到达时间
。
这个问题我们首先想到可以用全连接网络(FNN:FeedForword Neural Network)来解决。这个全连接网络的输入是一个词汇,比如把台北变为一个Embedding(OneHot、N-gram、Word2vec)输入到神经网络里。然后希望输出是一个概率,即属于所有slot的几率。
如果有两个输入:
arrive Taipei on November 2nd
leave Taipei on November 2nd
对于全连接神经网络来说,输入一样,输出也会一样。输入Taipei
,要么输出是目的地
的几率最高,要么是出发地
的几率最高,没有办法有时候让目的地
的几率最高,有时候让出发地
的几率最高,怎么办呢?
这个时候,我们就希望神经网络是有记忆力的。
如果神经网络是有记忆力的,它会记得在看到红色Taipei
这个词之前,就已经看过arrive
这个词汇;它会记得在看到绿色Taipei
这个词之前,就已经看过leave
这个词汇。它会根据这段话的上下文,产生不同的输出。
如果神经网络是有记忆力的,这样就可以解决输入同样的词汇,但是输出必须不同这个问题。那么这种有记忆力的神经网络,就叫做Recurrnt Neural Network(RNN)。
二、RNN原理
1.简要概括:每次前向神经网络里的隐藏层的神经元产生输出(下图中的a1a1和a2a2)后,都会被存到memory中去,然后当下一个input输入后,隐藏层的输入不仅仅考虑x1x1和x2x2,还会考虑上一次的隐藏层输出存在memory中的值。
2.具体原理
假设如下图所示的所有权值都是1,所有的神经元都没有bias,假设所有的激活函数都是线性的,假设input是sequence,具体值如下图中所示,假设memory的初始值是0。
然后如下图所示隐藏层的值2被写到memory中,接下来再输入第二个单词的embedding,那么隐藏层的输入有四个,加权的结果是6,输出的结果也是6。
由上图可以看出,输入是一样的,但是输出是可能不一样的,因为存在memory中的值是不一样的。
接下来,如下图所示上图中隐藏层的输出6就会被存到memory中去,memory中的值就由2变为6。隐藏层的输入有四个(6+6+2+2=16),所以隐层的输出就是16。
所以因为memory的存在,任意调换sequence的顺序,那么输出就会不一样。比如把sequence的最后一个单词挪到最前面去,则输出是会完全不一样的。所以,RNN会考虑输入的seqence的顺序。
3.举例:订票系统
上面并不是三个网络,而是同一个神经网络,是同一个网络在三个不同的时间点被使用了三次。
所以,有了memory以后,我们希望输入同一个词汇,输出不同的概率这个问题,就有可能解决。
如下图所示,同样是输入Taipei
,但是因为红色Taipei
前面接leave
,绿色Taipei
前面接arrive
,因为leave
和arrive
它们的embedding不一样,所以隐层的输出也会不同,存在memory里面的值也会不同。所以虽然现在两个x2x2是一模一样的,但是因为存在memory里面的值不同,所以隐层的输出就会不一样,所以最后的输出也就会不一样。
三、RNN的多种架构
1、多层Deep的RNN
2、ELman和Jordan网络结构
前面第二段落我们讲的都是Elman网络架构,Jordan网络往memory中存的是output的值。Jordan网络可以得到比较好的性能,因为Elman网络的隐藏层是没有target的,比较难控制它学到了什么信息,但是Jordan网络的输出y是有target的,可以对放在memory中的是什么东西比较清楚的。
3、双向RNN
RNN的读取方向不仅可以是按照句子的顺序,也可以是反过来的。
可以同时train一个正向的RNN和逆向的RNN,然后把两个RNN的隐藏层都拿出来接给一个输出层,得到最后的输出y。
用双向RNN的好处,就是网络产生输出的时候,看的范围比较广。如果只有正向的RNN,在产生yt+1yt+1的时候,网络只看过x1x1一直到xt+1xt+1,但是如果是双向的RNN,在产生yt+1yt+1的时候,网络不只是看过x1x1一直到xt+1xt+1,也看了从句尾一直到xt+1xt+1。就是说,网络是看了整个sequence后,才决定输出是什么,会比只看句子的一半得到更好的性能。
四、总结
1、关于RNN的梯度消失问题
梯度下降算法找到成本函数的全局最小值,该函数将成为网络的最佳设置。信息通过神经网络从输入神经元传播到输出神经元,而误差则通过网络计算并传播回以更新权重。
它对 RNN 的工作方式非常相似,但在这里我们还有更多工作要做。
- 首先,信息在 RNN 中随时间传播,这意味着来自先前时间点的信息被用作下一个时间点的输入。
- 其次,您可以计算每个时间点的成本函数或误差。
基本上,在训练期间,成本函数会将您的结果(下图中的红色圆圈)与所需的输出进行比较。因此,对于这些红色圆圈中的每一个,整个时间序列中都有这些值。
计算成本函数 et,现在通过网络将成本函数传播回去更新权重。从本质上讲,参与计算输出的每个神经元(与此成本函数相关)都应该更新其权重,以最大程度地减少该误差。RNN 的问题在于,不仅这个输出层正下方的神经元做出了贡献,而且很久以前的所有神经元都做出了贡献。所以,必须一直传播到这些神经元。
问题与更新 wrec (权重循环) 有关——在展开的时间循环中用于将隐藏层连接到自身的权重。例如,为了从 xt-3 到 xt-2,我们将 xt-3 乘以 wrec。然后,为了从 xt-2 到 xt-1,我们再次将 xt-2 乘以 wrec。因此,我们将相同的精确权重乘以多次,这就是问题所在:当您将某物乘以一个小数时,值会很快减小。
正如我们所知,在神经网络开始时为权重分配了接近于零的随机值,然后网络从那里对其进行训练。但是,当你从接近零的 wrec 开始,然后乘以 xt、xt-1、xt-2、xt-3、...按此值,您的梯度会随着每次乘法而变得越来越小。
这对网络意味着什么?
梯度越低,网络更新权重的难度就越大,获得最终结果所需的时间就越长。例如,1000 个 epoch 可能足以获得时间点 t 的最终权重,但由于此时的梯度非常低,因此不足以训练时间点 t-3 的权重。然而,问题不仅在于一半的网络没有得到适当的训练。早期层的输出用作后续层的输入。因此,时间点 t 的训练始终基于来自未训练层的输入进行。因此,由于梯度消失,整个网络没有得到适当的训练。
综上所述,如果 wrec 很小,则存在梯度消失问题,如果 wrec 很大,则存在梯度爆炸问题。对于梯度消失问题,在网络中走得越远,梯度越低,训练权重就越困难,这会对整个网络中的所有进一步权重产生多米诺骨牌效应。