递归神经网络(RNN)是流行的模型,在许多NLP任务中表现出很大的希望。 但是,尽管他们最近受欢迎,但我发现只有有限数量的资源可以解释RNN如何工作以及如何实施它们。 这就是本教程的内容。 这是一个多部分系列,我计划在其中涵盖以下内容:
作为教程的一部分,我们将实现基于递归神经网络的语言模型。语言模型的应用是双重的:首先,它允许我们根据它们在现实世界中发生的可能性来评分任意句子。 这为我们提供了语法和语义正确性的衡量标准。 这些模型通常用作机器翻译系统的一部分。其次,语言模型允许我们生成新文本(我认为这是更酷的应用程序)。 在莎士比亚上训练语言模型可以让我们生成类似莎士比亚的文本。Andrej Karpathy的这篇有趣的文章演示了基于RNN的字符级语言模型能够实现的功能。
我假设你对基本的神经网络有些熟悉。 如果你不是,你可能想要从头开始实施一个神经网络,它将引导你完成非经常性网络背后的想法和实现。
RNN背后的想法是利用序列信息。 在传统的神经网络中,我们假设所有输入(和输出)彼此独立。 但对于许多任务而言,这是一个非常糟糕的主意。 如果你想预测句子中的下一个单词,你最好知道它前面有哪些单词。RNN被称为循环,因为它们对序列的每个元素执行相同的任务,输出取决于先前的计算。考虑RNN的另一种方式是它们有一个“记忆”,它可以捕获到目前为止计算的信息。 理论上,RNN可以利用任意长序列中的信息,但实际上它们仅限于回顾前面几个步骤(稍后将详细介绍)。 这是典型的RNN的样子:
递归神经网络和计算时间的展开涉及其正向计算。 来源:自然
上图显示了RNN正在展开(或展开)到完整网络中。 通过展开我们只是意味着我们为整个序列写出网络。 例如,如果我们关心的序列是5个单词的句子,则网络将展开为5层神经网络,每个单词一个层。 相关计算的公式如下:
这里有几点需要注意:
RNN在许多NLP任务中取得了巨大成功。 在这一点上,我应该提到最常用的RNN类型是LSTM,它在捕获长期依赖性方面要比vanilla RNN好得多。 但不要担心,LSTM与我们将在本教程中开发的RNN基本相同,它们只是采用不同的方式来计算隐藏状态。 我们将在稍后的文章中更详细地介绍LSTM。 以下是RNP在NLP中的一些示例应用(绝不是详尽的列表)。
给定一系列单词,我们想要预测给定前一个单词的每个单词的概率。语言模型允许我们测量句子的可能性,这是机器翻译的重要输入(因为高概率句子通常是正确的)。能够预测下一个单词的副作用是我们得到一个生成模型,它允许我们通过从输出概率中抽样来生成新文本。根据我们的训练数据,我们可以生成各种各样的东西。在语言建模中,我们的输入通常是一系列单词(例如编码为单热矢量),我们的输出是预测单词的序列。在训练网络时,我们设置 ot=xt+1 o t = x t + 1 ,因为我们希望步骤t的输出是实际的下一个字。
关于语言建模和生成文本的研究论文:
机器翻译类似于语言建模,因为我们的输入是源语言中的一系列单词(例如德语)。 我们希望以目标语言输出一系列单词(例如英语)。 一个关键的区别是我们的输出仅在我们看到完整输入后才开始,因为我们翻译的句子的第一个单词可能需要从完整的输入序列中捕获的信息。
RNN for Machine Translation. Image Source: 来源:点击这
关于机器翻译的研究论文:
给定来自声波的声学信号的输入序列,我们可以预测一系列语音片段及其概率。
关于语音识别的研究论文:
-Towards End-to-End Speech Recognition with Recurrent Neural Networks
与卷积神经网络一起,RNN已被用作模型的一部分,以生成未标记图像的描述。 令人惊讶的是,这看起来有多好。 组合模型甚至将生成的单词与图像中找到的特征对齐。
Deep Visual-Semantic Alignments for Generating Image Descriptions. Source: http://cs.stanford.edu/people/karpathy/deepimagesent/
训练RNN与训练传统神经网络类似。 我们也使用反向传播算法,但有点不同。 由于参数由网络中的所有时间步骤共享,因此每个输出的梯度不仅取决于当前时间步长的计算,还取决于先前的时间步骤。例如,为了计算t = 4处的梯度,我们需要反向传播3个步骤并总结梯度。 这称为反向传播时间(BPTT)。如果这还没有弄懂细节,请不要担心,我们将在血腥细节上发表一篇文章。现在,请注意由于所谓的梯度消失/爆炸问题,使用BPTT训练的vanilla RNN难以学习长期依赖性(例如相距很远的步骤之间的依赖性)。存在一些处理这些问题的机制,并且某些类型的RNN(如LSTM)专门用于绕过它们。
多年来,研究人员开发了更复杂的RNN类型,以解决vanilla RNN模型的一些缺点。 我们将在稍后的文章中更详细地介绍它们,但我希望本节作为简要概述,以便您熟悉模型的分类。
双向RNN基于以下思想:时间t处的输出可能不仅取决于序列中的先前元素,还取决于未来元素。 例如,要预测序列中缺少的单词,您需要查看左侧和右侧上下文。 双向RNN非常简单。 它们只是两个堆叠在一起的RNN。 然后基于两个RNN的隐藏状态计算输出。
深度RNN类似于双向RNN,只是我们现在每个时间步有多个层。 在实践中,这为我们提供了更高的学习能力(但我们还需要大量的训练数据)。
LSTM networks 这些天很受欢迎,我们在上面简要介绍了它们。 LSTM与RNN没有根本不同的架构,但它们使用不同的函数来计算隐藏状态。LSTM中的memery称为单元格,您可以将它们视为黑箱,将前一个状态 ht−1 h t − 1 和当前输入 xt x t 作为输入。在内部,这些单元格决定要保留什么(以及从中擦除什么)memery。然后,它们组合先前的状态,当前内存和输入。 事实证明,这些类型的单元在捕获长期依赖性方面非常有效。LSTM在开始时可能会非常混乱,但如果您有兴趣了解更多这篇文章有一个很好的解释。
到现在为止还挺好。 我希望您已经对RNN是什么以及它们可以做什么有了基本的了解。 在下一篇文章中,我们将使用Python和Theano实现我们语言模型RNN的第一个版本。 请在评论中留下问题!