Jordan RNN于1986年提出:《SERIAL ORDER: A PARALLEL DISTRmUTED PROCESSING APPROACH》 Elman RNN于1990年提出:《Finding Structure in Time》 《LSTM原始论文:Long Short-Term Memory》 《GRU原始论文:Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation》
一、RNN概述
为什么有神经网络需要循环神经网络?
在普通的神经网络中,信息传输是单向的。虽然这种限制使网络更容易学习,但它也在一定程度上削弱了神经网络模型的能力。特别是在许多实际任务中,网络的输出不仅与当前时刻的输入有关,而且与过去一段时间的输出有关。此外,普通网络很难处理时间数据,如视频、语音、文本等,时间数据的长度一般不固定,前馈神经网络要求输入和输出的维数是固定的,不能随意改变。因此,在处理这类与时序相关的问题时,需要一个能力更强的模型。
循环神经网络(Recurrent Neural Network,RNN)它是一种具有短期记忆能力的神经网络。在循环神经网络中,神经元不仅可以接受其他神经元的信息,还可以接受自己的信息,形成具有环路的网络结构。换句话说,神经元的输出可以直接影响到下一步。
RNN(Recurrent Neural Network), 中文称循环神经网络, 它一般以序列数据为输入, 通过网络内部的结构设计,有效地捕捉序列之间的关系特征, 一般以序列的形式输出.
DNN算法(全连接神经网络)CNN算法(卷积神经网络)的输出只考虑前一个输入的影响,而不考虑其他时刻输入的影响,如简单的猫、狗、手写数字和其他单个物体的识别。
- 然而,这些算法的表现并不令人满意,因为一些与时间有关的算法,如视频的下一刻预测、文档前后文本内容的预测等。 RNN应运而生。RNN 解决了这个问题。RNN 它是一个包含循环的网络,允许信息。
- RNN是一种特殊的神经网络结构, 它是根据"人的认知是基于过去的经验和记忆"这一观点提出. 它与DNN,CNN不同的是: 它不仅考虑了前一刻的输入,还赋予了网络一个记忆功能.
- RNN它被称为循环神经网,即一个序列 “” 与 “” 也有关。具体的表达形式是,网络将记忆并应用于当前输出的计算,即隐藏层之间的节点不再连接,而是连接,隐藏层的输入不仅包括输入层的输出,还包括前一刻隐藏层的输出。
- RNN应用领域很多, 可以说,只要考虑时间顺序,就可以使用RNN来解决:
- 自然语言处理(NLP): 主要有视频处理, 文本生成, 语言模型, 图像处理
- 机器翻译, 机器写小说
- 语音识别
- 生成图像描述
- 计算文本相似度
- 音乐推荐,网易考拉商品推荐,Youtube视频推荐等新的应用领域.
因为RNN结构可以很好地利用序列之间的关系, 因此,对自然界具有连续性的输入序列, 如人类语言, 语音等处理得很好, 广泛应用于NLP各个领域的任务, 如文本分类, 情感分析, 意图识别, 机器翻译等.
以用户意图识别为例进行简单分析:
- 第一步: 用户输入了"What time is it ?", 我们首先需要对它进行基本的分词, 因为RNN是按照顺序工作的, 每次只收到一个单词处理.
- 第二步: 首先将单词"What"输送给RNN, 它产生输出O1.
- 第三步: 继续将单词"time"输送给RNN, 但此时RNN不仅仅利用"time"来产生输出O2, 它还将用于上一层的隐层输出O1作为输入信息.
- 第四步: 重复此步骤, 直到所有单词都处理完毕。.
- 第五步: 最后,输出最终隐层O5.处理分析用户意图.
RNN模型的分类 { 根据输入输出结构进行分类 { “NvsN”RNN “Nvs1”RNN “1vsN”RNN “NvsM”RNN 按照 R N N 对内部结构进行分类 { 传统RNN LSTM Bi-LSTM GRU Bi-GRU \begin{aligned} \text{RNN模型分类} \begin{cases} 根据输入输出结构进行分类 \begin{cases} \text{“N\ vs\ N”\ RNN}\\[0.5ex] \text{“N\ vs\ 1”\ RNN}\\[0.5ex] \text{“1\ vs\ N”\ RNN}\\[0.5ex] \text{“N\ vs\ M”\ RNN}\\ \end{cases} \\ 按照RNN对内部结构进行分类 \begin{cases} \text{传统RNN}\\[0.5ex] \text{LSTM}\\[0.5ex] \text{Bi-LSTM}\\[0.5ex] \text{GRU}\\[0.5ex] \text{Bi-GRU} \end{cases} \end{cases} \end{aligned} RNN模型的分类? ? ⎧按照输入和输出的结构进行分类⎩ ⎨ ⎧“N vs N” RNN“N vs 1” RNN“1 vs N” RNN“N vs M” RNN按照RNN的内部构造进行分类⎩ ⎨ ⎧传统RNNLSTMBi-LSTMGRUBi-GRU
- 图1:固定长度的输入和输出 (e.g. 图像分类)
- 图2:序列输出 (e.g.图像转文字)
- 图3:数列输入 (e.g. 文本分类)
- 图4:异步的序列输入和输出(e.g.文本翻译).
- 图5:同步的序列输入和输出 (e.g. 根据视频的每一帧来对视频进行分类)
1、“N vs N” RNN
它是RNN最基础的结构形式, 最大的特点就是: 输入和输出序列是等长的. 由于这个限制的存在, 使其适用范围比较小, 可用于生成等长度的合辙诗句.
2、“N vs 1” RNN
有时候我们要处理的问题输入是一个序列,而要求输出是一个单独的值而不是序列,应该怎样建模呢?我们只要在最后一个隐层输出h上进行线性变换就可以了,大部分情况下,为了更好的明确结果, 还要使用sigmoid或者softmax进行处理. 这种结构经常被应用在文本分类问题上.
3、“1 vs N” RNN
如果输入不是序列而输出为序列的情况怎么处理呢?我们最常采用的一种方式就是使该输入作用于每次的输出之上. 这种结构可用于将图片生成文字任务等.
4、“N vs M” RNN
这是一种不限输入输出长度的RNN结构, 它由编码器和解码器两部分组成, 两者的内部结构都是某类RNN, 它也被称为seq2seq架构. 输入数据首先通过编码器, 最终输出一个隐含变量c, 之后最常用的做法是使用这个隐含变量c作用在解码器进行解码的每一步上, 以保证输入信息被有效利用. seq2seq架构最早被提出应用于机器翻译, 因为其输入输出不受限制,如今也是应用最广的RNN模型结构. 在机器翻译, 阅读理解, 文本摘要等众多领域都进行了非常多的应用实践.
二、RNN传统结构
通过简化图,我们看到RNN比传统的神经网络多了一个循环圈,这个循环表示的就是在下一个时间步()上会返回作为输入的一部分,我们把RNN在时间点上展开,得到的图形如下:
对于一个模型而言,最重要的四个部分:输入、输出、参数、对应运算关系。
- 输入: X X X,以及来自前一时刻隐藏层的结果 h t − 1 h_{t-1} ht−1
- 输出: Y Y Y,以及传递给下一时刻隐藏层的结果 h t h_t ht
- 参数: W i W_{i} Wi、 W h W_{h} Wh、 b b b、 W o W_o Wo
- 对应运算关系(信息传播): h t = σ [ W i X + W h ⋅ h t − 1 + b ] Y = S o f t m a x [ W o ⋅ h t ] \begin{aligned} h_t&=σ[W_{i}X+W_{h}·h_{t-1}+b]\\[2ex] Y&=Softmax[W_o·h_t] \end{aligned} htY=σ[WiX+Wh⋅ht−1+b]=Softmax[Wo⋅ht]
有了这个RNN基本单元,整个RNN网络也就呼之欲出了。
1、传统RNN结构
- Pointwise Operation:对应位置的运算(加法/乘法)【比如:2个3行4列的矩阵的Pointwise Operation就是2个矩阵对应位置的元素分别做运算】
- Concatenate:矩阵的合并【一般是左右方向(横向)的合并,因为横向一般表示各个特征,每一列代表一个特征。比如A矩阵是4列(4个特征),B矩阵是10列(10个特征),合并后就是一个14列的矩阵(14个特征)】
内部结构分析: 我们把目光集中在中间的方块部分, 它的输入有两部分, 分别是 h t − 1 h_{t-1} ht−1 以及 X t X_{t} Xt, 代表上一时间步的隐层输出, 以及此时间步的输入, 它们进入RNN结构体后, 会"融合"到一起, 这种融合我们根据结构解释可知, 是将二者进行拼接, 形成新的张量 [ h t − 1 , X t ] [h_{t-1}, X_{t}] [ht−1,Xt], 之后这个新的张量将通过一个全连接层(线性层), 该层使用tanh作为激活函数, 最终得到该时间步的输出 h t h_t ht, 它将作为下一个时间步的输入和 X t + 1 X_{t+1} Xt+1一起进入结构体. 以此类推.
- RNN的cell比较简单,我们用 X t X_t Xt表示 t t t 时刻cell的输入, C t C_t Ct 表示 t t t 时刻cell的状态, h t h_t ht 表示 t t t 时刻的输出(输出和状态在RNN里是一样的)。
- 那么其前向传播的公式也很简单: h t = C t = [ h t − 1 , X t ] ∗ W + b t h_t=C_t=[h_{t−1},X_t]∗W+b_t ht=Ct=[ht−1,Xt]∗W+bt,其中 [,] 表示concat。 W W W 和 b b b 分别为RNN的 kernel 和 bias。
RNN传统结构:
- 在每个神经单元中只有一个tanh激活函数。激活函数tanh用于帮助调节流经网络的值, tanh函数将值压缩在-1和1之间.
- 相对于DNN、CNN每个神经元只有一个输入,RNN的每个神经单元有两个输入。如上图所示,第 t t t 个神经元的输入不仅仅有 x t x_t xt,还有上个神经元的状态 h t − 1 h_{t-1} ht−1 或者是上一个神经元的输出 y t − 1 y_{t-1} yt−1。这里根据 h t h_t ht接收的是 h t − 1 h_{t-1} ht−1 还是 y t − 1 y_{t-1} yt−1的不同,分为Elman network与Jordan Network,一般来说我们用的都是Elman network。
- X X X 它表示输入层的值,是一个向量;
- U U U 是输入层到隐藏层的权重矩阵;跟CNN类似,RNN模型中不同时刻的 U U U是共享的。
- W W W 是隐藏层上一次的值作为这一次的输入的权重;跟CNN类似,RNN模型中不同时刻的 W W W是共享的。
- S S S 表示隐藏层的值Embedding,是一个向量;
- V V V 是隐藏层到输出层的权重矩阵;
- O O O 表示输出层的值,是一个向量;
Feed Forward Neural Network | Recurrent Neural Network | Passing Hidden State to next time step |
---|---|---|
- RNN网络在 t t t 时刻接收到输入 X t X_t Xt 之后,隐藏层的值是 S t S_t St,输出值是 O t O_t Ot。关键一点是, S t S_t St 的值不仅仅取决于 X t X_t Xt ,还取决于 S t − 1 S_{t-1} St−1 。我们可以用下面的公式来表示循环神经网络的计算方法: S ⃗ t = f ( X ⃗ t ⋅ U ⃗ + S ⃗ t − 1 ⋅ W ⃗ ) O ⃗ t = g ( V ⃗ ⋅ S ⃗ t ) \begin{aligned} \vec{S}_t&=f(\vec{X}_t·\vec{U}+\vec{S}_{t-1}·\vec{W})\\ \vec{O}_t&=g(\vec{V}·\vec{S}_t) \end{aligned} S tO t