算法介绍

<math> <semantics> <mrow> </mrow> <annotation encoding="application&#47;x&#45;tex"> \quad </annotation> </semantics> </math>循环神经网络出现于20世纪80年代,在其发展早期,应用不是特别丰富。最近几年由于神经网络结构的进步和GPU上深度学习训练效率的突破,RNN变得越来越流行。RNN对时间序列数据非常有效,其每个神经元可通过内部组件保存之前输入的信息。
<math> <semantics> <mrow> </mrow> <annotation encoding="application&#47;x&#45;tex"> \quad </annotation> </semantics> </math>人每次思考时不会重头开始,而是保留指甲钳思考的一些结果为现在的决策提供支持。例如我们对话时,我们会根据上下文的信息理解一句话的含义,而不是对每句话重头进行分析。传统的神经网络不能实现这个功能,这可能是其一大缺陷,例如卷积神经网络虽然可以对图像进行分类,但是可能无法对视频中的每一帧图像发生的事情进行关联分析,我们无法利用前一帧图像的信息,而循环神经网络则可以解决这个问题。RNN最大的特点是神经元的某些输出可作为其输入再次传输到神经元中,因此可以利用之前的信息。

<math> <semantics> <mrow> </mrow> <annotation encoding="application&#47;x&#45;tex"> \quad </annotation> </semantics> </math>如图7-4所示,KaTeX parse error: Expected 'EOF', got '\x' at position 1: \̲x̲_t是RNN的输入,A是RNN的一个节点,而 <math> <semantics> <mrow> <msub> <mi> h </mi> <mi> t </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> h_t </annotation> </semantics> </math>ht是输出。我们对这个RNN输入数据 <math> <semantics> <mrow> <msub> <mi> x </mi> <mi> t </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> x_t </annotation> </semantics> </math>xt,然后通过网络计算并得到输出结果 <math> <semantics> <mrow> <msub> <mi> h </mi> <mi> t </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> h_t </annotation> </semantics> </math>ht,再将某些信息(state,状态)传到网络的输入。我们将输出 <math> <semantics> <mrow> <msub> <mi> h </mi> <mi> t </mi> </msub> </mrow> <annotation encoding="application&#47;x&#45;tex"> h_t </annotation> </semantics> </math>ht与label进行比较可以得到误差,有了这个误差以后,我们就可以使用梯度下降和Back-Propagation Through Time(BPTT)方法对网络进行训练,BPTT与训练前馈神经网络的传统BP方法类似,也是使用反向传播求解梯度并更新网络参数权重。另外,还有一种方法叫Real-Time Recurrent Learning(RTRL),它可以正向求解梯度,不过其计算复杂性比较高。此外,还有介于BPTT和RTRL这两种方法之间的混合方法,可以用来缓解时间序列过长带来的梯度弥散问题。
<math> <semantics> <mrow> </mrow> <annotation encoding="application&#47;x&#45;tex"> \quad </annotation> </semantics> </math>如果我们将RNN中的循环展开成一个串联的结构,如图:
就可以更好的理解循环神经网络的结构了。RNN展开后,类似于有一系列输入x和一系列输出h的串联的普通神经网络,上一层的神经网络会传递信息给下一层。这种串联的结构天然就非常适合时间序列数据的处理和分析。需要注意的是,展开后的每一个层级的神经网络,其参数都是相同的,我们并不需要训练成百上千层神经网络的参数,只需要训练一层RNN的参数,这就是它结构的巧妙之处,这里共享参数的思想和卷积网络中权值共享的方式也很类似。
<math> <semantics> <mrow> </mrow> <annotation encoding="application&#47;x&#45;tex"> \quad </annotation> </semantics> </math>RNN虽然被设计成可以处理整个时间序列,但是其记忆最深的还是最后输入的一些信息。而更早之前的信号的强度则越来越低,最后只能起到一点辅助的作用,即决定RNN输出的还是最后输入的一些信号。这样的缺陷导致RNN在早期的作用并不明显,慢慢淡出了大家的视野。而后随着LSTM的发现,循环神经网络重新回到大家的视野,并逐渐在众多领域取得了很大的成功和突破,包括语音识别,文本分类,语音模型,自动对话,机器翻译,图像标注等领域。
<math> <semantics> <mrow> </mrow> <annotation encoding="application&#47;x&#45;tex"> \quad </annotation> </semantics> </math>对于某些简单的问题,可能只需要最后输入的少量时序信息即可解决。但对某些复杂问题,可能需要更早的一些信息,甚至是时间序列开头的信息,但间隔太远的输入信息,RNN是难以记忆的,因此长程依赖是传统RNN的致命伤。LSTM是Schmidhuber教授于1997年提出的,它天生就是为了解决长程问题依赖而设计的,不需要特别复杂地调试超参数,默认就可以记住长期的信息。LSTM的内部结构相比RNN更复杂,如图其中包含了4层神经网络,其中小圆圈是point-wise的操作,比如向量加法,点乘等,而小矩形则代表一层可学习参数的神经网络。LSTM单元上面那条直线代表LSTM的状态state,它会贯穿所有串联在一起的LSTM单元。状态state在这条隧道中传递时,LSTM单元可以对其添加或者删减信息,这些对信息流的修改操作由LSTM的Gates控制。这些Gates中包含了一个Sigmoid层和一个向量点乘的操作,这个Sigmoid层的输出是0到1之间的值,它直接控制了信息传递的比例。如果为0代表不允许信息传递,为1代表允许信息全部通过。每个LSTM单元中包含3个这样的Gates,用来维护和控制单元的状态信息。凭借对状态信息的存储和修改,LSTM单元就可以实现长程记忆。
<math> <semantics> <mrow> </mrow> <annotation encoding="application&#47;x&#45;tex"> \quad </annotation> </semantics> </math>循环神经网络的应用非常广,不过用的最多的地方还是自然语言处理。用RNN训练出的语言模型,其效果令人惊叹。我们可以输入大量莎士比亚的剧本文字等信息给RNN,训练得到的语言模型可以模仿莎士比亚的文字,自动生成类似的诗歌,剧本。
<math> <semantics> <mrow> </mrow> <annotation encoding="application&#47;x&#45;tex"> \quad </annotation> </semantics> </math>语言模型是NLP中非常重要的一个部分,同时也是语音识别,机器翻译和由图片生成标题等任务的基础和关键。语言模型是一个可以预测语句的概率模型。规定上下文的语境,即历史出现的单词,语言模型可以预测下一个单词出现的概率。Penn Tree Bank(PTB)是在语言模型中经常使用的的一个数据集,它的质量比较高,可以用来评测语言模型的准确率,同时数据集不大,训练也比较大,接下来就使用LSTM实现一个语言模型。

算法步骤