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_qoutputs.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
模型:
简洁实现: