DL Note-5 RNN

Recurrent Network

Sequence Model

序列建模任务是指对一个序列的输入进行建模,比如文本、音频、视频等。序列模型的输入和输出都是序列,如机器翻译、语音识别、视频分类等任务。重要的是捕捉序列中的上下文

Basic Principle

Local Dependency

Local Dependency:对于序列中的每一个元素,它的预测是依赖于它的前面的元素的。这种依赖关系是局部的

P(x1,x2,,xT)=t=1TP(xtx1,,xt1)=t=1Tg(st2,xt1)P(x_1,x_2,\dots,x_T) = \prod_{t=1}^{T} P(x_t|x_1,\dots,x_{t-1}) = \prod_{t=1}^{T} g(s_{t-2},x_{t-1})

直接对 P(xtx1,,xt1)P(x_t | x_1, \dots, x_{t-1}) 建模是极其困难的,因为随着 tt 的增长,条件部分的长度是可变的,会导致参数量爆炸。

  • 马尔可夫假设 (Markov Assumption):一个简单的妥协是假设当前状态只依赖于前一个或前几个状态(如n-gram模型)。但这会丢失大部分长期上下文信息,对于理解复杂序列是远远不够的。
  • 固定窗口 (Fixed Window):使用一个固定大小的窗口(如前n个词)输入到MLP中。这种方法虽然解决了输入维度问题,但窗口大小难以确定,且丢失了窗口外的上下文。更重要的是,MLP的输入是位置无关的,它无法自然地处理序列的顺序信息。

我们引入一个隐藏状态向量 hth_t,并作出核心假设:hth_t 能够压缩编码截至 tt 时刻的所有必要历史信息。hth_t 的计算依赖于前一时刻的状态 ht1h_{t-1} 和当前时刻的输入 xtx_t。 $$h_t = f(h_{t-1}, x_t)$$ 这样,预测 xt+1x_{t+1} 就只需要 hth_t 即可:P(xt+1x1,,xt)P(xt+1ht)P(x_{t+1} | x_1, \dots, x_t) \approx P(x_{t+1} | h_t)。这个递推关系是RNN的灵魂。 同时,RNN引入了两个关键假设:

  1. 时间平稳性假设 (Stationarity Assumption):决定状态如何演变的函数 ff 在所有时间步上是相同的。这意味着模型在序列的不同位置学习到的模式是通用的。这在实践中体现为参数共享 (Parameter Sharing),即计算 h1,h2,,hTh_1, h_2, \dots, h_T 时,使用的权重矩阵是同一套。这极大地减少了模型参数量,使其能够处理任意长度的序列。
  2. 隐藏状态假设hth_t 包含了预测未来所需的全部历史信息。虽然理论上如此,但在实践中,基础RNN很难维持非常久远的记忆。
  • 核心机制: 通过一个循环更新的隐藏状态 hth_t 来作为序列的“记忆”,理论上该状态压缩了 tt 时刻之前的所有历史信息。
  • 核心假设: 状态转移函数 ff 在时间上是共享的,这不仅极大减少了参数,也使得模型能够泛化到不同长度和位置的序列模式。
  • 本质: RNN将一个任意长度的序列问题,转化为了一个在每个时间步上重复执行相同操作的、结构固定的问题。

Language Model

语言中的建模任务为:给定一个句子的前面的单词,预测下一个单词。这个任务被称为语言模型。语言模型的目标是最大化句子的概率。语言模型的输入是一个句子,输出是一个概率分布,表示下一个单词的概率。

向量化表达:可以使用one-hot向量表示单词,也可以使用词向量表示单词。每个词的表达大概需要1000维度。
如果使用MLP,要将每个词的向量拼接起来,然后输入到MLP中。这样的模型不适合处理长序列,参数是非常可怕的。在MLP中丢失了一部分的信息(由于MLP的输入维度是可交换的),丢失了前后序关系。

A Better MLP

n-gram:使用n-gram模型,可以考虑前n个单词的信息。

输出的概率分布是一个softmax层,输入是一个向量,这个向量是前n个单词的向量拼接起来的。然后在得到的概率分布上进行采样。滚动预测,使用第一个次的预测结果作为第二次的输入,会有误差累计的问题。

但是上述模型会有一个问题:参数量太大;对于每一个词的预测需要有一个MLP,这样的模型不适合处理长序列。

Parametric Sharing

不同时刻使用的参数是一样的,这样可以大大降低参数量。这样的模型是循环神经网络


RNN

循环神经网络中最重要的内容是中间的隐藏层,构建学习到的时间程度上的特征。在每个时刻输入的都是向量,称为token embedding
上述模型在纵向方向上,从xtx_tyty_t就是一个前馈网络feedforward network(包括MLP和CNN)。在横向方向上,从st1s_{t-1}sts_t就是一个循环网络recurrent network

Recurrent Layer

hth_t用来编码tt时刻之前的所有信息。对于这样的层,接受的输入是xtx_tht1h_{t-1},输出是hth_thth_t的计算公式如下:

ht=fW(ht1,xt)h_t = f_W(h_{t-1},x_t)

ht=tanh(Wht1+Uxt+bh)h_t = \tanh (Wh_{t-1} + Ux_t + b_h)

长期以来使用的是双曲正切作为激活函数,但是使用ReLu可能有更好的梯度性质。

yt^=Vht+by\hat{y_t} = Vh_t + b_y

可以认为hth_t包含了之前的所有信息,所以使用hth_t来预测yty_t通过引入状态变量来使得递推公式在形式上是二阶依赖(来源于两个依赖)。

可以将RNN的结构看作两个维度的信息流:

  • 纵向(深度)方向:在单个时间步 tt 内,信息从输入 xtx_t 流经隐藏层 hth_t 到输出 yt^\hat{y_t}。这部分是一个标准的前馈网络,其训练挑战(如梯度消失/爆炸)与MLP或CNN类似。
  • 横向(时间)方向:信息从前一状态 ht1h_{t-1} 流向当前状态 hth_t。这是RNN特有的循环连接,也是其强大能力和主要训练难点(尤其是长程依赖导致的梯度问题)的根源。

Bidirectional&Deep RNN

这里纵向方向上的前馈网络中的训练难点在前面的MLP与CNN中是一样的,梯度消失和梯度爆炸。
上面的图中的yt,cy_{t,c}是真是标签的独热编码,CC是此表中的元素个数。

在横向方向上,梯度消失是很严重的。因为hth_t包含了ht1h_{t-1}的信息,所以梯度会在时间上指数级的衰减。解决这个问题的方法是LSTMGRU

RNN for LM

  • 理论上,可以表达没有边界的时间上的依赖,由于将状态变量编码为hth_thth_t包含了之前的所有信息。
  • 将序列编码到一个向量中,这个向量包含了整个序列的信息。
  • 参数在时间上是共享的
  • 但是在实际上,很难建模时间上的长时间依赖。对于较早的信息,后面的权重会很小。

一个模型是否有效,在于assumptions与实际情况是否匹配。

Architecture

1. Many to One
  • 任务: 情感分析、文本分类。
  • 结构: 输入一个序列,只在最后一个时间步 TT 产生一个输出。
  • 这里的核心假设是,最后一个隐藏状态 hTh_T 已经对整个序列的信息进行了充分的编码和总结。然而,有时序列的关键信息(如情感词)可能出现在中间,这促使了后续Attention等机制的发展。
2. One to Many
  • 任务: 图像描述生成、音乐生成。
  • 结构: 输入一个单独的向量(如图像特征),输出一个序列。
  • 通常,这个单一输入向量被用来初始化RNN的初始隐藏状态 h0h_0,或者在每个时间步都作为输入的一部分提供给RNN。
3. Many to Many
  • 同步 (Aligned):如视频逐帧分类、词性标注。输入序列和输出序列的长度严格对齐。
  • 异步 (Delayed/Autoregressive):如语言模型。输出序列是输入序列的错位版本(预测下一个词)。
4. Sequence to Sequence (Seq2Seq)
  • 任务: 机器翻译、对话系统、文本摘要。
  • 结构: 输入和输出都是序列,但长度不一定相同。这通常由一个编码器 (Encoder) 和一个解码器 (Decoder) 组成。
  • Encoder: 一个RNN,负责读取整个输入序列,并将其所有信息压缩成一个固定长度的上下文向量 (context vector) cc(通常是Encoder最后一个时间步的隐藏状态)。
  • Decoder: 另一个RNN,以该上下文向量 cc 为初始状态,逐步生成输出序列。

首先将输入变量{xt}\{x_t\}编码到状态变量{ht}\{h_t\}encoder,然后再将状态变量{ht}\{h_t\}解码到输出变量{yt}\{y_t\}decoder。编码器是没有loss function的,解码器接受的输入是编码器的输出,解码器的输出是一个概率分布。解码器的loss function是交叉熵损失函数。

在上面的图片中,W1,W2W_1,W_2是模型的参数,{xt},{yt},{ht}\{x_t\},\{y_t\},\{h_t\}是模型的变量,考虑中文翻译英文问题,可以将W1W_1理解为模型如何理解中文,W2W_2可以理解为如何将写出英文。

机器翻译任务中的挑战

  • 输入和输出是异构的
  • 长序列的处理

如何从概率中采样

  • 选择概率最大的
  • 概率较大的有更大的概率被选择
  • Beam Search贪心方法进行搜索

可以选择概率较大的k个词,然后以这个词为条件计算下一个词的条件概率,类似于构建一个真k叉树,这样的方法是一种贪心的方法。考虑这棵树上所有的路径,选择最大的路径(本质上是一种搜索技术)。

Backpropagation Through Time

LU=t=0TLtU=t=0Ts=0tLtytythththshsU\frac{\partial L}{\partial U} = \sum_{t=0}^T \frac{\partial L_{t}}{\partial U} = \sum_{t=0}^{T} \sum_{s=0}^t \frac{\partial L_{t}}{\partial y_t} \frac{\partial y_t}{\partial h_t} \frac{\partial h_t}{\partial h_s}\frac{\partial h_s}{\partial U}

前一个求和的意义是对于损失函数的各个部分求和,后面的求和式是对于hth_t的前面的每一个可能的链求和。
其中:

hths=i=s+1thihi1\frac{\partial h_t}{\partial h_s} = \prod_{i=s+1}^t \frac{\partial h_i}{\partial h_{i-1}}

这个式子是一个矩阵乘法,是一个矩阵的连乘。这个矩阵是一个雅可比矩阵。

Cauchy-Schwarz不等式可以证明:

htht1WTdiag(f(ht1))σmaxγ\| \frac{\partial h_t}{\partial h_{t-1}} \| \leq \| W^T \| \|diag (f'(h_{t-1}))\| \leq \sigma_{max} \gamma

这里σmax\sigma_{max}是矩阵WW的最大奇异值,γ\gamma是激活函数的导数的最大值。
于是:

hths=i=s+1thihi1(σmaxγ)ts\| \frac{\partial h_t}{\partial h_{s}} \| = \prod_{i=s+1}^t \| \frac{\partial h_i}{\partial h_{i-1}} \| \leq (\sigma_{max} \gamma)^{t-s}

这个式子说明了梯度消失的问题,梯度消失是指梯度在时间上的指数级衰减。或者梯度爆炸的问题,梯度爆炸是指梯度在时间上的指数级增长。

Truncated BPTT

这个方法是将时间上的梯度截断,这样可以减少梯度消失和梯度爆炸的问题。但是这样的方法会导致梯度的估计不准确,因为梯度的估计是基于一个截断的时间窗口的。

BPTT本质上就是将循环网络在时间维度上“展开”成一个深度前馈网络,然后应用标准的反向传播算法。计算损失函数 LL 对某个较早时刻 ss 的状态 hsh_s 的梯度时,链式法则要求我们连乘一系列雅可比矩阵:

hths=i=s+1thihi1=i=s+1tWhTdiag(f(hi1))\frac{\partial h_t}{\partial h_s} = \prod_{i=s+1}^t \frac{\partial h_i}{\partial h_{i-1}} = \prod_{i=s+1}^t W_h^T \text{diag}(f'(h_{i-1}))

这个连乘是问题的根源。如果雅可比矩阵的范数(由权重 WhW_h 和激活函数的导数决定)持续大于1,梯度会呈指数级增长,导致梯度爆炸;如果持续小于1,梯度会呈指数级消失,导致梯度消失

  • 问题根源: BPTT中梯度的计算涉及雅可比矩阵的长期连乘
  • 梯度爆炸 (Exploding Gradients): 权重过大导致梯度指数级增长。
  • 后果: 训练不稳定,参数更新过大导致NaN。解决方法: 梯度裁剪 (Gradient Clipping),即在梯度超过某个阈值时,强行将其缩放回来。
  • 梯度消失 (Vanishing Gradients): 权重过小导致梯度指数级衰减。后果: 模型无法学习到长程依赖关系,较早时刻的信息无法影响到后面的参数更新。解决方法: 门控机制 (Gating Mechanism),如LSTM和GRU。

Long Short-Term Memory

  • 遗忘,将过去“没用”的信息遗忘

  • 更新,将新的信息更新到状态变量中

  • 输出,输出门控制一部分信息用来进行预测

  • 细胞状态 ctc_t: 这是LSTM的核心。可以把它想象成一条“信息高速公路”或“传送带”,信息可以在上面很顺畅地流动,只进行少量的线性操作。这使得梯度能够更容易地在时间步之间传播。

  • 门 (Gates): LSTM有三个关键的门(遗忘门、输入门、输出门),它们都是小型的神经网络(通常是Sigmoid层),其输出在 [0, 1] 之间,用来控制信息的通过量。

    1. 遗忘门 (Forget Gate, ftf_t): 决定从旧的细胞状态 ct1c_{t-1}遗忘多少信息。
    2. 输入门 (Input Gate, iti_t): 决定让多少“候选新信息” c~t\tilde{c}_t 写入到当前细胞状态中。
    3. 输出门 (Output Gate, oto_t): 决定从更新后的细胞状态 ctc_t输出多少信息,作为当前时间步的隐藏状态 hth_t

tt时刻的状态变量hth_t储存的是tt时刻的信息,ctc_ttt时刻的记忆变量,ht1h_{t-1}xtx_ttt时刻的输入,ftf_t是遗忘门,iti_t是输入门,oto_t是输出门,gtg_t是更新门。

(ifog)=(σσσtanh)([WiWfWoWg][ht1xt]+[bibfbobg])\begin{pmatrix} i \\ f \\ o \\ g \end{pmatrix} = \begin{pmatrix} \sigma \\ \sigma \\ \sigma \\ \tanh \end{pmatrix} \left( \begin{bmatrix} W_i \\ W_f \\ W_o \\ W_g \end{bmatrix} \begin{bmatrix} h_{t-1} \\ x_t \end{bmatrix} + \begin{bmatrix} b_i \\ b_f \\ b_o \\ b_g \end{bmatrix} \right)

  1. 准备输入 (拼接 - Concatenation) 将上一个时间步的隐藏状态 h_{t-1} 和当前时间步的输入 x_t 在垂直方向上拼接成一个更长的向量。这是后续所有计算的统一输入。
  2. 线性变换 (Linear Transformation) 用一个堆叠起来的巨大权重矩阵 W (由W_i, W_f, W_o, W_g 四个独立矩阵堆叠而成) 与拼接后的输入向量进行一次矩阵乘法,并加上一个同样堆叠起来的偏置向量 b。 * 这一步是为了计算效率,通过一次大的并行计算,得到四个组件各自的“原始得分”。
  3. 非线性激活 (Element-wise Activation) 对上一步得到的“原始得分”向量进行分段处理,按元素应用不同的激活函数。
  • i, f, o, g 的维度是完全相同的
  • 它们的维度都等于LSTM层定义的一个核心超参数——隐藏维度 (hidden_size)

上述网络构造了一个信息流高速路径,使得梯度能够进行快速的传播。

遗忘门和残差网络的思想是类似的,都是将过去的信息和现在的信息进行融合。这样的网络可以更好的处理长序列的问题。[[DL Note-3 CNN#ResNet]]

  • 核心组件: 独立的细胞状态 (Cell State) ctc_t
  • 关键操作: ctc_t 的更新主要是加法 (ftct1+itc~tf_t \odot c_{t-1} + i_t \odot \tilde{c}_t),而不是像简单RNN中那样的矩阵乘法和非线性激活的嵌套。
  • 效果: 加法操作使得梯度在反向传播时能够更直接、更完整地传递,避免了连乘导致的指数级衰减。遗忘门和残差网络(ResNet)中的恒等映射思想有异曲同工之妙,都为信息/梯度提供了一条“高速公路”。

Gradient Clipping

梯度的大小是由模长决定的,如果梯度的模长过大,可以将梯度的模长进行截断。这样可以避免梯度爆炸的问题。

Variational Dropout

在深度网络中,如果是过拟和的,也就是对于一个含有多个参数的网络。也就是说如果输入的参数小于参数的个数,那么相对应的线性方程组是欠定的。

在RNN中对应的纵向方向上是多层感知机,所以可以采用标准的Dropout方法。但是在横向方向上是一个循环网络,Dropout方法不适用。因为Dropout方法会破坏时间上的连续性,违背了参数共享的原则。
采用步调一致的方法进行操作,这样可以保持时间上的连续性。这样的方法是Variational Dropout

Layer Normalization

在CNN中,对于每一个通道的值进行归一化。在这样的每一个通道中计算均值和方差。还是要加入一个平移变量和伸缩变量。

在RNN中,主要的原因是门控结构是相对于每一个序列而言的,所以应该引入一种新的归一化方法Layer Normalization,应该在每一条样本(一个序列)在每一个时刻经过之后的值在CC个通道上进行归一化操作。
最后得到的结果是:将所有的向量放在以原点为球心的单位球面上。

Weight Normalization

对于每层的参数w\mathbf{w}进行重参数化:

w=gvv\mathbf{w} = \frac{g}{\|v\|}v

对右边的式子vv\frac{v}{\|v\|}进行优化是更为容易的,重参数化的意思是,在训练和测试的时候使用不同的参数表达形式,这样是更加容易优化的。

Training-Inference Shift

滚动预测:在训练的时候,使用真实的标签进行预测;在测试的时候,使用的是推理得到的值进行预测。这是一个自回归任务。

Curriculum Learning

在训练的时候,可以先训练一些简单的任务,然后再训练一些复杂的任务。这样可以更好的训练模型。
在实际中,可以对所有的样本计算loss,先计算loss较小的样本,然后再计算loss较大的样本。这就是自步学习
这里涉及到选择不同的样本顺序的问题。

Scheduled Sampling:在学习刚开始的时候,更多地使用真实的标签进行预测;随着学习的进行,更多地使用模型预测的值进行预测。是RNN中很重要的技术


RNN with Attention

Human Attention

人类的注意力:

  • 可持续注意力(没有实现)
  • 选择性注意力(人类的选择性注意力复杂得多)
  • 交替式注意力
  • 分配式注意力

Attention in Deep Learning

Allowing the model to dynamically pay attention to only certain parts of the input that help in performing the task at hand effectively.

存在时间temporal Attention和空间Spatial Attention上的注意力。一般而言指的是时间上的注意力。

Auto-Regessive

最重要的问题是编码器和解码器之间的信息沟通太少了,存在有信息瓶颈。在翻译任务中就像必须先完整地听完一段很长的中文,然后闭上眼睛,仅凭脑中的一个模糊记忆,去完整地翻译出对应的英文。

并且在翻译任务中,输入和输出的顺序并不是一致的,大部分的语言的语序是不一样的。
希望看到后面的信息,这和RNN的设计目的是相违背的。全连接的思想又回来了,获得全局信息的方法有很多,不只是有MLP的方法。有一种基本思想是Relevance,也就是和当前任务相关的信息。这个思想是在Attention中得到了体现。

Attention

计算两个东西的相似度有:计算内积、输入relation network。这样的模型在互联网中有很多的应用,比如推荐系统、搜索引擎等。

注意力的分配是符合概率分布的,所以可以使用上面计算得到的相关性eije_{ij}使用softmax函数进行归一化。这样得到的分布就是注意力的分布:

αij=exp(eij)k=1Txexp(eik)\alpha_{ij} = \frac{\exp(e_{ij})}{\sum_{k=1}^{T_x} \exp(e_{ik})}

上述计算式表达的含义是,在状态ii的时刻分配在jj上的注意力(对于jj的求和为1)。继续计算cic_i

ci=j=1Txαijxjc_i = \sum_{j=1}^{T_x} \alpha_{ij} x_j

这里cic_i是对于状态ii的时刻的注意力向量,是对于xx的加权和。

si=f(si1,yi1,ci)s_i = f(s_{i-1},y_{i-1},c_i)

这里sis_i是状态变量,yi1y_{i-1}是前一个时刻的输出,cic_i是当前时刻的注意力向量。这里的函数ff是一个GRU or LSTM。这个模型是一个Seq2Seq模型。

这里的cic_isis_i的区别是什么,为什么和LSTM有关

在机器翻译的过程中,使用source的上下文信息比直接使用词典来翻译更好。这样的模型可以更好的处理长序列的问题。只要是序列都会使用滑动窗口,一般设置为50~100之间。对于较短的情况,可以使用psdding的方法;对于较长的情况会使用截断的方法。希望找一个与序列的长度线性关系的模型。

Attention vs. MLP

相同点:

  • 都是全局模型,是对于长序关系的建模。

不同点:

  • Attention是基于概率的,MLP是基于全连接的。
  • Attention引入relevance的思想,能大大减小参数量

Hierarchical Attention

先建模词注意力然后再建模句子注意力。

Global Attention

score={htThshtTWahsvaTtanh(Wa[ht;hs])\text{score} = \begin{cases} h_t^T \overline{h_s} \\ h_t^T W_a \overline{h_s} \\ v_a^T \tanh(W_a[h_t;\overline{h_s}]) \end{cases}

发现上面三种计算方式的效率是差不多的。

Memory

Human Memory

  • Sensory Memory
    • 计算机视觉与机器感知
  • Short-term Memory
    • 与计算机中的内存是很相近的,LSTM是一种将短期记忆尽量变长的方法。
  • Long-term Memory
    • 前面的模型中没有实现这个功能

在自然语言中,比较困难的任务是进行对话,这时候需要进行长期记忆。在对话中,需要对话的上下文进行理解。

Neural Turing Machine

在这个模型中,最重要的是对内存1进行寻址的操作,这个操作是一个注意力的操作。
对于读的操作,是按照注意力的大小对地址里面的内容进行加权平均。
对于写的操作,类似于LSTM中的Forget Gate,先进行擦除之后才进行写入。

对于Internal Memory,最大的问题是可能会遗忘,对于External Memory,是一个外部的存储器,这样的存储是比较稳定的。

  • 解决了信息瓶颈: 不再依赖于单一的、固定长度的上下文向量,而是为解码的每一步都生成一个动态的、量身定制的上下文向量。
  • 实现了“软对齐”: 注意力权重分布直观地显示了输入和输出序列之间的对齐关系,大大增强了模型的可解释性。
  • 有效处理长序列: 由于能够直接访问所有输入状态,模型处理长程依赖的能力得到质的飞跃。Attention机制是后续Transformer等更强大模型的基础。

DL Note-5 RNN
https://yima-gu.github.io/2025/07/28/Deep Learning/DL Note-5 RNN/
作者
Yima Gu
发布于
2025年7月28日
许可协议