RNN
title: RNN
date: 2019-03-05 11:49:20
tags:
mathjax: true
循环神经网络(Recurrent Neural Network)是用来建模序列化数据的一种主流深度学习模型。我们知道,传统的前馈神经网络一般的输入都是一个定长的向量,无法处理变长的序列信息,即使通过一些方法把序列处理成定长的向量,模型也很难捕捉序列中的长距离依赖关系。RNN则通过将神经元串行起来处理序列化的数据。由于每个神经元都能用它的内部变量保存之前输入的序列信息,因此整个序列被浓缩成抽象的表示,并可以据此进行分类或生成新的序列。近年来RNN在很多领域取得突破性进展 —— 机器翻译、序列标注、图像描述、推荐系统、智能聊天机器人、自动作词作曲等。
下图展示了一个典型的循环神经网络结构:
一个长度为T 的序列用循环神经网络建模,展开之后可以看做是一个T曾的前馈神经网络。其中,第 $t$ 层的隐含状态 $h{t}$ 编码了序列中前 $t$ 个输入的信息,可以通过当前的输入$x{t}$和上一层的状态 $h{t-1}$ 计算得到;最后一层的状态 $h{t}$ 编码了整个序列的信息,因此可以作为整个序列的压缩表示。循环神经网络的前向传播公式为:
其中 $f$ 和 $g$ 为激活函数,$U$ 为输入层到隐含层的权重矩阵,$W$ 为隐含层从上一时刻到下一时刻状态转移的权重矩阵。$f$ 可以选取 Tanh 函数 或者 ReLU 函数,$g$ 可以采用 Softmax 函数。
问题1:循环神经网络的梯度消失问题
循环神经网络模型的求解可以采用 BPTT 算法实现, BPTT 实际上是反向传播算法的变种。这一现象主要源于深度神经网络中的梯度消失。传统的循环神经网络梯度可以写成连乘的形式:
其中,
其中 $n$ 为 隐含层 $h{t-1}$ 的维度(即隐含单元的个数), $\frac{\partial{net_1}}{\partial{net{t-1}}}$ 对应 $n*n$ 维矩阵,又被称为雅各比矩阵。
由于预测误差是沿着神经网络的每一层反向传播的,因此当雅各比矩阵的最大特征值大于1时, 随着离输出越来越远,每层梯度大小会呈指数增长,导致梯度爆炸;反之,若雅各比矩阵的最大特征值小于1, 梯度的大小会呈指数减小,产生梯度消失。
梯度爆炸的问题可以通过梯度裁剪来缓解,即当梯度的范式大于某个某个给定值时, 对梯度进行等比收缩。而对于梯度消失问题, 可以通过加入门口机制来弥补梯度消失带来的损失。
问题 2: 在循环神经网络中,是否可以使用 ReLU 作为激活函数?
可以,但是需要将$W$初始化为单位矩阵。如果不然会引发严重的数值问题和梯度消失或爆炸问题。
数值问题:
考虑前向传播公式:
根据前向传播公式向前传递一层,可以得到
如果使用 $ReLU$ 替代公式中的激活函数 $f$, 并且假设 $ReLU$ 处于激活区域(即输入大于0),则有 $f(x)=x, net{t}=Ux{t}+W(Ux{t-1}+Wh{t-2})$, 继续将其展开,$net_{t}$ 的表达式中最终将包含$t$ 个 $W$ 连乘。如果 $W$ 不是单位矩阵,最终的结果将趋于 $0$ 或者无穷,引发严重的数值问题。
梯度爆炸或梯度消失:
考虑循环神经网络的梯度计算公式:
假设采用 $ReLU$ 激活函数,且一开始所有的神经元都处于激活中, 则 $diag[f’(net{t-1})]$ 为单位矩阵, 有 $\frac{\partial{net_t}}{\partial{net{t-1}}}=W$。在梯度经过了$n$ 层之后, $\frac{\partial{net{t}}}{\partial{net{1}}} = W^n$。可以看到即使采用了 $ReLU$ 激活函数,只要$W$ 不是单位矩阵,还是会出现梯度消失或者爆炸的现象。
问题 3: LSTM 是如何实现长短期记忆功能的?
与传统的循环神经网络相比,LSTM 仍然是基于$xt$ 和 $h{t-1}$ 来计算 $h_t$, 只不过对内部的结构进行了更加精心的设计,加入了输入门 $i_t$ 、遗忘门 $f_t$ 以及输出门 $o_t$ 三个门和一个内部记忆单元 $c_t$。
输入门控制当前计算的新状态以多大程度更新到记忆单元中;遗忘门控制前一步记忆单元中的信息有多大程度被遗忘掉;输出门控制当前的输出有多大程度取决于当前的记忆单元。
经典的LSTM中, 第 $t$ 步的更新计算公式为:
其中输入门 $i{t}$ 是通过输入 $x_t$和上一步的隐含层输出 $h{t-1}$ 来进行线性变换,再经过激活函数 $\sigma$ 得到的。输入门 $it$ 的结果是向量,其中每个元素是 0 到 1 之间的实数, 用于控制各维度流过阀门的信息量;$W{i}$、$Ui$ 两个矩阵核向量 $b_i$ 为输入门的参数,是在训练过程中得到的。**遗忘门 $f{t}$ 和输出门 $o{t}$ 的计算方式与输入门类似,它们有各自的参数 $W$、$U$ 和 $b$ **。 与传统的循环神经网络不通的是,从上一个记忆单元的状态 $c{t-1}$ 到 当前的状态 $c_{t} $ 的转移不一定完全取决于激活函数计算得到的状态,还由输入门和遗忘门来共同控制。
在一个循环好的网络中,当输入的序列中没有重要信息时, $LSTM$ 的遗忘门的值会接近于 1, 输入门的值会接近于0, 此时过去的信息回本保存,从而实现长期记忆功能;当输入序列中出现重要信息时,$LSTM$ 应当将其存入记忆中,此时其输入门的值会接近于1; 当输入的序列出现了重要信息,且该信息意味着之前的记忆不在重要时,输入门的值会接近于1, 而遗忘门的值接近于0, 这样旧的记忆被遗忘,新的重要信息被记忆。经过这样的设计,整个网络更容易学到序列之间的长期依赖。
问题4:LSTM 里各个模块分别使用什么激活函数,可以使用别的激活函数吗?
关于激活函数的选取, 在 $LSTM$ 中,遗忘门、输入门和输出门使用 $Sigmoid$ 函数作为激活函数;在生成候选记忆时,使用双曲正切函数 $Tanh$ 作为激活函数。
(1) 这两个激活函数都是饱和的,也就是说在输入达到一定值得情况下,输出就不会发生明显变化了。如果使用非饱和的激活函数,例如 $ReLU$,那么将很难实现门控的效果。
(2) $Sigmoid$ 函数的输出在 0 ~ 1 之间,符合门控的物理定义。当输入较大或者较小时, 其输出会非常接近1或 0, 从而保证该门的开关。
(3)在生成候选记忆时,使用 $Tanh$ 函数,时因为其输出在-1~1 之间,这与大多数场景下特征分布是0中心吻合。此外,Tanh 函数在输入为 $0$ 附近相比 $Sigmoid$ 含有有更大的梯度,通常使模型收敛更快。
此外,在一些对计算能力有限制的设备,诸如可穿戴设备中,由于 $Sigmoid$ 函数求指数需要一定的计算量,此时会使用0/1门$(hard gard)$让门控输出为0或者1的离散值,即当输入小于阈值时,门控输出为0;当输入大于阈值时,输出为1。从而在性能下降不明显的情况下,减少计算量。
问题 5: 什么是 Seq2Seq模型?Seq2Seq模型有哪些优点?
$Seq2Seq$ 模型的核心思想是,通过深度神经网络将一个作为输入的序列映射为一个作为输出的序列,这一过程由编码输入与解码输出两个环节构成。在经典的实现中,编码器和解码器各由一个循环神经网络构成,既可以选择传统的循环神经网络结构,也可以使用长短期记忆模型。门控循环单元等。在 $Seq2Seq$ 模型中,两个循环神经网络是共同训练的。典型的循环神经网络编解码结构图如下所示:
问题 6: Seq2Seq 模型在解码时, 有哪些常用的方法?
$Seq2Seq$ 模型最基础的解码方法是贪心法, 即选取一种度量标准后,每次都在当前状态下选择最佳的一个结果, 直到结束。很显然,贪心法获得的是一个局部最优解,由于实际问题的复杂性,该方法往往不能取得更好的效果。集束搜索(beam search) 是一种常见的改进算法。该方法会保存 beam size 个当前的较佳选择,然后解码时每一步根据保存的选择进行下一步扩展和排序,接着选择前 beam size 个进行保存,循环迭代,直到结束时选择最佳的一个作为解码的结果。 随着 beam size 的增大,其搜索的空间增大,最终效果会有所提升,但需要的计算量也相应增大。在实际应用中,b往往会选择一个适中的范围,以8 ~ 12 为佳。下图是 beam size 为2时的集束搜索示例。
解码时使用堆叠的RNN、增加 Dropout机制、与编码器之间建立残差连接、增加Attention机制等,均是常见的改进措施。在实际的研究工作中,可以根据不同使用场景,有针对性的选择和实践。
问题7:Seq2Seq 模型引入注意力机制是为了解决什么问题? 为什么选用双向的循环神经网络模型?
在 Seq2Seq 模型中,当前隐状态以及上一个输出词决定了当前的输出词, 即:
在实际应用中会发现随着序列的增长,模型的性能发生显著下降。这是因为编码时输入序列的全部信息被压缩到一个向量表示中。随着序列增长,句子约前面的信息就丢失的越严重。$Seq2Seq$ 模型中引入注意力机制就是为了解决这个问题。
(1) 在编码过程中,我们仍然使用普通的循环神经网络对输入序列进行编码,得到隐状态 $h1, h2, …, hT$。使用一个神经网络 $align$ 上一个输入序列的隐状态 $s{i-1}$ 和输入序列隐状态 $h{j}$ 作为输入,计算出一个 $x{j}, y{i}$ 对齐的值 $e{ij}$, 再归一化得到权重 $\alpha_{ij}$。
(2) 计算语境向量 $c_{i}$ , 即是输入序列全部隐状态 $h1, h2, …, h_T$的一个加权和。
(3) 在解码过程中,每一个输出词都依赖于前一个隐状态以及输入序列每一个对应的隐状态。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!