AI 术语通俗词典:LSTM
LSTM 是深度学习、循环神经网络、自然语言处理、时间序列预测和人工智能模型训练中非常经典的一个术语,全称是 Long Short-Term Memory,通常翻译为“长短期记忆网络”。它用来描述一种能够在序列数据中保留较长时间依赖关系的神经网络结构。换句话说,LSTM 是在回答:模型怎样在处理一串连续数据时,既记住前面重要信息,又忘掉不重要信息。
如果说普通前馈神经网络主要处理固定输入,卷积神经网络擅长提取局部空间特征,那么 LSTM 更强调“按时间顺序处理信息”。它不是一次只看一个孤立样本,而是沿着序列一步步读取输入,并通过内部状态保存历史信息。
因此,LSTM 常用于文本建模、语音识别、机器翻译、时间序列预测、金融数据分析、传感器数据建模和早期序列生成任务中,是理解循环神经网络和序列建模的重要基础概念。
一、基本概念:什么是 LSTM
LSTM 是一种特殊的循环神经网络(Recurrent Neural Network,RNN)。
普通 RNN 在处理序列时,会把上一步的隐藏状态传递到下一步:
x₁ → h₁ → h₂ → h₃ → ... → hₜ
其中:
• xₜ 表示第 t 个时间步的输入
• hₜ 表示第 t 个时间步的隐藏状态
这种结构可以让模型利用之前的信息。
但是,普通 RNN 在长序列中容易出现梯度消失或梯度爆炸问题,导致模型很难记住很久以前的信息。
LSTM 的核心改进是:在普通隐藏状态之外,引入一个专门保存长期信息的“细胞状态”。
LSTM 在每个时间步通常维护两个状态:
• hₜ:隐藏状态,表示当前时间步的短期输出信息
• cₜ:细胞状态,表示沿时间传递的长期记忆信息
可以简单表示为:
输入 xₜ + 上一步状态 hₜ₋₁, cₜ₋₁ ↓ LSTM 单元 ↓输出 hₜ + 新状态 cₜ从通俗角度看,LSTM 像一个带记忆本的读者:
• hₜ 是当前读到这一刻的理解
• cₜ 是一路保留下来的重要笔记
• 门控机制决定哪些内容要写入、保留或输出
因此,LSTM 不是简单地把信息一路传下去,而是通过门控结构控制信息流动。
二、为什么需要 LSTM
LSTM 之所以重要,是因为很多数据不是孤立样本,而是有顺序、有上下文、有前后依赖的序列。
例如:
• 一句话中,后面的词依赖前面的语境
• 一段语音中,当前音素依赖前后发音
• 股票价格中,当前走势依赖历史变化
• 传感器数据中,当前状态依赖过去状态
• 用户行为序列中,当前点击可能依赖之前兴趣
普通神经网络如果只看当前输入,很难处理这类问题。
普通 RNN 虽然可以传递历史信息,但它在长序列中常遇到一个问题:距离当前时间步越远的信息,越难被有效保留下来。
例如,在句子:
这本书虽然前面铺垫很长,但最后的结局非常精彩。模型要理解“精彩”评价的是“结局”,也需要结合前文语境。如果序列很长,普通 RNN 可能逐渐遗忘前面信息。
LSTM 通过细胞状态和门控机制缓解这一问题。
从通俗角度看:普通 RNN 像只靠脑子临时记忆;LSTM 像一边读一边做笔记,并且会判断哪些笔记该保留、哪些该擦掉。
LSTM 的主要目标是:
• 记住重要的长期信息
• 忘掉不重要或过时的信息
• 缓解长序列中的梯度消失问题
• 更稳定地处理时间序列和文本序列
三、LSTM 的核心结构:细胞状态与三个门
LSTM 的核心结构可以概括为:
细胞状态 + 三个门
其中,细胞状态负责保存长期信息,三个门负责控制信息如何流动。
三个门分别是:
• 遗忘门
• 输入门
• 输出门
图 1:LSTM 的核心结构
1、细胞状态:长期记忆通道
细胞状态 cₜ 是 LSTM 中最关键的记忆通道。
它沿着时间方向传递,可以把重要信息保留较长时间。
可以简单理解为:
cₜ₋₁ → cₜ → cₜ₊₁
从通俗角度看:细胞状态像一条贯穿整个序列的“记忆主线”。
LSTM 不会每一步都完全重写这条主线,而是通过门控机制决定:
• 哪些旧信息继续保留
• 哪些旧信息应该忘记
• 哪些新信息应该写入
2、遗忘门:决定忘掉什么
遗忘门决定上一时刻的细胞状态 cₜ₋₁ 中哪些信息应该保留,哪些应该丢弃。
遗忘门输出通常在 0 到 1 之间:
• 接近 1 表示保留
• 接近 0 表示遗忘
3、输入门:决定写入什么
输入门决定当前输入中的哪些新信息应该写入细胞状态。
它通常和候选记忆一起工作。
输入门控制“写不写”,候选记忆提供“写什么”。
4、输出门:决定输出什么
输出门决定当前细胞状态中的哪些信息应该作为隐藏状态 hₜ 输出。
隐藏状态 hₜ 会传给下一时间步,也可能用于当前任务预测。
从通俗角度看:
• 遗忘门:旧笔记哪些要擦掉
• 输入门:新内容哪些要写入
• 输出门:当前哪些记忆要拿出来使用
四、LSTM 的计算过程
在每个时间步 t,LSTM 会接收当前输入 xₜ、上一时间步隐藏状态 hₜ₋₁ 和上一时间步细胞状态 cₜ₋₁。
它会计算新的隐藏状态 hₜ 和新的细胞状态 cₜ。
1、遗忘门
遗忘门通常写为:
其中:
• fₜ 表示遗忘门输出
• σ 表示 Sigmoid 函数
• W_f 表示遗忘门权重矩阵
• b_f 表示遗忘门偏置
• hₜ₋₁ 表示上一时间步隐藏状态
• xₜ 表示当前时间步输入
• [hₜ₋₁, xₜ] 表示把二者拼接起来
fₜ 中的每个值都在 0 到 1 之间,用来控制旧记忆 cₜ₋₁ 的保留比例。
2、输入门与候选记忆
输入门为:
候选记忆为:
其中:
• iₜ 表示输入门输出
• c̃ₜ 表示候选细胞状态
• tanh 用于生成候选记忆内容
输入门 iₜ 决定候选记忆 c̃ₜ 中哪些部分应该写入长期记忆。
3、更新细胞状态
细胞状态更新为:
其中:
• cₜ 表示当前时间步细胞状态
• cₜ₋₁ 表示上一时间步细胞状态
• fₜ ⊙ cₜ₋₁ 表示保留下来的旧记忆
• iₜ ⊙ c̃ₜ 表示写入的新记忆
• ⊙ 表示逐元素相乘
这一步是 LSTM 的核心。
从通俗角度看:
当前长期记忆 = 保留下来的旧记忆 + 写入的新记忆
4、输出门与隐藏状态
输出门为:
隐藏状态为:
其中:
• oₜ 表示输出门输出
• hₜ 表示当前时间步隐藏状态
• tanh(cₜ) 表示把细胞状态转换到适合输出的范围
从通俗角度看:输出门决定当前长期记忆中哪些内容要表现出来,形成当前输出 hₜ。
五、LSTM 如何缓解长期依赖问题
长期依赖问题是指:模型需要利用较早时间步的信息,但普通 RNN 难以长期保留这些信息。
普通 RNN 的隐藏状态每一步都被重新计算,长期信息容易在连续变换中逐渐消失。
LSTM 通过细胞状态 cₜ 提供了一条相对稳定的信息通道。
在细胞状态更新公式中:
旧记忆 cₜ₋₁ 可以通过遗忘门 fₜ 被部分保留下来。
如果某些维度的 fₜ 接近 1,那么这些信息可以较长时间地传递下去。
从通俗角度看:LSTM 的长期记忆不是每一步都被完全重写,而是可以沿着时间线持续保留。
这有助于缓解普通 RNN 中常见的梯度消失问题。
不过,需要注意:LSTM 只能缓解长期依赖问题,并不能彻底解决所有长距离建模问题。
当序列非常长、依赖非常复杂时,LSTM 仍然可能困难。这也是后来 Transformer 和注意力机制在长文本建模中广泛使用的重要原因之一。
六、LSTM 与普通 RNN、GRU 的区别
LSTM 经常与普通 RNN 和 GRU 一起比较。
图 2:普通 RNN、LSTM、GRU 的比较
1、普通 RNN
普通 RNN 的结构比较简单,通常只维护隐藏状态 hₜ:
其中:
• hₜ 表示当前隐藏状态
• hₜ₋₁ 表示上一时间步隐藏状态
• xₜ 表示当前输入
普通 RNN 结构简单,但在长序列中容易遗忘早期信息。
2、LSTM
LSTM 同时维护隐藏状态 hₜ 和细胞状态 cₜ,并通过三个门控制信息流动。
它的特点是:
• 结构较复杂
• 参数量较多
• 能较好处理长期依赖
• 训练通常比普通 RNN 更稳定
3、GRU
GRU 是 Gated Recurrent Unit,通常翻译为“门控循环单元”。它可以看作一种比 LSTM 更简化的门控循环网络。
GRU 通常没有单独的细胞状态,而是使用更新门和重置门控制隐藏状态。
从通俗角度看:
• 普通 RNN:简单记忆
• LSTM:长期记忆 + 三个门
• GRU:简化门控记忆
可以概括为:
• 普通 RNN:结构简单,但容易遗忘长期信息
• LSTM:门控更完整,适合较复杂长期依赖
• GRU:结构更简洁,计算成本通常较低
在实际任务中,LSTM 和 GRU 没有绝对优劣,需要根据数据规模、序列长度、任务类型和计算资源选择。
七、LSTM 的常见应用场景
LSTM 适合处理具有时间顺序或序列结构的数据。
1、自然语言处理
在 Transformer 普及之前,LSTM 是自然语言处理中的重要结构。
它曾广泛用于:
• 文本分类
• 情感分析
• 机器翻译
• 序列标注
• 语言建模
• 文本生成
例如,在情感分析中,LSTM 可以按顺序读取一句话,并把前后语境压缩到隐藏状态中,用于判断整体情感。
2、时间序列预测
LSTM 常用于处理时间序列数据,例如:
• 股票价格
• 电力负荷
• 气温变化
• 交通流量
• 传感器读数
这些数据的当前值往往依赖历史趋势,LSTM 可以利用过去时间步的信息预测未来变化。
3、语音与音频序列
语音信号天然具有时间顺序。
LSTM 可以按时间步处理声学特征,用于语音识别、语音情感分析和音频事件检测等任务。
4、用户行为序列
在推荐系统中,用户行为通常也是序列:
浏览商品 → 点击商品 → 加入购物车 → 购买
LSTM 可以建模用户兴趣随时间变化的过程。
从通俗角度看:凡是“当前结果依赖过去过程”的任务,都可能适合使用 LSTM。
八、LSTM 的优势、局限与使用注意事项
1、LSTM 的主要优势
LSTM 最大的优势是能够处理序列数据中的长期依赖。
它通过细胞状态和门控机制,让模型可以选择性地保留重要历史信息。
其次,LSTM 比普通 RNN 更稳定。
在长序列中,它通常比普通 RNN 更不容易完全遗忘早期信息。
再次,LSTM 适用范围较广。
文本、语音、时间序列、行为序列等任务都可以使用 LSTM 建模。
从通俗角度看,LSTM 的优势在于:它让模型既能顺序阅读数据,又能把重要信息记得更久。
2、LSTM 的主要局限
LSTM 也有局限。
首先,计算速度较慢。
由于 LSTM 必须按时间步依次处理序列,难以像 Transformer 那样在时间维度上高度并行。
其次,结构较复杂。
LSTM 有多个门和多个权重矩阵,参数量比普通 RNN 多。
再次,非常长的依赖仍然困难。
虽然 LSTM 能缓解长期依赖问题,但面对很长文本或复杂全局关系时,仍可能不如注意力机制灵活。
此外,LSTM 对输入顺序敏感。
如果数据本身没有明显序列结构,使用 LSTM 未必合适。
3、使用 LSTM 时需要注意的问题
使用 LSTM 时,需要注意:
• 输入通常需要整理成 batch × seq_len × feature_dim 或 seq_len × batch × feature_dim
• PyTorch 中 batch_first=True 会让输入形状使用 batch × seq_len × feature_dim
• hidden size 决定隐藏状态维度
• num_layers 可以堆叠多层 LSTM
• 双向 LSTM 可以同时利用前向和后向信息
• 长序列训练可能需要截断反向传播
• 序列长度不一致时通常需要 padding 或 packed sequence
• LSTM 输出通常包括全部时间步输出和最后状态
从实践角度看,LSTM 适合有明显顺序依赖的数据,但并不是所有任务都必须使用 LSTM。对于长文本和大规模语言建模,Transformer 通常更常见。
九、Python 示例
下面给出几个简单示例,用来帮助理解 LSTM 的基本使用。
示例 1:使用 PyTorch 创建 LSTM 层
import torchimport torch.nn as nn # 创建LSTM层:输入特征维度8,隐藏状态维度16,单层,batch_first=True使输入形状为 (batch, seq, feature)lstm = nn.LSTM( input_size=8, hidden_size=16, num_layers=1, batch_first=True) # 生成一批随机输入:4个序列,每个序列5个时间步,每个时间步8维特征x = torch.randn(4, 5, 8) # 前向传播:output 是所有时间步的隐藏状态,h_n 是最后一个时间步的隐藏状态,c_n 是最后一个时间步的细胞状态output, (h_n, c_n) = lstm(x) print("输入形状:", x.shape) # (4,5,8)print("全部时间步输出形状:", output.shape) # (4,5,16)print("最后隐藏状态形状:", h_n.shape) # (1,4,16) (层数, batch, hidden)print("最后细胞状态形状:", c_n.shape) # (1,4,16)输出形状通常为:
输入形状: torch.Size([4, 5, 8])全部时间步输出形状: torch.Size([4, 5, 16])最后隐藏状态形状: torch.Size([1, 4, 16])最后细胞状态形状: torch.Size([1, 4, 16]其中:
• 4 表示 batch size
• 5 表示序列长度
• 8 表示输入特征维度
• 16 表示 hidden size
• h_n 表示最后隐藏状态
• c_n 表示最后细胞状态
示例 2:用 LSTM 做简单文本分类结构
import torchimport torch.nn as nn class LSTMTextClassifier(nn.Module): """基于LSTM的文本分类器""" def __init__(self, vocab_size, embedding_dim, hidden_size, num_classes): super().__init__() # 词嵌入层:将词ID映射为稠密向量,0作为padding索引 self.embedding = nn.Embedding( num_embeddings=vocab_size, embedding_dim=embedding_dim, padding_idx=0 ) # LSTM层:输入嵌入向量,输出隐藏状态,batch_first使输入形状为(batch, seq, feature) self.lstm = nn.LSTM( input_size=embedding_dim, hidden_size=hidden_size, batch_first=True ) # 分类器:将LSTM最后隐藏状态映射到类别logits self.classifier = nn.Linear(hidden_size, num_classes) def forward(self, token_ids): # token_ids形状: (batch, seq_len) x = self.embedding(token_ids) # (batch, seq_len, embedding_dim) output, (h_n, c_n) = self.lstm(x) # output: 所有时间步, h_n: 最后时间步隐藏状态 last_hidden = h_n[-1] # 取最后一层最后一个时间步 (batch, hidden_size) logits = self.classifier(last_hidden) # (batch, num_classes) return logits # 实例化模型:词汇表1000,嵌入维度32,隐藏层64,二分类model = LSTMTextClassifier( vocab_size=1000, embedding_dim=32, hidden_size=64, num_classes=2) # 随机生成一批输入:8个句子,每个句子10个词IDtoken_ids = torch.randint(0, 1000, (8, 10)) logits = model(token_ids) # 前向传播 print("输出 logits 形状:", logits.shape) # (8,2)此示例中:
• Embedding 层把 token id 转为向量
• LSTM 按序列读取 token 向量
• 最后隐藏状态用于分类
• Linear 层输出类别 logits
示例 3:双向 LSTM
import torchimport torch.nn as nn # 双向LSTM层:输入8维,隐藏16维,双向(输出维度翻倍为32)lstm = nn.LSTM( input_size=8, hidden_size=16, num_layers=1, batch_first=True, bidirectional=True # 双向,输出方向为2) # 一批数据:4个序列,每序列5个时间步,每步8维x = torch.randn(4, 5, 8) output, (h_n, c_n) = lstm(x) print("output 形状:", output.shape) # (4,5,32) 因为双向print("h_n 形状:", h_n.shape) # (2,4,16) 双向各一层print("c_n 形状:", c_n.shape) # 同上这里 output 最后一维是 32,是因为双向 LSTM 会把前向和后向隐藏状态拼接:
其中:
• 16 表示 hidden size
• 2 表示两个方向:前向和后向
从通俗角度看:双向 LSTM 既从前往后读序列,也从后往前读序列,因此可以同时利用左右上下文。
示例 4:LSTM 用于时间序列预测
import torchimport torch.nn as nn class TimeSeriesLSTM(nn.Module): """基于LSTM的时间序列回归模型:输入序列预测单个值""" def __init__(self, input_size, hidden_size): super().__init__() # LSTM层:输入特征维度 input_size,隐藏状态维度 hidden_size,batch_first=True 使输入形状为 (batch, seq, feature) self.lstm = nn.LSTM( input_size=input_size, hidden_size=hidden_size, batch_first=True ) # 回归头:将LSTM最后一个时间步的隐藏状态映射到标量预测值 self.regressor = nn.Linear(hidden_size, 1) def forward(self, x): # x形状: (batch, seq_len, input_size) output, (h_n, c_n) = self.lstm(x) # output: (batch, seq_len, hidden_size) # 取每个序列最后一个时间步的输出 last_output = output[:, -1, :] # (batch, hidden_size) # 通过线性层得到预测值 y_pred = self.regressor(last_output) # (batch, 1) return y_pred # 实例化模型:输入3个特征,隐藏状态32维model = TimeSeriesLSTM(input_size=3, hidden_size=32) # 模拟一批数据:8个序列,每个序列20个时间步,每步3个特征x = torch.randn(8, 20, 3) y_pred = model(x) # 前向传播 print("预测输出形状:", y_pred.shape) # (8, 1)此示例中:
• 每条序列有 20 个时间步
• 每个时间步有 3 个输入特征
LSTM 读取整段历史序列,最后时间步表示用于预测一个连续值。
📘 小结
LSTM 是一种用于处理序列数据的循环神经网络结构。它通过细胞状态保存长期记忆,并使用遗忘门、输入门和输出门控制信息保留、写入和输出。相比普通 RNN,LSTM 更适合处理较长依赖关系,但计算更复杂、并行性较弱。对初学者而言,可以把 LSTM 理解为:一种会选择性记笔记的序列模型,它能在逐步读取数据时保留重要历史信息。
“点赞有美意,赞赏是鼓励”
