Skip to content
2026-09-29 04:201851 字NLPRNN深度学习

RNN的基础概念 ​

什么是RNN模型 ​
  • RNN(Recurrent Neural Network,循环神经网络)

  • 一般以序列数据为输入, 通过网络内部的结构设计有效捕捉序列之间的关系特征, 一般也是以序列形式进行输出.

  • RNN单层网络结构

  • 以时间步对RNN进行展开后的单层网络结构:

  • RNN的循环机制使模型隐层上一时间步产生的结果, 能够作为当下时间步输入的一部分(当下时间步的输入除了正常的输入外还包括上一步的隐层输出)对当下时间步的输出产生影响.

RNN的作用 ​

因为RNN结构能够很好利用序列之间的关系, 因此针对自然界具有连续性的输入序列, 如人类的语言, 语音等进行很好的处理, 广泛应用于NLP领域的各项任务, 如文本分类, 情感分析, 意图识别, 机器翻译等.

RNN的分类 ​
  • 按照RNN的内部构造进行分类:

    • 传统RNN
    • LSTM
    • Bi-LSTM
    • GRU
    • Bi-GRU
  • 按照输入和输出的结构进行分类:

    • N vs N - RNN
    • N vs 1 - RNN
    • 1 vs N - RNN
    • N vs M - RNN

传统RNN ​

RNN 结构分析 ​

本次的输出 = 权重矩阵 * [本次的输入, 上一时刻的隐藏状态] + 本次的偏置

优缺点 ​

代码示例 ​
python
import torch
import torch.nn as nn

def rnn_base():
    # 创建RNN模型
    rnn = nn.RNN(input_size=10, hidden_size=6, num_layers=1)
    # - input_size: 输入的维度(词嵌入的维度、词向量维度)
    # - hidden_size: 隐藏层的维度(输出维度)
    # - num_layers: 隐藏层的层数
    input = torch.randn(5, 3, 10)  # (seq_len, batch_size, input_size)
    h0 = torch.randn(1, 3, 6)      # (num_layers, batch_size, hidden_size)
    # 实例化模型
    output, hn = rnn(input, h0)
    print(rnn)  # 输出模型结构 - (10, 6)
    print(output.shape)  # (seq_len, batch_size, hidden_size) - [5, 3, 6]
    print(hn.shape)      # (num_layers, batch_size, hidden_size) - [1, 3, 6]
    '''修改句子长度 seq_len'''
    input = torch.randn(20, 3, 10)  # 5 -> 20
    h0 = torch.randn(1, 3, 6)
    output, hn = rnn(input, h0)
    print(output.shape)  # [5, 3, 6] -> [20, 3, 6]
    print(hn.shape)      # [1, 3, 6]
    '''修改隐藏层的层数 num_layers'''
    input = torch.randn(5, 3, 10)
    h0 = torch.randn(2, 3, 6)  # 1 -> 2
    rnn = nn.RNN(input_size=10, hidden_size=6, num_layers=2)
    output, hn = rnn(input, h0)
    print(output.shape)  # [5, 3, 6]
    print(hn.shape)      # [1, 3, 6] -> [2, 3, 6]


rnn_base()

LSTM ​

  • LSTM(Long Short-Term Memory,长短时记忆结构)是传统RNN的变体

  • 与经典RNN相比能够有效捕捉长序列之间的语义关联,缓解梯度消失或爆炸现象

  • 同时LSTM的结构更复杂, 它的核心结构可以分为四个部分去解析:

    • 遗忘门
    • 输入门
    • 细胞状态
    • 输出门
  • LTSM的核心:3个门 + 1个记忆细胞。

    把LSTM想象成一个小房间,里面有:

    • 3个门(开关):遗忘门、输入门、输出门,分别控制信息的留、进、出
    • 1个记忆细胞(cell):专门存重要的信息,相当于“长期记忆本”

    整理流程总结:有点像管家整理记忆

    • 遗忘门:筛选旧记忆(丢垃圾)-> 更新长期记忆本
    • 输入门:筛选新信息(捡宝贝)-> 加到长期记忆本
    • 记忆细胞:长期保存关键信息(记到小本本中)
    • 输出门:筛选要传递的记忆(挑重点)-> 传递给下一个管家
LSTM 结构分析 ​

优缺点 ​
  • 优点:LSTM的门结构能够有效减缓长序列问题中可能出现的梯度消失或爆炸, 虽然并不能杜绝这种现象, 但在更长的序列问题上表现优于传统RNN.
  • 缺点:由于内部结构相对较复杂, 因此训练效率在同等算力下较传统RNN低很多.
代码示例 ​
python
import torch
import torch.nn as nn

def lstm_base():
    # 创建LSTM模型
    lstm = nn.LSTM(input_size=5, hidden_size=6, num_layers=1)
    input = torch.randn(5, 3, 5)  # (seq_len, batch_size, input_size)
    h0 = torch.randn(1, 3, 6)     # (num_layers, batch_size, hidden_size)
    c0 = torch.randn(1, 3, 6)     # (num_layers, batch_size, hidden_size)
    output, (hn, cn) = lstm(input, (h0, c0))  
    print(lstm)
    print(output.shape)  # [5, 3, 6] - (seq_len, batch_size, hidden_size)
    print(hn.shape)      # [1, 3, 6] - (num_layers, batch_size, hidden_size)
    print(cn.shape)      # [1, 3, 6] - (num_layers, batch_size, hidden_size)

lstm_base()

Bi-LSTM ​

  • Bi-LSTM 即:双向LSTM,它没有改变LSTM本身任何的内部结构
  • 只是将LSTM应用两次且方向不同, 再将两次得到的LSTM结果进行拼接作为最终输出

GRU ​

  • GRU(Gated Recurrent Unit)也称门控循环单元结构

    对比LSTM,为什么还需要GRU?

    LSTM靠‘三个门+记忆细胞’接近长序列记忆问题,但是结构复杂,计算慢

    GRU想的是“能否简化结构,又保留智能记忆的功能”,它把LSTM的部分门合并,变成了更轻量的“记忆管家”,训练更快,还能解决长序列问题

  • 它也是传统RNN的变体, 同LSTM一样能够有效捕捉长序列之间的语义关联, 缓解梯度消失或爆炸现象.

  • 同时它的结构和计算要比LSTM更简单, 它的核心结构可以分为两个部分去解析:

    • 更新门
    • 重置门
  • GRU的核心:两个门+1个隐藏状态

    • 两个门:重置门+更新门 -> 对比LSTM少1个门,更简单
    • 隐藏状态:存关键信息,相当于“记忆本”,比LSTM的记忆细胞更简单
GRU 结构分析 ​

优缺点 ​
  • GRU的优势:GRU和LSTM作用相同, 在捕捉长序列语义关联时, 能有效抑制梯度消失或爆炸, 效果都优于传统RNN且计算复杂度相比LSTM要小.
  • GRU的缺点:GRU仍然不能完全解决梯度消失问题, 同时其作用RNN的变体, 有着RNN结构本身的一大弊端, 即不可并行计算, 这在数据量和模型体量逐步增大的未来, 是RNN发展的关键瓶颈.
代码示例 ​
python
import torch
import torch.nn as nn

def lstm_base():
    # 创建LSTM模型
    gru = nn.GRU(input_size=5, hidden_size=6, num_layers=1)
    input = torch.randn(5, 3, 5)  # (seq_len, batch_size, input_size)
    h0 = torch.randn(1, 3, 6)     # (num_layers, batch_size, hidden_size)
    output, hn = gru(input, h0)
    print(gru)
    print(output.shape)  # [5, 3, 6] - (seq_len, batch_size, hidden_size)
    print(hn.shape)      # [1, 3, 6] - (num_layers, batch_size, hidden_size)

lstm_base()

Bi-GRU ​

Bi-GRU与Bi-LSTM的逻辑相同, 都是不改变其内部结构, 而是将模型应用两次且方向不同, 再将两次得到的GRU结果进行拼接作为最终输出

‍

每一篇文章,都是时间的标本