深度学习3:长短期神经网络LSTM
- 🍨 本文为🔗365天深度学习训练营中的学习记录博客
- 🍖 原作者:K同学啊
一 LSTM基本概念
1 LSTM定义
长短期记忆网络(Long Short-Term Memory,LSTM)是一种改进的循环神经网络(RNN)结构,由 Hochreiter 和 Schmidhuber 于 1997 年提出。它通过在网络中引入“门控机制”(Gating Mechanism)与“记忆单元”(Cell State),能够在序列数据中有选择地保留或遗忘信息,从而有效解决传统 RNN 在长序列训练中容易出现的梯度消失与梯度爆炸问题。
LSTM 的核心思想是让模型既能记住长期依赖的信息,又能对短期变化做出响应,因此被广泛应用于自然语言处理、时间序列预测、语音识别等需要捕捉长距离依赖关系的任务中。

2 传统RNN存在的问题
循环神经网络(RNN)的核心思想是通过“循环结构”让前一时刻的隐藏状态 ht-1 参与当前时刻的计算,从而在时间维度上传递信息。这使得 RNN 理论上可以利用序列中的上下文信息,理解“前因后果”。然而在实际训练中,RNN 会遇到两个关键问题,具体如下所示。
2.1 梯度消失与梯度爆炸(Vanishing/Exploding Gradient)
在反向传播过程中,梯度需要沿时间维度不断传递和相乘。当序列较长时,梯度会被反复缩小或放大,导致前面时间步的参数几乎得不到有效更新。结果是——模型只能记住“短期信息”,而“远处的信息”被遗忘。
2.2无法捕捉长距离依赖(Long-term Dependency)
在短语句中,RNN 可以根据临近的上下文完成预测,比如 “the clouds are in the ?” 很容易预测出 “sky”;但在长句中,如 “I grew up in France ... I speak fluent ?”,预测 “French” 需要模型记住很久以前的“France”信息。普通 RNN 无法保持这种长时间跨度的记忆,从而失去语义关联。


简而言之,RNN 善于记忆“近处”,却难以记住“远方”。这正是 LSTM 被提出的原因——通过更精细的“记忆控制机制”,解决 RNN 在长序列建模中的遗忘问题。
3 LSTM核心思想
面对 RNN 中梯度消失和长期依赖无法捕捉的问题,LSTM(Long Short-Term Memory) 的核心创新在于:它在结构中引入了一个 “记忆单元(Cell State)” 与 “门控机制(Gating Mechanism)”,让网络可以有选择地记住重要信息、遗忘无关信息,从而在长序列中保持稳定的梯度流。


3.1 Cell状态
普通 RNN 的隐藏状态 ht 既要负责短期的输出,又要传递长期的记忆,任务过于繁重。而 LSTM 将这两者分开:隐藏状态 ht:负责当前时刻的输出;记忆单元 Ct:负责跨时间步的长期信息保存,它可以从上一时刻直接通到下一时刻。

这种设计让梯度可以沿着 Ct 这条“几乎无衰减的高速通道”直接传播,避免了传统 RNN 的梯度消失问题。
3.2 门
如果 LSTM 只是原封不动地保存之前的记忆,那就没有太多价值。它还必须根据需要,能够增加新的记忆,同时擦除旧的无用记忆。LSTM 是通过一种叫作“门”的机制来控制怎么擦除旧记忆、写入新记忆的,下面我们逐步来介绍这种机制。

如上图所示,门可以用来控制信息是否能够通过。它是一个激活函数为 sigmoid 的层,
0表示阻止任何信息通过,1表示所有信息通过,而 0∼1之间的值表示部分通过。
3.2.1 遗忘门
ft 叫做遗忘门(Forget Gate),表示上一个时间步传下来的记忆 Ct−1 中,哪些信息应该保留,哪些应该被遗忘。遗忘门激活函数为:
3.2.2 输入门
输入门的作用是控制“当前输入 xt 和 前一时刻隐状态 ht−1”中提取出的新信息,有多少比例能够进入记忆单元 Ct。输入门由两个部分组成:输入门系数 it 与输入门候选值 C~t。

(1)输入门系数
(2)输入门候选值
(3)输入门工作机制
最终结果会被加入到 Cell 状态更新公式中:

3.2.3 输出门
输出门决定了“记忆单元 Ct 中哪些信息需要被输出到隐藏状态 ht,即哪些内容可以被当前时间步传递到下一个时间步或外部网络。输出门由两部分组成:计算输出门激活值 ot、计算当前隐藏状态 ht。

(1)计算输出门激活值 ot
(2)计算当前隐藏状态 ht
总体而言,LSTM 通过遗忘门、输入门与输出门的协同控制,实现了对信息流的选择性记忆与抑制。这种“门控记忆机制”使得网络能够在时间序列中保留重要的上下文特征,并抑制无关或过时的内容,从而显著提升了长序列建模的稳定性和表达能力。
二 Pytorch实现
1 LSTM函数原型
torch.nn.LSTM(
input_size,
hidden_size,
num_layers=1,
bias=True,
batch_first=False,
dropout=0,
bidirectional=False
)
2 参数说明
-
input_size:输入特征的维度。
-
hidden_size:隐藏状态的维度,也是输出特征的维度。
-
num_layers(可选参数):LSTM 的层数(即堆叠的 LSTM 层数)。
-
默认值为 1,表示只有一层 LSTM。
-
如果设置为 2,则会堆叠 2 层 LSTM,每一层的输入是前一层的输出。
-
-
bias(可选参数):是否使用偏置项,默认值为
True。 -
batch_first(可选参数):是否将输入和输出的第一个维度视为批量大小。
-
默认值
False,输入数据的形状为(seq_len, batch_size, input_size)。 -
如果为
True,输入和输出张量形状为(batch_size, seq_len, feature_size)。 -
通常在处理序列数据时,
batch_first=True更符合常见的数据格式。
-
-
dropout(可选参数):在 LSTM 层之间的 dropout 比例。
-
仅当有多层 LSTM (
num_layers > 1) 时生效。 -
dropout 会在不同层之间随机“丢弃”部分神经元连接,用于防止过拟合。
-
-
bidirectional(可选参数):是否使用双向 LSTM,默认值为
False。-
如果为
True,LSTM 会同时学习正向和反向的序列信息,增强模型对上下文的理解。 -
当使用双向 LSTM 时,输出张量的形状中
hidden_size会变为hidden_size * 2。
-
3 LSTM的输入
LSTM 接受的输入是一个三维张量:
-
如果
batch_first=False:输入形状为 (seq_len, batch_size, input_size) -
如果
batch_first=True:输入形状为 (batch_size, seq_len, input_size)
其中:
-
seq_len:序列的长度,即时间步数。
-
batch_size:每个批次的样本数。
-
input_size:每个时间步输入数据的特征维度。
⚠️ 若输入为二维数据:PyTorch 会自动把二维张量视为一个“序列”,而不是一个 “batch”。
也就是说,它默认你只有一个样本。这样效果会大打折扣,记得将二维数据修改为三维数据。
4 LSTM的输出
当我们通过 lstm(input_data) 进行前向传播时,LSTM 会返回两个输出:
1️⃣ output:LSTM 层的最终输出(所有时间步的输出)。
2️⃣ (h_n, c_n):LSTM 的隐藏状态和细胞状态,即上图中的 ht与 Ct。
🔹 output
output 是 LSTM 对每个时间步输出的隐藏状态。
-
若
batch_first=False:输出形状为 (seq_len, batch_size, hidden_size),即每个时间步对应一个隐藏状态向量。 -
若
batch_first=True:输出形状为 (batch_size, seq_len, hidden_size)。
示例:
-
输入形状为 (5, 2, 10),
hidden_size=20,则output的形状为 (5, 2, 20)。 -
每个时间步的输出表示输入数据经过 LSTM 后得到的隐藏状态。
🔹 h_n(隐藏状态)
h_n 是 LSTM 在最后一个时间步的隐藏状态,表示序列的最终输出(可用于后续任务,如分类等)。
-
h_n的形状为 (num_layers, batch_size, hidden_size)。 -
若有多层 LSTM,
h_n会包含所有层的隐藏状态(最上层为最后的隐藏状态)。
示例:
-
若
num_layers=1,h_n形状为 (1, 2, 20)。 -
若
num_layers=2,h_n形状为 (2, 2, 20),表示有两层 LSTM,每层的最后一个时间步的隐藏状态。
🔹 c_n(细胞状态)
c_n 是 LSTM 中细胞状态的最后一个时间步的输出,它保留了长期的记忆信息。
-
c_n的形状与h_n相同:(num_layers, batch_size, hidden_size)。
示例:
-
若
num_layers=1,c_n形状为 (1, 2, 20)。 -
若
num_layers=2,c_n形状为 (2, 2, 20)。
5 示例
import torch
import torch.nn as nn
# 定义一个单向 LSTM 模型
input_size = 10 # 输入特征维度
hidden_size = 20 # 隐藏层维度
num_layers = 2 # LSTM 层数
batch_size = 3 # 每批次样本数
seq_len = 5 # 序列长度(时间步数)
# 初始化 LSTM 模型
lstm = nn.LSTM(input_size, hidden_size, num_layers)
# 构造一个输入张量
input_tensor = torch.randn(seq_len, batch_size, input_size)
# 将输入传递给 LSTM 模型
output, (hn, cn) = lstm(input_tensor)
# 打印输出张量的形状
print("Output shape:", output.shape) # 输出特征的形状
print("Hidden state shape:", hn.shape) # 最后一个时间步的隐藏状态形状
print("Cell state shape:", cn.shape) # 最后一个时间步的细胞状态形状
更多推荐
所有评论(0)