Pytorch 第十二回:循环神经网络——LSTM模型

发布于:2025-04-03 ⋅ 阅读:(15) ⋅ 点赞:(0)

Pytorch 第十二回:循环神经网络——LSTM模型

本次开启深度学习第十二回,基于Pytorch的LSTM循环神经网络模型。本回分享第二个循环神经网络,叫做LSTM模型。在本回中,设计通过LSTM模型来对股票收盘价格进行预测。接下来给大家分享具体思路。
本次学习,借助的平台是PyCharm 2024.1.3,python版本3.11 numpy版本是1.26.4,pytorch版本2.0.0+cu118,d2l的版本是1.0.3


前言

讲述模型前,先讲述两个概念,统一下思路:

1、 RNN模型缺点

传统的RNN模型,存在以下两个缺点:
1)梯度消失与梯度爆炸
随着序列数据长度的加大,传统RNN模型在进行反向传播计算梯度时,需多次连乘权重矩阵,从而导致梯度值指数级衰减(消失)或激增(爆炸)‌。
2)长期依赖建模能力弱
RNN模型的隐藏状态只能存储短期记忆,对长序列(如文档级文本)中依赖联系的捕捉能力差‌。

2、 LSTM模型

LSTM模型在传统RNN模型的基础上,引入‌了记忆元和‌门控机制‌(遗忘门、输入门、输出门),同时采用加法更新、保留序列的信息,从而加强了长序列数据的长期记忆,提高了模型梯度传递的稳定性。

3、记忆元

记忆元(Cell State)是LSTM的核心组成部分,用于存储和传递序列的长期信息。与传统RNN模型仅依赖隐藏状态传递信息不同,LSTM模型将‌短期记忆(隐藏状态)‌和‌长期记忆(记忆元)‌分离,通过门控机制动态调节两者的信息流动,从而避免了模型在处理长序列数据时出现的梯度消失和长期依赖问题。其数据流动图如下所示:
在这里插入图片描述

4、输入门、输出门 与遗忘门

输入门:筛选当前输入中的重要信息加入记忆元。
‌输出门:控制当前记忆元中哪些信息应输出到隐(藏)状态。
遗忘门:决定哪些历史信息需要被丢弃。

闲言少叙,直接展示逻辑,先上引用:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch
from torch import nn
import time

一、数据准备

1、读取数据

首先,从csv文件中读取股票的收盘价格。csv文件可以从本人分享的资源中下载。代码如下:

data_csv = pd.read_csv('./stock_data.csv', usecols=[3])

原始数据图如下所示:
在这里插入图片描述

2、数据预处理

数据预处理过程包括清除数据中的空数据行(列)、对数据内容进行归一化等操作。

data_csv = data_csv.dropna()
dataset = data_csv.values
dataset = dataset.astype('float32')
max_value = np.max(dataset)
min_value = np.min(dataset)
interval = max_value - min_value
dataset = list(map(lambda x: x / interval, dataset))

3、获得数据集和测试集

进行数据预测时,设计用前三天的数据预测今天的数据。因此需要将数据进行一个划分,即三天前的数据集data_X和当天的数据集data_Y 。获得训练集和测试集后,为符合训练需求,需要修改其数据格式(Pytorch小记第十一回中有解释),并将数据转换为tensor类型。

def optimize_dataset(dataset, primitive=3):
    dataX, dataY = [], []
    for i in range(len(dataset) - primitive):
        a = dataset[i:(i + primitive)]
        dataX.append(a)
        dataY.append(dataset[i + primitive])
    return np.array(dataX), np.array(dataY)


# 创建好输入输出
data_X, data_Y = optimize_dataset(dataset)
# 划分训练集和测试集,百分之70作为训练集
train_size = int(len(data_X) * 0.7)
test_size = len(data_X) - train_size
train_X = data_X[:train_size]
train_Y = data_Y[:train_size]
test_X = data_X[train_size:]
test_Y = data_Y[train_size:]

train_X = train_X.reshape(-1, 1, 3)
train_Y = train_Y.reshape(-1, 1, 1)
test_X = test_X.reshape(-1, 1, 3)
train_x = torch.from_numpy(train_X)
train_y = torch.from_numpy(train_Y)
test_x = torch.from_numpy(test_X)

二、模型准备

1.定义LSTM模型

这里定义的LSTM模型由pytorch自带的lstm函数和全连接层组成。与RNN模型对比一下(第十一回内容),这里的参数多了一个num_layers,用来设定隐藏层的层数。当层数增多时,可以分析更加复杂的序列数据,当然模型的训练时间也会增加。

class lstm_net(nn.Module):
    def __init__(self, channels_in, channels_hidden, channels_out=1, num_layers=1):
        super(lstm_net, self).__init__()

        self.lstm = nn.LSTM(channels_in, channels_hidden, num_layers)
        self.flatten = nn.Flatten()
        self.connect = nn.Linear(channels_hidden, channels_out)

    def forward(self, x):
        x, _ = self.lstm(x)
        a, b, c = x.shape
        x = self.flatten(x)
        x = self.connect(x)
        x = x.view(a, b, -1) # 方便后续做差,格式要匹配
        return x

2、定义损失函数和优化函数

定义计算均方误差损失函数;定义Adam优化器,学习率设定为0.01。

loss_f = nn.MSELoss()
optimizer = torch.optim.Adam(forecast_net.parameters(), lr=1e-2)

三、模型训练

1、实例化模型

这里实例化了一个输入单元个数为3,隐藏单元数量为6的LSTM模型,为提高训练时间,这里引入GPU进行训练(如何引入GPU进行训练,可以查看第六回),代码如下所示:

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("device=", device)
forecast_net = lstm_net(3, 6).to(device)

2、进行1000次迭代训练

进行1000次迭代训练,代码如下:

for k in range(1000):
    train_x = train_x.to(device)
    train_y = train_y.to(device)
    out = forecast_net(train_x)
    loss = loss_f(out, train_y).to(device)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    time_consume = time.time() - time1
    if (k + 1) % 100 == 0:  #
        print('Epoch:	{},	Loss:	{:.5f},consume time:{:.3f}s'.format(k + 1, loss, time_consume))

3、输出展示

展示训练过程中的损失值和消耗时间:

Epoch:	100,	Loss:	0.00015,consume time:1.731s
Epoch:	200,	Loss:	0.00011,consume time:3.348s
Epoch:	300,	Loss:	0.00009,consume time:4.968s
Epoch:	400,	Loss:	0.00008,consume time:6.562s
Epoch:	500,	Loss:	0.00008,consume time:8.168s
Epoch:	600,	Loss:	0.00007,consume time:9.758s
Epoch:	700,	Loss:	0.00007,consume time:11.380s
Epoch:	800,	Loss:	0.00006,consume time:12.987s
Epoch:	900,	Loss:	0.00006,consume time:14.586s
Epoch:	1000,	Loss:	0.00005,consume time:16.176s

对比RNN模型的训练时间,和训练精度(可以查看第十一回内容):采用同样的数据进行训练且序列数据长度较短时,LSTM训练的训练效果与RNN不分上下;采用GPU进行训练时,训练时间也是相差不多。(若不采用GPU训练,则可以明显看出RNN模型消耗时间更多)。

4、预测收盘价格

接着使用训练好的模型预测股票的收盘价格,代码如下所示:

forecast_net = forecast_net.eval()  # 转换成测试模式
data_X = data_X.reshape(-1, 1, 3)
data_X = torch.from_numpy(data_X)
pred_data = data_X.to(device)
y_pred = forecast_net(pred_data).to("cpu")
y_pred = y_pred.view(-1).data.numpy()

plt.figure("股票数据预测")
plt.plot(y_pred, 'r', label='forecast data')
plt.plot(dataset, 'g', label='real data')
plt.legend(loc='best')
plt.show()

生成股票收盘预测趋势与实际收盘趋势的对比图,对比图如下所示:
在这里插入图片描述
在训练数据都为较短的序列数据的情况下,对比RNN模型和SLTM模型所生成的趋势图,RNN模型和SLTM模型的能力不相上下,都可以较好的预测出当天股票的收盘价格。

总结

1)数据准备:准备股票收盘趋势的训练集和测试集;
2)模型准备:定义LSTM模型、损失函数和优化器;
3)数据训练:实例化模型并训练,并生成股票收盘趋势与实际收盘趋势的对比图。