分享好友 人工智能首页 频道列表

循环神经网络(RNN)相关知识 rnn递归神经网络

循环神经网络  2023-02-10 11:467660

RNN概述

循环神经网络(RNN)是用于处理序列数据的神经网络,该序列在时刻 t(从1 到 τ)包含向量 x(t)x^{(t) }。典型的网络结构如下图所示:

循环神经网络(RNN)相关知识

RNN每个时间步都需要将 x 值的输入序列映射到输出值 o 的对应序列。其中 o 是未归一化的对数概率,并且在损失函数 L 内部计算 y^=softmax(x)\hat y = softmax(x)。损失函数 L 用于衡量每个 o 与相应的训练目标 y 的距离。

RNN输入到隐含单元的连接由权重矩阵 U 参数化,隐含单元与隐含单元连接由权重矩阵 W 参数化,隐含单元到输出节点的连接由权重矩阵 V 参数化。从上面的图中也可以看出,与CNN类似,在RNN中同样有参数共享的思想(共享了参数WUVW,U,V等)。这使得模型的泛化能力更强,因为模型不会依赖于特定位置上的输入xx。例如考虑这两句话:“I went to Nepal in 2009’’ 和 “In 2009, I went to Nepal.” ,他们表达的意思完全相同,但是时间2009出现在不同的地方,RNN的参数共享机制可以更有效的提取到这个时间信息。参数共享也允许模型泛化到没有见过的序列长度,并且训练模型所需的训练样本远远少于不带参数共享的模型。

当训练循环网络根据过去的信息去预测未来的信息时,网络通常要使用隐含状态 h (t) 来表示时刻 t 之前的序列信息:
h(t)=g(t)(x(t),x(t1),x(t2),,x(2),x(1))=f(h(t1),x(t);θ). \begin{aligned} h^{(t)} &=g^{(t)}(x^{(t)},x^{(t-1)},x^{(t-2)},\dots,x^{(2)}, x^{(1)}) \\ & = f(h^{(t-1)}, x^{(t)} ; \theta) . \end{aligned}
函数g(t)g^{(t)}将过去的序列(x(t),x(t1),x(t2),,x(2),x(1))(x^{(t)},x^{(t-1)}, x^{(t-2)},\dots,x^{(2)}, x^{(1)})作为输入来生成当前的隐含状态h(t)h(t)。实际上,我们可以递归调用函数ff来完成隐含状态的计算。这么做主要有两个优点:

  1. 无论序列的长度如何,模型始终具有相同的输入数据。因为它只关注给定输x(t)x^{(t)}后,从一种状态h(t1)h(t-1)到另一种状态h(t)h(t)的转移, 而不是在可变长度的历史输入数据x(t1),x(t2),,x(2),x(1)x^{(t-1)},x^{(t-2)},\dots,x^{(2)}, x^{(1)}上的操作。
  2. 我们可以在每个时间步(tt时刻)使用相同参数的状态转移函数ff

在不同的NLP场景中,h(t) 需要保存的信息也不同。例如在词性标注任务中,h(t) 更多的是要保存前一个单词的信息;而在机器翻译任务中,则需要保存输入序列的所有信息。

前向传播公式

上面的图中没有指明**函数,假设使用tanhtanh作为**函数,并且假设输出值是离散的,例如用于预测类别。一种表示离散变量的方式是:把输出 o 作为离散变量每种可能值的非标准化对数概率。然后,我们可以应用 softmax 函数获得标准化后概率的输出向量y^\hat y

RNN从特定的初始状态 h (0) 开始前向传播。从 t = 1 到 t = τ 的每个时间步,我们应用以下更新方程:
a(t)=b+Wh(t1)+Ux(t)h(t)=tanh(a(t))o(t)=c+Vh(t) \begin{aligned} &\mathbf a^{(t)} = \mathbf b + \mathbf W \mathbf h^{(t-1)} + \mathbf U \mathbf x^{(t)} \\ &\mathbf h^{(t)} = \tanh(\mathbf a^{(t)}) \\ &\mathbf o^{(t)} = \mathbf c + \mathbf V \mathbf h^{(t)} \\ \end{aligned}

y^(t)=softmax(o(t))=eo(t)t=1τeo(t) \hat {\mathbf y} ^{(t)} = softmax(\mathbf o^{(t)}) = \frac{e^{o^{(t)}}}{\sum_{t=1}^\tau e^{o^{(t)}}} \\

其中的参数的偏置向量 b 和 c 连同权重矩阵 U、V 和 W,分别对应于输入到隐藏单元、
隐藏单元到输出和隐藏单元到隐藏单元的连接。这个循环网络将一个输入序列映射到相同长度的输出序列。与 x 序列配对的 y 的总损失就是所有时间步的损失之和,例如定义损失L为所有时间步的负对数似然函数:
L({x(1),,x(τ)},{y(1),,y(τ)})=tL(t)=tlogPmodel(y(t){x(1),,x(τ)}) \begin{aligned} &L(\{x^{(1)},\ldots,x^{(\tau)}\},\{y^{(1)},\ldots,y^{(\tau)}\}) \\ &= \sum_{t} L^{(t)} \\ &= -\sum_{t} \log P_{model}(y^{(t)}|\{x^{(1)},\ldots,x^{(\tau)}\}) \end{aligned}
了解正向传播的计算内容之后,就可以讨论通过时间反向传播算法来更新网络参数了。

通过时间反向传播(BPTT)

回顾之前的计算图:

循环神经网络(RNN)相关知识

对于每一个节点 N,我们需要先 N 后面的节点的梯度,然后递归地计算梯度 NL∇ _N L。我们从最后一个节点开始递归:
LL(t)=1 \frac{\partial L}{\partial L^{(t)}} = 1
观察正向传播的计算公式,不难发现 L(t)L^{(t)}是关于y^(t)\hat {\mathbf y} ^{(t)}的函数,y^(t)\hat {\mathbf y} ^{(t)}softmaxsoftmax的结果, 而softmaxsoftmax是关于 o(t)o^{(t)}的函数。求LL对非标准化对数概率 o(t)o^{(t)}求偏导(相关求导过程可以参考Softmax求导),得到:
(o(t)L)i=Loi(t)=LL(t)L(t)y^i(t)y^i(t)oi(t)={y^i(t)1,yi(t)=labely^i(t)0,yi(t)label \begin{aligned} (\nabla_{\mathbf o^{(t)}} L)_i &= \frac{\partial L}{\partial o_{i}^{(t)}}\\ &= \frac{\partial L}{\partial L^{(t)}} \frac{\partial L^{(t)}}{\partial \hat {\mathbf y} ^{(t)}_i} \frac{\partial \hat {\mathbf y} ^{(t)}_i}{\partial o_{i}^{(t)}} \\ &= \begin{cases} \hat {y}_i ^{(t)} - 1 , \qquad {y}_i ^{(t)} =label\\ \hat {y}_i ^{(t)} - 0, \qquad {y}_i ^{(t)} \ne label \end{cases} \end{aligned}
从序列的末尾开始,反向进行计算。在最后的时间步 τ,只有 o (τ) 依赖于h (τ) ,不存在h (τ+1)依赖于h (τ) ,因此这个梯度很简单。由o(t)=c+Vh(t)\mathbf o^{(t)} = \mathbf c + \mathbf V \mathbf h^{(t)},可以知道:
h(τ)L=o(τ)h(τ)o(τ)L=VTo(τ)L \nabla_{\mathbf h^{(\tau)}}L = \frac{\partial o^{(\tau)}}{\partial h^{(\tau)}}\nabla_{\mathbf o^{(\tau)}} L = \mathbf V^T \nabla_{\mathbf o^{(\tau)}} L
然后我们可以从时刻 t = τ − 1 到 t = 1 反向迭代,通过时间反向传播梯度。由下面的式子:
a(t)=b+Wh(t1)+Ux(t)h(t)=tanh(a(t))o(t)=c+Vh(t) \mathbf a^{(t)} = \mathbf b + \mathbf W \mathbf h^{(t-1)} + \mathbf U \mathbf x^{(t)} \\ \mathbf h^{(t)} = \tanh(\mathbf a^{(t)}) \\ \mathbf o^{(t)} = \mathbf c + \mathbf V \mathbf h^{(t)}
不难发现当t < τ时, o (t) 和 h (t+1) 都依赖于h (t) 。因此,它的梯度由两个部分组成:
h(t)L=(h(t+1)h(t))(h(t+1)L)+(o(t)h(t))(o(t)L)=W(h(t+1)L)diag(1(h(t+1))2)+V(o(t)L) \begin{array}{l} \nabla_{h^{(t)}} L=\left(\frac{\partial \boldsymbol{h}^{(t+1)}}{\partial \boldsymbol{h}^{(t)}}\right)^{\top}\left(\nabla_{\boldsymbol{h}^{(t+1)}} L\right)+\left(\frac{\partial \boldsymbol{o}^{(t)}}{\partial \boldsymbol{h}^{(t)}}\right)^{\top}\left(\nabla_{\boldsymbol{o}^{(t)}} L\right) \\ =\boldsymbol{W}^{\top}\left(\nabla_{\boldsymbol{h}^{(t+1)}} L\right) \operatorname{diag}\left(1-\left(\boldsymbol{h}^{(t+1)}\right)^{2}\right)+\boldsymbol{V}^{\top}\left(\nabla_{\boldsymbol{o}^{(t)}} L\right) \end{array}
其中:
tanh(x)=1(tanh(x))2 \tanh'(x) = 1- (tanh(x))^2

h(t+1)h(t)=tanh(b+Wh(t)+Ux(t+1))h(t)=WTdiag(1(h(t+1))2) \begin{aligned} \frac{\partial \boldsymbol{h}^{(t+1)}}{\partial\boldsymbol{h}^{(t)}} &= \frac{\partial \tanh(\mathbf b + \mathbf W \boldsymbol h^{(t)} + \mathbf U \mathbf x^{(t+1)} )}{\partial\boldsymbol{h}^{(t)}} \\ &= \mathbf W^T diag(1-(\boldsymbol h^{(t+1)})^2) \end{aligned}

基于前面的步骤,接下来进行参数的跟新:
cL=t(o(t)c)o(t)L=to(t)LbL=t(h(t)b(t))h(t)L=tdiag(1(h(t))2)h(t)LVL=ti(Loi(t))Voi(t)=t(o(t)L)h(t)W=ti(Lhi(t))W(t)hi(t)=tdiag(1(h(t))2)(h(t)L)h(t1)UL=ti(Lhi(t))U(t)hi(t)=tdiag(1(h(t))2)(h(t)L)x(t) \begin{aligned} \nabla_{c} L &=\sum_{t}\left(\frac{\partial \boldsymbol{o}^{(t)}}{\partial \boldsymbol{c}}\right)^{\top} \nabla_{\boldsymbol{o}^{(t)}} L=\sum_{t} \nabla_{\boldsymbol{o}^{(t)}} L \\ \nabla_{\boldsymbol{b}} L &=\sum_{t}\left(\frac{\partial \boldsymbol{h}^{(t)}}{\partial \boldsymbol{b}^{(t)}}\right)^{\top} \nabla_{\boldsymbol{h}^{(t)}} L=\sum_{t} \operatorname{diag}\left(1-\left(\boldsymbol{h}^{(t)}\right)^{2}\right) \nabla_{\boldsymbol{h}^{(t)}} L \\ \nabla_{\boldsymbol{V}} L &=\sum_{t} \sum_{i}\left(\frac{\partial L}{\partial o_{i}^{(t)}}\right) \nabla_{\boldsymbol{V}} o_{i}^{(t)}=\sum_{t}\left(\nabla_{o^{(t)}} L\right) \boldsymbol{h}^{(t)^{\top}} \\ \nabla_{\boldsymbol{W}} &=\sum_{t} \sum_{i}\left(\frac{\partial L}{\partial h_{i}^{(t)}}\right) \nabla_{\boldsymbol{W}^{(t)}} h_{i}^{(t)} \\ &=\sum_{t} \operatorname{diag}\left(1-\left(\boldsymbol{h}^{(t)}\right)^{2}\right)\left(\nabla_{\boldsymbol{h}^{(t)}} L\right) \boldsymbol{h}^{(t-1)^{\top}} \\ \nabla_{U} L &=\sum_{t} \sum_{i}\left(\frac{\partial L}{\partial h_{i}^{(t)}}\right) \nabla_{\boldsymbol{U}^{(t)}} h_{i}^{(t)} \\ &=\sum_{t} \operatorname{diag}\left(1-\left(\boldsymbol{h}^{(t)}\right)^{2}\right)\left(\nabla_{\boldsymbol{h}^{(t)}} L\right) \boldsymbol{x}^{(t)^{\top}} \end{aligned}

RNN确定序列长度方式

第一种是添加一个表示序列末端的特殊符号。在训练集中,我们将该符号作为序列的一个额外成员,即紧跟每个训练样本 x (τ) 之后。

第二种选择是在模型中引入一个额外的Bernoulli输出,表示在每个时间步决定继续或停止。相比向词汇表增加一个额外符号,这种方法更普遍,因为它适用于任何RNN。在这种方法中,sigmoid被训练为最大化正确预测的对数似然,即在每个时间步序列决定结束或继续。

第三种是将一个额外的输出添加到模型并预测整数 τ 本身。模型可以预测 τ 的值,然后使用 τ 步有价值的数据。这种方法需要在每个时间步的循环更新中增加一个额外输入,使得循环更新知道它是否是靠近所产生序列的末尾。

其他RNN结构

除了上面介绍的RNN结构,还有一些其他结构:

1, 每个时间步都产生一个输出,但是只有当前时刻的输出 o 与下个时刻的隐藏单元之间有连接的RNN:

循环神经网络(RNN)相关知识

这样的RNN没有最开始介绍的 RNN 那样强大,上图中的RNN被训练为将特定输出值放入 o 中,并且 o 是允许传播到未来的唯一信息。此处没有从 h 前向传播的直接连接。之前的 h 仅通过产生的预测间接地连接到当前。o 通常缺乏过去的重要信息,除非它非常高维且内容丰富。这使得该图中的RNN不那么强大,但是它更容易训练,因为每个时间步可以与其他时间步分离训练,允许训练期间更多的并行化。

2, 隐藏单元之间存在循环连接,但读取整个序列后只在最后一个时间步产生单个输出的RNN:

循环神经网络(RNN)相关知识

这样的网络可以用于概括序列,并产生一个向量 o 用于表示整个输入序列,然后可以对 o 进行进一步的处理。例如在翻译任务中,先输入原始输入的句子,得到句子的向量表示 o ,然后对 o 展开进一步的翻译任务。

3,包含上下文的RNN:

循环神经网络(RNN)相关知识

此RNN包含从前一个输出到当前状态的连接。这些连接允许RNN在给定 x 的序列后,对相同长度的 y 序列上的任意分布建模。

4,双向RNN

在许多应用中,我们要输出的 y (t) 的预测可能依赖于整个输入序列。例如,在语音识别中,当前声音作为音素的正确解释可能取决于未来几个音素,甚至可能取决于未来的几个词,因为词与附近的词之间的存在语义依赖。双向RNN结构如下:

循环神经网络(RNN)相关知识

隐藏状态变量 h 在时间上向前传播信息(向右),而隐藏状态变量 g 在时间上向后传播信息(向左)。因此在每个点 t,输出单元 o (t) 可以受益于输入 h (t) 中关于过去的相关信息以及输入 g (t) 中关于未来的相关信息。

5,编码—解码结构(序列到序列)的RNN

编码—解码结构的RNN支持将输入序列映射到不一定等长的输出序列,结构如下图所示:

循环神经网络(RNN)相关知识

这在许多场景中都有应用,如语音识别、机器翻译或问答,其中训练集的输入和输出序列的长度通常不相同。它由读取输入序列的编码器RNN以及生成输出序列的解码器RNN组成。编码器RNN的最终隐藏状态用于计算一般为固定大小的上下文向量 C,C 表示输入序列的语义概要信息并且作为解码器RNN的输入。

基于RNN的应用

RNN通常用于处理序列形式的输入数据,如文本,语音等。输出也可以是序列或者某个预测值。常见的应用如下:

1,序列数据的分析

例如情感分析,输入一句话的每个字的向量表示,输出其情感的预测标签。网络结构如下:

循环神经网络(RNN)相关知识

2,序列数据的转换

例如机器翻译,输入是某种语言的字序列,输出是翻译后的字序列。网络结构如下:

循环神经网络(RNN)相关知识

再如,词性标注,输入是字的向量表示,输出是每个字对应的词性标注信息,常见网络结构如下:

循环神经网络(RNN)相关知识

3,序列数据的生成

例如,图片描述生成,输入是一张图片的向量表示,输出图片的描述信息。网络结构如下:

循环神经网络(RNN)相关知识

RNN的不足

RNN很难解决长依赖问题,即经过许多个时间步的传播之后,梯度值倾向于0或者无穷大,这样的现象称之为梯度消失和梯度爆炸。

1,从隐藏变量h角度来看

为了简化说明,我们认为:
h(t)=WTh(t1) \boldsymbol h^{(t)} = \boldsymbol W^T \boldsymbol h^{(t-1)}
根据递推关系,可以转换为:
h(t)=(Wt)Th(0) \boldsymbol h^{(t)} = (\boldsymbol W^t)^T \boldsymbol h^{(0)}
W\boldsymbol W 符合下列形式的特征分解:
W=QΣQT \boldsymbol W = \boldsymbol Q \boldsymbol \Sigma \boldsymbol Q^T
其中Q\boldsymbol Q是正交矩阵。于是有:
h(t)=QTΣtQh(0) \boldsymbol h^{(t)} = \boldsymbol Q^T \boldsymbol \Sigma^t \boldsymbol Q \boldsymbol h^{(0)}
经过多个阶段的传播后,如果$ \boldsymbol \Sigma^t11中的特征值小于1,特征值将衰减到零。如果特征值大于1,经过t次相乘后,特征值将激增。任何不与最大特征向量对齐的\boldsymbol h^{(0)}$的部分将最终被丢弃,无法做到长期依赖。

2,从梯度传播角度来看

梯度的反向传播过程如下图所示:

循环神经网络(RNN)相关知识

不难得到:
Jy0=Jh3h3h2h2h1h1y0 \frac{\partial J}{\partial y_0} = \frac{\partial J}{\partial h_3}\frac{\partial h_3}{\partial h_2} \frac{\partial h_2}{\partial h_1} \frac{\partial h_1}{\partial y_0}
上面的式子是多个偏导数的累乘,如果每个偏导数的值都小于1,那么传播到 t=0t=0 时刻的梯度几乎等于0了,也就是梯度消失了。梯度消失意味着只有靠近输出的几层才真正起到学习的作用,无法通过加深网络层数来提升预测效果,这样RNN很难学习到输入序列中的长距离依赖关系。

反之,如果每个偏导数的值都大于1,那么传播到 t=0t=0 时刻的梯度被指数倍放大,也就是梯度爆炸了。可以通过梯度裁剪来缓解,即当梯度的范式大于某个给定值的时候,对梯度进行等比缩放。

为了能学习到更长的依赖关系,需要对RNN网络加以改进,下一篇文章提到的LSTM模型可以一定程度上得到改善。

参考文章:

《深度学习》

RNN详解

查看更多关于【循环神经网络】的文章

展开全文
相关推荐
反对 0
举报 0
图文资讯
热门推荐
优选好物
更多热点专题
更多推荐文章
第六讲 循环神经网络--LSTM--stock
1 !pip install tushare2 import tushare as ts3 import numpy as np4 import tensorflow as tf5 from tensorflow.keras.layers import Dropout, Dense, LSTM6 import matplotlib.pyplot as plt7 import os8 import pandas as pd9 from sklearn.preprocessing

0评论2023-02-10476

基于循环神经网络的图像特定文本抽取方法
 作者的模型整体框架包含两部分,分别为OCR 部分 (采用人家的模型, 输出文本)特定文本抽取部分 (作者的工作)1. 引言早期图像特定文本抽取主要是通过 OCR 中的版面分析(Layout analysis)来实现。即首先利用 版面分析 的方法得到图像中特定的文本区域,然后

0评论2023-02-09946

更多推荐