57长短期记忆网络(LSTM
)
1.LSTM
原理
LSTM
是专为解决标准RNN
的长时依赖问题而设计的。标准RNN
在训练过程中,随着时间步的增加,梯度可能会消失或爆炸,导致模型难以学习和记忆长时间间隔的信息。LSTM
通过引入一组称为门的机制来解决这个问题:
- 输入门(Input Gate):控制有多少新的信息可以传递到记忆单元中。
- 遗忘门(Forget Gate):控制当前记忆单元中有多少信息会被保留。
- 输出门(Output Gate):控制记忆单元的输出有多少被传递到下一步。
LSTM
还引入了一个称为记忆单元(Cell State)的概念,用于携带长期信息。这些门的组合使得LSTM
能够选择性地记住或遗忘信息,从而解决了长时依赖问题。
2.优点
- 解决梯度消失问题:通过门控机制,
LSTM
能够有效地传递梯度,避免了梯度消失和爆炸的问题。 - 捕捉长时依赖:
LSTM
能够记住和利用长时间间隔的信息,这是标准RNN
难以做到的。 - 灵活性:
LSTM
适用于各种序列数据处理任务,如时间序列预测、语言建模和序列到序列的翻译等。
3.LSTM
与GRU
的区别
GRU
(门控循环单元)是另一种解决长时依赖问题的RNN
变体。GRU
和LSTM
都引入了门控机制,但它们的具体实现有所不同。
- 结构简化:
GRU
的结构比LSTM
更简单,参数更少,计算效率更高。 - 性能对比:在一些任务上,
GRU
和LSTM
的性能相当,但在某些情况下,GRU
可能表现更好,特别是在较小的数据集或较短的序列上。 - 门的数量:
LSTM
有三个门(输入门、遗忘门和输出门),而GRU
只有两个门(更新门和重置门)。
4.LSTM
代码实践
import torch
from torch import nn
from d2l import torch as d2l
import matplotlib.pyplot as plt
# 设置批量大小和序列步数
batch_size, num_steps = 32, 35
# 加载时间机器数据集
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
# 初始化LSTM模型参数
def get_lstm_params(vocab_size, num_hiddens, device):
# 输入输出的维度大小
num_inputs = num_outputs = vocab_size
# 正态分布初始化权重
def normal(shape):
return torch.randn(size=shape, device=device) * 0.01
# 三个权重参数(用于输入门、遗忘门、输出门和候选记忆元)
def three():
return (normal((num_inputs, num_hiddens)), # 输入到隐藏状态的权重
normal((num_hiddens, num_hiddens)), # 隐藏状态到隐藏状态的权重
torch.zeros(num_hiddens, device=device)) # 偏置
W_xi, W_hi, b_i = three() # 输入门参数
W_xf, W_hf, b_f = three() # 遗忘门参数
W_xo, W_ho, b_o = three() # 输出门参数
W_xc, W_hc, b_c = three() # 候选记忆元参数
# 输出层参数
W_hq = normal((num_hiddens, num_outputs)) # 隐藏状态到输出的权重
b_q = torch.zeros(num_outputs, device=device) # 输出偏置
# 将所有参数附加到参数列表中
params = [W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc,
b_c, W_hq, b_q]
for param in params:
param.requires_grad_(True) # 设置参数需要梯度
return params
# 初始化LSTM的隐藏状态
def init_lstm_state(batch_size, num_hiddens, device):
return (torch.zeros((batch_size, num_hiddens), device=device), # 隐藏状态
torch.zeros((batch_size, num_hiddens), device=device)) # 记忆元
# LSTM前向传播
def lstm(inputs, state, params):
[W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c,
W_hq, b_q] = params
(H, C) = state # 隐藏状态和记忆元
outputs = []
for X in inputs:
# 输入门
I = torch.sigmoid((X @ W_xi) + (H @ W_hi) + b_i)
# 遗忘门
F = torch.sigmoid((X @ W_xf) + (H @ W_hf) + b_f)
# 输出门
O = torch.sigmoid((X @ W_xo) + (H @ W_ho) + b_o)
# 候选记忆元
C_tilda = torch.tanh((X @ W_xc) + (H @ W_hc) + b_c)
# 更新记忆元
C = F * C + I * C_tilda
# 更新隐藏状态
H = O * torch.tanh(C)
# 计算输出
Y = (H @ W_hq) + b_q
outputs.append(Y)
return torch.cat(outputs, dim=0), (H, C) # 返回输出和状态
# 训练和预测模型
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
# 创建自定义的LSTM模型
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_lstm_params,
init_lstm_state, lstm)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
plt.show()
# perplexity 1.3, 34433.0 tokens/sec on cuda:0
# 预测结果示例:time traveller conellace there wardeal that are almost us we hou
# 使用PyTorch的简洁实现
num_inputs = vocab_size
lstm_layer = nn.LSTM(num_inputs, num_hiddens) # 创建LSTM层
model = d2l.RNNModel(lstm_layer, len(vocab)) # 创建模型
model = model.to(device) # 将模型移动到GPU
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
plt.show()
# perplexity 1.0, 317323.7 tokens/sec on cuda:0
# 预测结果示例:time travelleryou can show black is white by argument said filby
自定义的LSTM
模型:
简洁实现: