一、如何处理序列信息
从分词到embedding是从文件到稠密词向量的过程,解决了模型输入的问题,即文本数值化。
第二个问题就是,如何从一个词向量序列中有效地提取整个序列的特征。
例如: 意图识别中,希望将“播放周杰伦的《稻香》”归类到“音乐播放”。目前能得到各词元的词向量,如何将这些向量融合成能表达证据指令含义的“文本向量”,并送入分类器呢?
1.1、简单方法的局限性
针对词向量序列融合成一个定长的文本向量,
早期解决方案
- 像词袋法一样,将所有向量相加或取平均。它的局限是忽略了语序信息。例如“我爱你”和“你爱我” 会得到完全相同的文本向量。 同时所有词视为同等重要。
- 使用全连接神经网络(FCN)。 具体处理方式是先求和再FCN或者先FCN再求和。同样无法理解词元之间的顺序关系和上下文依赖,也没有捕获序列特征。
3.使用CNN, 通过一维卷积核,滑过整个词向量。 缺陷是它的感受野是固定的。虽然可以通过堆叠多层CNN来扩大感受野,但是对于句子开头和结尾床距离依赖,CNN让然难以有效捕捉,无法预先设定一个适用于所有句子的最佳窗口大小。
二、 引入“记忆”的RNN
RNN 能够记住在处理当前词元之前都看过了哪些信息。

(1)输入 Xt: 作为每一个时间步的输入, 通过权重矩阵U连接到隐藏层。
(2)前一个时刻的隐藏状态(ht-1): hidden_state,通过循环权重矩阵W连接到隐藏层。
(3) 当前时刻的隐藏状态(ht): 当前时刻输出的新隐藏状态。
(4) 状态更新: ht-1到ht的过程
(5) 当前的隐藏状态ht也可以被用来计算当前时间步的最终输出。
❓ U和W 为什么设计为“时间步上参数共享”?
- 处理变长序列
模型不依赖固定序列长度。训练时学10步的规律,推理时可处理100步的输入(因每步用同一套规则)。- 大幅减少参数量:若每步用独立参数(如U₁, U₂...),参数量随序列长度爆炸增长,极易过拟合。共享后参数量仅由隐藏层维度决定(与序列长度无关)。
- 学习时序模式:共享的W使模型能捕捉“任意时间间隔的依赖”(如“主语→谓语”的关系),而非仅记住特定位置的模式。
- ** 平移不变性** : 相同模式出现在序列不同位置时(如“下雨”在句首或句尾),模型能用相同逻辑处理,提升泛化能力。
- 理论与生物启发: 模拟人类处理语言/时间序列的方式:用同一套认知规则处理不同时刻的信息。
三、RNN工作原理解析
3.1 文本分类实例

举例: 给“播放周杰伦的《稻香》”进行分类。
- 分词: ["播放", "周杰伦", "的", "《稻香》"], 转为ID序列 [23, 58, 102, 203](假设), embedding 得到4个词向量。 输入序列形状为(4,128)
- 进入RNN 逐步按顺序逐步处理, hidden_state 维度为H=64。 初始化h0一般为零向量。
(1) 第一步 t=1, 输入为x1="播放" 和隐藏状态 h0, 计算h1, h1得到了包含“播放”的信息。
(2)第二步 t=2, 输入x2="周杰伦" 和隐藏状态h1, 计算h2, h2得到了包含“播放”和“周杰伦”的信息。
(3)第三步 t=3, 输入 x3="的" 和隐藏状态h2, 计算h3, h3得到了包含“播放周杰伦的”的信息
(4) 第四步,t=4, 输入x4="《稻香》"和隐藏状态h3, 计算h4,h4得到了整个句子的信息。
最后h4被认为是整个句子动态上下文表示,也就是我们需要的“文本向量”。它捕获了整个句子的语序和语义信息。将h4送入全连接分类层,则可以得到各类别的置信度了。
通过这种方式RNN成功地将一个变长的词向量序列,编码成了一个蕴含序列信息的固定长度的特征向量。
3.2 从静态到动态的飞跃
RNN解决了静态词向量的局限性,实现了Type到Token的跨越。
静态的Type(词嵌入)体现在word2vec等模型中,学到字典中的静态语义。
RNN 通过隐藏状态ht则实现了动态的Token表示。
动态词向量:指的他是基于文本上下文产生的,而不是固定的向量。
ELMO? 动态词向量
四、从零实现一个RNN
五、双向循环神经网络
上边单向RNN, 信息只利用了t时刻和之前的信息,但是自然语言处理任务重,一个词通常依赖于上文也依赖于下文。例如 “苹果味道不错”,只看上文不知道苹果是指水果还是苹果公司。
为了利用未来信息,提出了双向循环神经网络,同时利用过去和未来的上下文信息。
5.1 BiRNN结构与原理
原理是由两个完全独立的RNN构成,并将他们叠加进行处理。一个是正向的,一个是反向的。

注意: 正香和反向的两个RNN拥有各自独立的权重参数,训练中被同事优化。
为什么不直接训练两个独立的RNN然后合并结果
BiRNN 可以在同一个Loss下同事训练两个方向的权重,这样能更好的适应目标任务。
最终输出是两个独立RNN的隐藏状态的拼接,如果每个RNN的hidden_size为H,那么BiRNN在每个时间步的输出维度将变为2H。
在Pytorch中,设置bidirectional为True。隐藏状态存储的第一个维度为num_layers*2,分别存储了正向和反向RNN在最后一个时间步的隐藏状态。
5.2 BiRNN的作用与局限
作用: 提取了更完整的上下文相关的特征,使得在许多NLP任务重(如命名实体识别、情感分析、机器翻译等)都取得了比单向RNN更好的效果。
局限:没有解决长距离依赖问题,依然会面临梯度消失或梯度爆炸的挑战。BiRNN因为需要处理完整的序列才能计算反向信息,所以无法被用于需要实时预测的场景。
六、随时间反向传播
BPTT(随时间反向传播):将RNN沿着时间维度展开,可视作一个各层参数共享的深层前馈网络,在这个结构上执行通用的反向传播算法。
假设整个序列的总损失L是所有时间步损失Lt的总和。
目标则是计算损失L对共享参数U和W的梯度。




这个连乘的形式正式RNN产生问题的根源所在。
七、 RNN的局限性
7.1 梯度消失与梯度爆炸
连乘导致小于1的数连乘会越来越小,导致梯度消失。 大于1的数连乘会导致梯度越来越大,导致梯度爆炸。常见梯度爆炸的解决办法是梯度裁剪,也就是梯度的范数超过某个阈值时,就将其缩放到该阈值。
7.2 长距离依赖
梯度消失导致了长距离依赖问题。
(1)反向传播视角: 梯度消失导致最开始的词的权重衰减为零。无法捕捉到远距离的语义依赖。
(2)正向传播视角: 信息遗忘或近期偏执。正向计算过程中,每一步的信息都会被新的输入和循环权重W 稀释或覆盖。经过足够多的时间步后,序列最初的信息在隐藏状态中所剩无几,导致模型遗忘了最初的差异。
7.3 单向性
常规RNN信息流是单向的,双向循环网络结合正向和反向信息流来解决单向性问题。 为了学习更复杂的特征表示,可以把多个RNN堆叠起来,构成深度循环神经网络。但是都没有从根本上解决梯度传播带来的长距离依赖问题。
研究者发明了两种更精巧的门控RNN结构,分别是长短记忆网络和门控循环单元。
总结
- 如何处理序列信息?
简单方法: 类似词袋法加权; 使用FCN等。 这些都是孤立处理,无法捕获上下文依赖以及序列特征。CNN (感受野有限,无法捕捉长距离依赖) - 引入记忆RNN
- RNN工作原理
输入是当前时间步的输入x和上一层的隐藏状态,有相同的U和W权重,每一个时间步计算之后都会更新权重,并输出新的隐藏状态。
这个最终的输出可以作为该文本向量,也就是动态向量。 - RNN实现
- BiRNN: 能够结合前文和后文的上下文信息,拼接前向和反向RNN的隐藏状态,共同优化权重。
- 随时间反向传播: Loss是每个时间步的损失之和
- RNN的局限性: 存在梯度爆炸或者梯度消失问题,无法解决长距离依赖问题。