如何构建LSTM神经网络模型

一、了解LSTM

1. 核心思想

首先,LSTM 是 RNN(循环神经网络)的变体。它通过引入细胞状态C(t) 贯穿于整个网络模型,达到长久记忆的效果,进而解决了 RNN 的长期依赖问题。

2. 思维导图

每个LSTM层次都有三个重要的门结构,从前往后依次是遗忘门 (forget gate layer)、输入门 (input gate layer)、输出门(output gate layer)。

还有两个重要的状态,分别是细胞状态 (cell state)、隐藏状态 (hidden state),即图示中的 C(t) 和 h(t) 。其中细胞状态不仅记忆某个时间步的信息,而是对整个时间序列保持较为稳定的记忆,是一种长期 "记忆信息" 。对于隐藏状态来说,它更多地关注当前时间步以及上一个时间步的输出,是一种短期 "记忆信息" 。

具体内容如下面思维导图所示:


二、利用pytorch构建LSTM

1. 构造神经网络模型

1.1 LSTM层
python 复制代码
self.lstm = nn.LSTM(
    input_size=28,  # 每次输入特征数量为28
    hidden_size=64,  # 表示每个时间步的输出会有 64 个特征
    num_layers=1,  # LSTM隐藏层的层数
    batch_first=True  # 输入数据的格式是"批次在第一位"
)
  • input_size: 这告诉模型,每次输入的数据有多少个特征(比如一张28x28像素的图像,每一行就是一个时间步)。也就是图示中的 x(t) 。
  • hidden_size:这是模型的"记忆"大小。即细胞状态C(t) 和隐藏状态 h(t) 的容量。
  • num_layers:等于1则代表只使用一层 LSTM 网络。
  • batch_first:这个参数表示输入数据的维度格式是(批次,时间步、特征数),即批次在第一维。
1.2 全连接层
python 复制代码
self.out = nn.Linear(
    in_features=64,
    out_features=10  # 将LSTM层提取到的64个特征进一步转化为10个输出(0~9)
)
  • in_features:全连接层的输入大小,来自LSTM的输出,每个时间步的特征数是64(即 hidden_size )
  • out_features:全连接层的输出大小是10,通常表示有10个类别。
1.3 Softmax层
python 复制代码
self.softmax = nn.Softmax(dim=1)

这一层主要是将全连接层的输出转化为概率分布。如果使用的是交叉熵代价函数(CrossEntropyLoss),可以不加这层。

2. 前向传播

  1. 在前面LSTM层中batch_first参数设置了输入数据的维度格式,即(批次,时间步、特征数)。所以首先要做的就是调整输入的维度格式。这里每个样本是 28 个时间步,每个时间步有 28 个特征(像是一个28x28的图像)

    python 复制代码
    x = x.view(-1, 28, 28)
  2. 让输入数据通过LSTM层,并最终输出三个信息,分别是 output,h_n 和 c_n。output 包含了每个时间步的输出信息(理解为LSTM分析每个时间步得到的结果)。h_n 是最后一个时间步的隐藏状态,c_n 是记忆状态。我们重点关注 h_n,因为它代表了 LSTM 在处理完所有时间步后的总结。

    python 复制代码
    output, (h_n, c_n) = self.lstm(x)
  3. 接下来从隐藏状态中拿到最后一个时间步 h_n 的输出 output_in_last_timestep。可以理解为,LSTM看完了所有时间步之后,得到了它对整个序列的理解。

    python 复制代码
    output_in_last_timestep = h_n[-1, :, :]

最后LSTM的输出被送到全连接层,转化成10个数字,这些数字代表模型对每个类别的预测分数。并通过Softmax转化为概率。

python 复制代码
x = self.out(output_in_last_timestep)
x = self.softmax(x)

构造好的LSTM神经网络模型代码如下所示:

python 复制代码
class LSTM(nn.Module):
    def __init__(self):
        super(LSTM, self).__init__()
        self.lstm = nn.LSTM(
            input_size=28,  # 每次输入特征数量
            hidden_size=64,  
            num_layers=1,  # LSTM隐藏层的层数
            batch_first=True  
        )
        self.out = nn.Linear(
            in_features=64,
            out_features=10  # 将LSTM层提取到的64个特征进一步转化为10个输出(0~9)
        )
        self.softmax = nn.Softmax(dim=1)

    def forward(self, x):
        x = x.view(-1, 28, 28)  # 将输入调整成一个 (批次大小, 时间步数, 特征数) 的形式
        output, (h_n, c_n) = self.lstm(x)
        output_in_last_timestep = h_n[-1, :, :]  # 从隐藏状态中拿到最后一个时间步的输出
        x = self.out(output_in_last_timestep)  # LSTM的输出被送到全连接层,转化成10个数字
        x = self.softmax(x)  
        return x

三、测试 LSTM 神经网络模型

用MNIST数据集测试代码如下:

python 复制代码
# 训练集
train_dataset = datasets.MNIST(root='./',
                               train=True,
                               transform=transforms.ToTensor(),  # 数据转换为张量格式
                               download=True)
# 测试集
test_dataset = datasets.MNIST(root='./',
                              train=False,
                              transform=transforms.ToTensor(),
                              download=True)

# 批次大小
batch_size = 100
# 装载训练集
train_loader = DataLoader(dataset=train_dataset,
                          batch_size=batch_size,  # 每次加载多少条数据
                          shuffle=True)  # 生成数据前打乱数据

# 装载测试集
test_loader = DataLoader(dataset=test_dataset,
                         batch_size=batch_size,
                         shuffle=True)

LR = 0.001  # 学习率
model = LSTM()  # 模型
crossEntropy_loss = nn.CrossEntropyLoss()  # 交叉熵代价函数
optimizer = optim.Adam(model.parameters(), LR)


def train():
    model.train()
    for i, data in enumerate(train_loader):
        inputs, labels = data  # 获得一个批次的数据和标签
        out = model(inputs)  # 获得模型预测输出(64张图像,10个数字的概率)
        loss = crossEntropy_loss(out, labels)  # 使用交叉熵损失函数时,可以直接使用整型标签,无须独热编码
        optimizer.zero_grad()  # 梯度清0
        loss.backward()  # 计算梯度
        optimizer.step()  # 修改权值


def test():
    model.eval()
    correct = 0
    for i, data in enumerate(test_loader):
        inputs, labels = data  # 获得一个批次的数据和标签
        out = model(inputs)  # 获得模型预测结构(64,10)
        _, predicted = torch.max(out, 1)  # 获得最大值,以及最大值所在位置
        correct += (predicted == labels).sum()  # 判断64个值有多少是正确的
    print("测试集正确率:{}\n".format(correct.item() / len(test_loader)))


# 训练20个周期
for epoch in range(20):
    print("Epoch:{}".format(epoch))
    train()
    test()

测试结果:

相关推荐
聚客AI6 分钟前
PyTorch玩转CNN:卷积操作可视化+五大经典网络复现+分类项目
人工智能·pytorch·神经网络
程序员岳焱9 分钟前
深度剖析:Spring AI 与 LangChain4j,谁才是 Java 程序员的 AI 开发利器?
java·人工智能·后端
Q同学10 分钟前
TORL:工具集成强化学习,让大语言模型学会用代码解题
深度学习·神经网络·llm
柠檬味拥抱11 分钟前
AI智能体在金融决策系统中的自主学习与行为建模方法探讨
人工智能
禺垣11 分钟前
图神经网络(GNN)模型的基本原理
深度学习
智驱力人工智能21 分钟前
智慧零售管理中的客流统计与属性分析
人工智能·算法·边缘计算·零售·智慧零售·聚众识别·人员计数
workflower39 分钟前
以光量子为例,详解量子获取方式
数据仓库·人工智能·软件工程·需求分析·量子计算·软件需求
壹氿43 分钟前
Supersonic 新一代AI数据分析平台
人工智能·数据挖掘·数据分析
柠石榴1 小时前
【论文阅读笔记】《A survey on deep learning approaches for text-to-SQL》
论文阅读·笔记·深度学习·nlp·text-to-sql
张较瘦_1 小时前
[论文阅读] 人工智能 | 搜索增强LLMs的用户偏好与性能分析
论文阅读·人工智能