9.2 长短期记忆网络(LSTM)

Long short-term memory
长期以来,隐变量模型存在着长期信息保存和短期输入缺失的问题。 解决这一问题的最早方法之一是长短期存储器(long short-term memory,LSTM)

长短期记忆网络的设计比门控循环单元稍微复杂一些, 却比门控循环单元早诞生了近20年。

9.2.1 门控记忆单元

记忆元(单元):记录附加的信息
输出门:从单元中输出条目
输入门:决定何时将数据读入单元
遗忘门:一种机制来重置单元的内容

9.2.1.1 输入门 忘记门 和输出门

就如在门控循环单元中一样,当前时间步的输入和前一个时间步的隐状态 作为数据送入长短期记忆网络的门中

它们由三个具有sigmoid激活函数的全连接层处理, 以计算输入门、遗忘门和输出门的值。 因此,这三个门的值都在(0,1)的范围内。

在这里插入图片描述

9.2.1.2. 候选记忆元

Q:候选记忆有什么作用,它和输入门有什么区别?
它的计算与上面描述的三个门的计算类似, 但是使用
tanh函数作为激活函数,函数的值范围为(-1,1)。 下面导出在时间步。处的方程:
在这里插入图片描述在这里插入图片描述

9.2.1.3. 记忆元

在这里插入图片描述
在这里插入图片描述

9.2.1.4. 隐状态

在这里插入图片描述
只要输出门接近1,我们就能够有效地将所有记忆信息传递给预测部分, 而对于输出门接近0,我们只保留记忆元内的所有信息,而不需要更新隐状态。

在这里插入图片描述

9.2.2. 从零开始实现

import torch
from torch import nn
from d2l import torch as d2l

batch_size,num_steps = 32,35#批量大小为32,时间步数为35
train_iter,vocab = d2l.load_data_time_machine(batch_size,num_steps)#加载数据集和词汇表,并将其分别赋值给 train_iter 和 vocab

9.2.2.1. 初始化模型参数

def get_lstm_params(vocab_size,num_hiddens,device):
	num_imputs = num_outputs = vocab_size
	# 定义一个辅助函数 normal,用于生成形状为 shape 的正态分布随机数张量
	def normal(shape):
		return torch.randn(size=shape,device=device)*0.01
	# 定义一个辅助函数 three,用于生成三个参数张量的元组
	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]
    # 将所有参数张量的梯度属性设置为 True,表示需要计算梯度
    for param in params:
    	param.requires_grad_(True)
    # 返回所有参数张量的列表
    return params

9.2.2.2. 定义模型

在初始化函数中, 长短期记忆网络的隐状态需要返回一个额外的记忆元, 单元的值为0,形状为(批量大小,隐藏单元数)。 因此,我们得到以下的状态初始化。

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))

实际模型的定义与我们前面讨论的一样: 提供三个门和一个额外的记忆元。 请注意,只有隐状态才会传递到输出层, 而记忆元Ct不直接参与输出计算。

前向传播:
前向传播是深度学习中的一种计算过程,用于从输入数据到输出结果的计算过程。在前向传播过程中,我们将输入数据通过神经网络模型的各个层进行计算和传递,最终得到输出结果。

具体来说,对于神经网络模型的每一层,输入数据经过线性变换(如矩阵乘法)和激活函数(如ReLU、sigmoid等)的作用,得到新的特征表示,然后将这些特征传递给下一层。这个过程从输入层开始,逐层进行,直到达到输出层,最后得到模型的预测结果。

前向传播过程可以看作是将输入数据在网络中“前向”流动的过程,每一层都根据输入数据进行计算和转换,最终得到输出结果。通过前向传播,我们可以获得模型对输入数据的预测结果,并在训练过程中计算损失函数,从而进行参数更新和优化。

#定义一个函数 lstm,用于执行 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)
    # 将所有时间步的输出在维度0上进行拼接,并返回拼接后的结果以及更新后的隐藏状态和细胞状态
    return torch.cat(outputs, dim=0), (H, C)

9.2.2.3. 训练和预测

让我们通过实例化 8.5节中 引入的RNNModelScratch类来训练一个长短期记忆网络, 就如我们在 9.1节中所做的一样。

vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
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)

9.2.3 简洁实现

num_inputs=vocab_size
lstm_layer=nn.LSTM(num_inputs,num_hiddens)
model = d2l.RNNModel(lstm_layer,len(vocab))
model = model.to(device)
d2l.train_ch8(model,train_iter,vocab,lr,num_epochs,device)

长短期记忆网络是典型的具有重要状态控制的隐变量自回归模型。 多年来已经提出了其许多变体,例如,多层、残差连接、不同类型的正则化。 然而,由于序列的长距离依赖性,训练长短期记忆网络 和其他序列模型(例如门控循环单元)的成本是相当高的。 在后面的内容中,我们将讲述更高级的替代模型,如Transformer。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值