LSTM案例airline-passengers全面解析与优化

前言

刚开始学习LSTM的一些理解

torch版本

print(torch.__version__)

1.10.2

原数据下载

https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv
注意:下载好数据后我手动把第一列的月份全都换成1-12的循环了(如下图),这个案例中原文件不能直接用
在这里插入图片描述

代码步步解析

加载包们

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import torch
import torch.nn as nn
from sklearn.preprocessing import MinMaxScaler

原始数据导入与绘制

# csv文件放在程序同一个文件夹下
# pd.read_csv()返回一个Dataframe对象
# 对于Dataframe对象可以使用.shape查看尺寸
training_set = pd.read_csv('airline-passengers.csv')

# iloc通过行号列号来取数据,[:, 1]代表行全取,取第二列
training_set.iloc[:, 1].plot()

# .values将Dataframe转换为ndarray类型,用于后续
# print(training_set.shape)可查看尺寸,为(144, 2)
training_set = training_set.values

在这里插入图片描述

CSV相关知识
Dataframe相关知识
.iloc相关知识
.values相关知识

数据处理

定义滑窗

滑窗用于数据集选取

# 根据几个参数对set进行数据处理
def sliding_windows(set, seq_length, predict_len, batch_size):
    x = []
    y = []

    # step:滑窗的步长,尽量小点,可以直接设为1或2
    # //:商向下取整
    # step = (len(set)-predict_len-seq_length)//batch_size
    step = 1

    # 每一个batch的输入(x)与输出(y)
    for i in range(batch_size):

        # 在这里可以分别确定x和y的维度
        # 列全选,意味着我的输入(x)维度为2,输出维度也是2
        # x和y维度不一定要一致,根据需求来
        _x = set[i*step:(i*step+seq_length), :]
        _y = set[i*step+seq_length+predict_len, :]
        x.append(_x)
        y.append(_y)

    return np.array(x), np.array(y)

seq_length为每单个训练sample取点个数
predict_len为预测多久以后的数据
batch_size为batch的数量

数据归一化与训练数据划分

# MinMaxScaler对training_set进行数据归一化(对每列分别归一)
sc = MinMaxScaler()
training_data = sc.fit_transform(training_set[:, :])

seq_length = 4
predict_len = 1
batch_size = 128
x, y = sliding_windows(training_data, seq_length, predict_len, batch_size)

# 67%用于训练,其余用于测试
train_size = int(len(y) * 0.67)
test_size = len(y) - train_size

# 将数据转化为Tensor对象
dataX = torch.Tensor(np.array(x))
dataY = torch.Tensor(np.array(y))

trainX = torch.Tensor(np.array(x[0:train_size]))
trainY = torch.Tensor(np.array(y[0:train_size]))

testX = torch.Tensor(np.array(x[train_size:len(x)]))
testY = torch.Tensor(np.array(y[train_size:len(y)]))

MinMaxScaler相关知识

print(x.shape)
print(y.shape)
print(trainX.size())
print(trainY.size())

(128, 4, 2)
(128, 2)
torch.Size([85, 4, 2])
torch.Size([85, 2])

训练数据集中
batch_size为85
seq_length为4
input_size为2

搭建LSTM

class LSTM(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes, num_layers, bidirectional=False):
        super(LSTM, self).__init__()

        self.input_size = input_size
        self.hidden_size = hidden_size
        self.num_classes = num_classes
        self.num_layers = num_layers
        self.bidirectional = bidirectional

        self.lstm = nn.LSTM(input_size=self.input_size, hidden_size=self.hidden_size, batch_first=True, 
                            num_layers=self.num_layers, bidirectional=self.bidirectional)

        if self.bidirectional:
            self.fc = nn.Linear(hidden_size*2, num_classes)
        else:
            self.fc = nn.Linear(hidden_size, num_classes)

    def forward(self, x):

        if self.bidirectional:
            h0 = torch.randn(self.num_layers*2, x.size(0), self.hidden_size)
            c0 = torch.randn(self.num_layers*2, x.size(0), self.hidden_size)
        else:
            h0 = torch.randn(self.num_layers, x.size(0), self.hidden_size)
            c0 = torch.randn(self.num_layers, x.size(0), self.hidden_size)

        out, (_, _) = self.lstm(x, (h0, c0))

        # 因为out有seq_length(4)个时态,所以取最后一个时态
        output = torch.squeeze(out[:, -1, :])
        output = self.fc(output)
        return output

大部分结构可以通过LSTM官网进行了解

.squeeze的相关知识

num_classes代表y的维度,本案例中y的维度是2
网络中fc全连接层的作用就是把(squeeze后的)output: (85, 16)的维度匹配成trainY: (85, 2)的维度,这样一来,最终return的output的尺寸就和trainY一致了

训练

# 参数设置
num_epochs = 2000
learning_rate = 0.01

input_size = 2
hidden_size = 16

num_layers = 1
num_classes = 2

lstm = LSTM(input_size, hidden_size, num_classes, num_layers, bidirectional=False)

# 选择损失函数和优化器
criterion = torch.nn.MSELoss()
optimizer = torch.optim.Adam(lstm.parameters(), lr=learning_rate)

# 开始训练
for epoch in range(num_epochs):
    outputs = lstm(trainX)
    # 因为优化器是累加梯度,所以每次要清零
    optimizer.zero_grad()

    # 计算损失
    loss = criterion(outputs, trainY)
    # 反向传播,损失函数计算关于权重的梯度,并将结果储存在权重的.grad中
    loss.backward()
    # 优化器更新lstm权重参数
    optimizer.step()

    if epoch % 100 == 0:
      print("Epoch: %d, loss: %1.5f" % (epoch, loss.item()))

Epoch: 0, loss: 0.11872
Epoch: 100, loss: 0.03787
Epoch: 200, loss: 0.00968
Epoch: 300, loss: 0.00569
Epoch: 400, loss: 0.00100
Epoch: 500, loss: 0.00041
Epoch: 600, loss: 0.00027
Epoch: 700, loss: 0.00025
Epoch: 800, loss: 0.00023
Epoch: 900, loss: 0.00019
Epoch: 1000, loss: 0.00019
Epoch: 1100, loss: 0.00019
Epoch: 1200, loss: 0.00020
Epoch: 1300, loss: 0.00016
Epoch: 1400, loss: 0.00016
Epoch: 1500, loss: 0.00018
Epoch: 1600, loss: 0.00015
Epoch: 1700, loss: 0.00016
Epoch: 1800, loss: 0.00015
Epoch: 1900, loss: 0.00014

测试

# 将模型切换为测试状态,用训练好的权重去预测
lstm.eval()
train_predict = lstm(dataX)

data_predict = train_predict.data.numpy()
dataY_plot = dataY.data.numpy()

# 之前的归一化,恢复到原始范围
data_predict = sc.inverse_transform(data_predict)
dataY_plot = sc.inverse_transform(dataY_plot)

# 取第二列用于画图
dataY_plot_1 = dataY_plot[:, 1:]
data_predict_1 = data_predict[:, 1:]

plt.axvline(x=train_size, c='r', linestyle='--')

plt.plot(dataY_plot_1)
plt.plot(data_predict_1)
plt.suptitle('Time-Series Prediction')
plt.show()

在这里插入图片描述

结语

目前对LSTM函数中的全连接层仍有疑惑
更多的参考资料在我的收藏里

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LSTMLSTM-CNN-Attention是两种常用的序列预测模型。LSTM是一种循环神经网络,适用于处理序列数据,具有记忆单元和门控机制,可以捕捉长期依赖关系。而LSTM-CNN-Attention是将CNN和Attention机制与LSTM结合起来的模型,通过卷积操作提取局部特征,再通过Attention机制对不同位置的特征进行加权,进一步增强模型的表达能力。 为什么LSTM-CNN-Attention在某些情况下比LSTM的预测效果更好呢?这可能有以下几个原因: 1. 局部特征提取:CNN具有强大的特征提取能力,通过卷积操作可以捕捉到输入序列的局部模式。这对于一些需要关注局部信息的任务(如图像识别、语音识别等)来说,往往能提供更好的预测效果。 2. 全局依赖关系:Attention机制可以根据输入序列的不同部分赋予不同的权重,使得模型能够更加关注与预测有关的部分。这有助于提升模型对全局依赖关系的建模能力,在一些需要考虑整体上下文关系的任务中表现更好。 3. 表达能力增强:LSTM-CNN-Attention将CNN和Attention机制与LSTM相结合,综合利用了它们各自的优势,进一步增强了模型的表达能力。通过引入更多的参数和非线性操作,可以更好地拟合输入序列的复杂模式。 需要注意的是,不同任务和数据集的特点会对模型的效果产生影响,因此在具体应用中,需要根据实际情况选择适合的模型。无论是LSTM还是LSTM-CNN-Attention,都有其适用的场景和优势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值