递归神经网络简介

titlegetatitle 2018-05-23

递归神经网络简介

介绍

人类每秒钟不从头开始他们的想法。当你读这篇文章的时候,你会根据你对之前单词的理解来理解每个单词。你不会把所有的东西都扔掉,然后重新开始思考。你的想法有持久性。

传统的神经网络不能这样做,这似乎是一个很大的缺点。例如,假设您想要对电影中的每一个点进行分类。目前还不清楚传统的神经网络是如何利用其对电影中发生的事件的推理来为后来的事件提供信息。

递归神经网络解决了这个问题。它们是具有循环的网络,允许信息持续。

递归神经网络简介

在上面的图中,神经网络A,查看一些输入xt并输出一个值ht。循环允许信息从网络的一个步骤传递到下一个步骤。一个递归的神经网络可以被认为是同一个网络的多个副本,每一个都传递一个消息给一个继任者。考虑一下如果我们展开循环会发生什么:

递归神经网络简介

这种链式性质揭示了递归神经网络与序列和列表密切相关。它们是用于这种数据的神经网络的自然架构。而且他们当然可以使用!在过去的几年中,RNN应用于各种问题取得了令人难以置信的成功:语音识别,语言建模,翻译,图像字幕......这个名单还在继续。

什么是递归神经网络

Vanilla 神经网络(以及卷积网络)的显着局限在于它们的API太受限制:它们接受固定大小的向量作为输入(例如图像)并产生固定大小的向量作为输出(例如,不同类别的概率)。不仅如此:这些模型使用固定数量的计算步骤(例如模型中的层数)执行此映射。

递归网络更令人兴奋的核心原因是它们允许我们对向量序列进行操作:输入、输出或最一般情况下的序列。

一些例子可能会使这个更具体:

递归神经网络简介

每个矩形是一个矢量,箭头表示功能(例如矩阵乘法)。输入矢量为红色,输出矢量为蓝色,绿色矢量为RNN状态(稍后会详细介绍)。从左到右:

  1. 不含RNN的Vanilla模式,从固定尺寸输入到固定尺寸输出(如图像分类)。

  2. 序列输出(例如图像字幕拍摄图像并输出一个单词的句子)。

  3. 序列输入(例如,一个给定句子被分类为表达正面或负面情绪的情绪分析)

  4. 序列输入和序列输出(例如,机器翻译:一个RNN读取英文句子,然后输出法文句子)。

  5. 同步序列输入和输出(例如,我们希望标记视频的每个帧的视频分类)。

我们稍后会看到,RNN将输入向量与它们的状态向量组合起来,形成一个固定的(但是学习到的)函数,以产生一个新的状态向量。

RNN计算

那么这些事情是如何工作的?

他们接受一个输入矢量x并给出一个输出矢量y。然而,关键的是,这个输出向量的内容不仅受到刚刚输入的输入的影响,还受到过去输入的整个历史记录的影响。作为一个类编写,RNN的API由一个单步功能组成:

rnn = RNN()

y = rnn.step(x) # x is an input vector, y is the RNN’s output vector

RNN类具有一些内部状态,每次调用该步时都会进行更新。在最简单的情况下,这个状态由单个隐藏向量h组成。下面是Vanilla RNN中step函数的实现:

class RNN:

# ...

def step(self, x):

# update the hidden state

self.h = np.tanh(np.dot(self.W_hh, self.h) + np.dot(self.W_xh, x))

# compute the output vector

y = np.dot(self.W_hy, self.h)

return y

这个RNN的参数是三个矩阵。

  • W_hh :基于前一个隐藏状态的矩阵。

  • W_xh:基于当前输入的矩阵。

  • W_hy:基于隐藏状态和输出的矩阵。

隐藏状态self.h用零矢量初始化,np.tanh(双曲正切)函数实现了一个非线性,它将激活的范围压缩到范围[-1,1]。

所以它是如何工作的 -

tanh中有两个术语:一个基于前一个隐藏状态,另一个基于当前输入。在numpy中,np.dot是矩阵乘法。

隐藏状态更新的数学表示法是

递归神经网络简介

tanh在元素上应用

我们用随机数来初始化RNN的矩阵,在训练过程中大量的工作是为了找到产生理想行为的矩阵,用一些损失函数来表示你倾向于你想要看到的输出你想看到的输出序列x。

更深一步

y1 = rnn1.step(x)

y = rnn2.step(y1)

换句话说,我们有两个独立的RNN:一个RNN正在接收输入矢量,第二个RNN正在接收第一个RNN的输出作为其输入。除了这些RNNs都不知道或不在乎 - 这些都只是进出的矢量,并且在反向传播期间有些梯度会流经每个模块。

我想简单地提一下,在实践中,我们大多数人使用的方式与上面提到的长期短期记忆(LSTM)网络略有不同。LSTM是一种特殊类型的循环网络,由于其更强大的更新方程和一些吸引人的后向传播动态,在实践中效果稍好。我不会详细讨论,但我所说的有关RNN的所有内容都保持完全相同,除了计算更新的数学形式(self.h = ...)会稍微复杂一些。从这里开始,我将交替使用术语“RNN / LSTM”,但本文中的所有实验均使用LSTM。

一个例子 - 字符级语言模型

我们将训练RNN字符级语言模型。也就是说,我们会给RNN一大块文本,并要求它给出一系列先前字符序列中下一个字符的概率分布。这将允许我们一次生成一个新字符。

作为一个工作示例,假设我们只有四个可能的字母“helo”的词汇表,并且希望在训练序列“hello”上训练一个RNN。这个训练序列实际上是4个独立训练样例的来源:

  1. 在“h”的情况下,“e”的概率应该是可能的,

  2. “l”应该可能在“he”的范围内

  3. “l”也应该是可能的,因为“hel”

  4. “o”应该是可能的,因为“hell”

具体而言,我们将使用1-k编码将每个字符编码为一个矢量(即,除词汇表中字符索引处的单个字符以外的所有零),然后使用帮助一次将它们送入RNN的一个步骤功能。然后,我们将观察一系列4维输出向量(每个字符一个维度),我们将其解释为RNN当前分配给序列中接下来每个字符的置信度。这是一张图表:

递归神经网络简介

例如,我们看到,在RNN看到字符“h”的第一个时间步中,它给1.0的下一个字母为“h”,2.2为字母“e”,-3.0至“l”和4.1到“o”。由于在我们的训练数据(字符串“hello”)中,下一个正确的字符是“e”,我们希望增加其信心(绿色)并降低所有其他字母(红色)的置信度。同样,我们希望网络能够给予更大的信心,我们在4个时间步骤中的每一个步骤都有所需的目标角色。

由于RNN完全由可微分操作组成,因此我们可以运行反向传播算法(这只是递归应用来自演算的链式规则),以找出我们应该调整其每一个权重的方向,以增加分数正确的目标(绿色粗体数字)。

然后,我们可以执行参数更新,在这个梯度方向上轻轻推动每个权重。如果我们在参数更新之后向RNN提供相同的输入,我们会发现正确字符的分数(例如,第一个时间步中的“e”)会略高(例如2.3而不是2.2),并且不正确字符的分数会略低。

然后我们多次重复这个过程,直到网络收敛,并且其预测最终与训练数据一致,因为正确的字符总是接下来预测的。

更技术性的解释是我们在每个输出向量上同时使用标准的Softmax分类器(通常也称为交叉熵损失)。RNN使用小批量随机梯度下降进行训练,我喜欢使用RMSProp或Adam(每参数自适应学习速率方法)来稳定更新。

还要注意,第一次输入字符“l”时,目标是“l”,但第二次目标是“o”。因此,RNN不能单独依靠输入,并且必须使用其循环连接来跟踪上下文以实现此任务。

在测试的时候,我们会向RNN提供一个角色,并分配下一个可能出现的角色。我们从这个发行版中抽取样本,并将它反馈回来以获取下一封信。重复这个过程,你正在取样文本!

相关推荐