思路
如图中,左二右三共五个公式,
- 首先实现分别关于o 、f 、i三个门的Wx、 Wh、 b,分别对应输入到该门的权重矩阵、上一时间步隐藏状态到该门的权重矩阵、偏置向量;
- 其次,得到三个参数矩阵后,根据右面三个公式进行三个门的计算;
- 我们将当前时间步的输入片段设为x_t,h_t是上一时间步的隐藏状态;
- 另取一个参数y_t= tanh(Wxc * x_t + h_t * Whc + bc),即左二中下面公式中 i 后面的部分
- 根据遗忘门 f 和输入门 i ,即左二中下面的公式,计算更新状态c_t = f_t * c_t + i_t * y_t
- 根据左二上面的公式更新h_t = o_t * tanh(c_t)
ps:`hidden_seq`
- 是一个存储隐藏状态的序列。它是一个三维张量,形状为`(seq_length, batch_size, hidden_size)`,其中`seq_length`是序列的长度(也就是时间步的数量),`batch_size`是批次的大小,`hidden_size`是隐藏状态的维度大小。
- 在许多序列模型中,如循环神经网络(RNN)和长短期记忆网络(LSTM),隐藏状态是在时间步之间传递的重要信息。`hidden_seq`会存储在训练过程中每个时间步的隐藏状态。
- 在上述代码中,`hidden_seq`的目的是将当前时间步的隐藏状态`h_t`存储并追加到序列中,以便在后续时间步中使用。在代码的其他部分,可能会使用`hidden_seq`来进行序列的处理和相关计算
batch_size
- batch size)是一次处理的样本数量。在训练神经网络时,通常会将数据划分为多个批次,并将每个批次作为模型的输入进行训练。每个批次中包含的样本数量即为批次大小。
- 批次大小的选择是一个重要的超参数,需要根据具体问题和计算资源进行调整。较小的批次大小可能导致更频繁的参数更新,使模型更加敏感,但计算效率较低。较大的批次大小可以提高计算效率,但也可能降低模型的学习速度和泛化能力。
- 在训练过程中,通常会将所有的样本数据分为若干个批次,并依次将每个批次作为输入送入神经网络进行前向传播和反向传播。通过按批次处理数据,可以加速模型的训练过程,提高计算效率,并充分利用硬件设备(如GPU)的并行计算能力。
import torch
import torch.nn as nn
class Lstm(nn.Module):
#用于创建神经网络模型。所有自定义的神经网络模型都应该继承自`nn.Module`。
def __intit(self, input_sz, hidden_sz):
super().__init__()
self.input_size = input_sz
self.hidden_size = hidden_sz
#i
self.Wxi = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.Whi = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.bi = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
#f
self.Wxf = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.Whf = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.bf = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
#o
self.Wxo = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.Who = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.bo = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
#c
self.Wxc = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.Whc = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.bc = nn.Parameter(torch.Tensor(input_sz, hidden_sz))
self.init_weights()#用于初始化神经网络中的权重参数。
def forward(self, x, init_states=None):
batch_size, seq_sz, _ = x.size()
hidden_seq = []
if init_states is None:
h_t, c_t = (
torch.zeros(batch_size, self.hidden_size).to(x.device),#x.device表示输入张量x所在的设备
torch.zeros(batch_size, self.hidden_size).to(x.device)
)
else:
h_t, c_t = init_states
for t in range(seq_sz):
x_t = x[:, t, :]
i_t = torch.sigmoid(x_t @ self.Wxi + h_t @ self.Whi + self.bi)
f_t = torch.sigmoid(x_t @ self.Wxf + h_t @ self.Whf + self.bf)
o_t = torch.sigmoid(x_t @ self.Wxo + h_t @ self.Who + self.bo)
y_t = torch.tanh(x_t @ self.Wxc + h_t @ self.Whc + self.bc)
c_t = f_t * c_t + i_t * y_t
h_t = o_t * torch.tanh(c_t)
hidden_seq.append(h_t.unsqueeze(0))
hidden_seq = torch.cat(hidden_seq, dim = 0)
hidden_seq = hidden_seq.transpose(0, 1).contiguous
return hidden_seq, (h_t, c_t)