LSTM时间序列预测

关于时间序列预测

你可能经常会遇到这样的问题,给你一个数据集,要你预测下一个时刻的值是多少?如下图所示,这种数据往往并没有规律可言,也不可能用一个简单的n阶模型去拟合。老实说,以前我遇到这种问题都是直接上灰色模型,但是用的多了就感觉会有点问题。其它还有一些模型比方说ARAM、ARIRM我没有试过。这篇文章主要讲解用LSTM如何进行时间序列预测

数据

数据直接放在代码里,省去了下载文件并读取的麻烦。这组数据是首都国际机场1949-01~1960-12这12年来的客流量,一共12*12=144个月。我们选取前9年的数据(75%)作为Train Data,后3年的数据(25%)作为Test Data。本来还需要Val Data的,但由于数据量比较少,而且不用搞得那么麻烦,所以就不做Validation了。由于我观察到的客流量变化周期是一年的,因为我为客流数据加上了年、月这两个维度的标记

def load_data():
    # passengers number of international airline, 1949-01~1960-12 per month
    seq_number = np.array(
        [112., 118., 132., 129., 121., 135., 148., 148., 136., 119., 104.,
         118., 115., 126., 141., 135., 125., 149., 170., 170., 158., 133.,
         114., 140., 145., 150., 178., 163., 172., 178., 199., 199., 184.,
         162., 146., 166., 171., 180., 193., 181., 183., 218., 230., 242.,
         209., 191., 172., 194., 196., 196., 236., 235., 229., 243., 264.,
         272., 237., 211., 180., 201., 204., 188., 235., 227., 234., 264.,
         302., 293., 259., 229., 203., 229., 242., 233., 267., 269., 270.,
         315., 364., 347., 312., 274., 237., 278., 284., 277., 317., 313.,
         318., 374., 413., 405., 355., 306., 271., 306., 315., 301., 356.,
         348., 355., 422., 465., 467., 404., 347., 305., 336., 340., 318.,
         362., 348., 363., 435., 491., 505., 404., 359., 310., 337., 360.,
         342., 406., 396., 420., 472., 548., 559., 463., 407., 362., 405.,
         417., 391., 419., 461., 472., 535., 622., 606., 508., 461., 390.,
         432.], dtype=np.float32)
    # plt.plot(seq_number)
    # plt.ion()
    seq_number = seq_number[:, np.newaxis] # add a new dimension

    # 12 years
    seq_year = np.arange(12)
    # 12 month
    seq_month = np.arange(12)
    seq_year_month = np.transpose(
        [np.repeat(seq_year, len(seq_month)),
         np.tile(seq_month, len(seq_year))],
    )
    seq = np.concatenate((seq_number, seq_year_month), axis=1)

    # normalization
    seq = (seq - seq.mean(axis=0)) / seq.std(axis=0)
    return seq

总的数据维度是(144, 3),即144个月的[客流量,年份,月份]这3个维度的数据。并且我对数据进行了归一化处理

模型

我们希望输入前9年的数据,让LSTM预测后3年的客流,那么我们可以先用前9年中每个月的数据训练LSTM,让它根据前几个月预测下一个月的客流。等训练完成后,我们让LSTM根据前9年的数据预测出下一个月的客流,把刚刚输出的预测客流作为输入,迭代求得后3年的客流

请注意,通常情况下Tensor的第一个维度是批次大小batch size,但是PyTorch建议我们输入循环神经网络的时候,Tensor的第一个维度是序列长度seq len,第二个维度才是batch size

对于这个客流数据,seq_len指的是时间序列的长度,这里前9年,共108个月,则seq_len=108input_dim指的是输入的维度,这里输入数据由三个维度构成,则input_dim=3

接下来我们就可以确定LSTM的结构了

lstm = nn.LSTM(input_dim, mid_dim, mid_layers)
# input_dim 指的是LSTM输入Tensor的维度,根据我们的数据已经确定了这个值是3
# mid_dim 指的是LSTM三个门(gaee)的网络宽度,也是LSTM输出Tensor的维度
# mid_layers 指的是LSTM内部各个gate使用的全连接层的数量,一般设为1或2

x = torch.randn(seq_len, batch_size, input_dim)
output = lstm(x)
assert output.size() == (seq_len, batch_size, mid_dim)

mid_layers一般设置为1或者2:理论上足够宽(神经元个数足够多),并且至少存在一层具有任何一种"挤压"性质的激活函数的2层全连接层就能拟合任何的连续函数

为了进行时间序列预测,我们在LSTM后面街上两层全连接层(1层也行),用于改变最终LSTM输出Tensor的维度。我们只需要预测客流量这一个值,因此out_dim=1

fc = nn.Sequential(
    nn.Linear(mid_dim, mid_dim)
    nn.ReLU(),
    nn.Linear(mid_dim, out_dim),
)

x = output_of_LSTM
seq_len, batch_size, mid_dim = x.shape
x = x.view(-1, mid_dim)
output_of_fc = fc(x)
output_of_fc = output_of_fc.view(seq_len, batch_size, out_dim)

训练

同一批次中序列长度不同,需要使用from torch.nn.utils.rnn import pad_sequence

我们只有一组训练数据,即前9年的客流量。我们可以在同一批次中,训练LSTM预测不同月份的客流量。1~t月的输入对应了t+1月的客流量。由于同一批次里面训练序列长度不统一,直接在末尾补0的操作不优雅,所以我们需要借助torch 自带的工具 pad_sequence的协助,具体如下

var_x = torch.tensor(train_x, dtype=torch.float32, device=device)
var_y = torch.tensor(train_y, dtype=torch.float32, device=device)

batch_var_x = list()
batch_var_y = list()

for i in range(batch_size):
    j = train_size - i
    batch_var_x.append(var_x[j:])
    batch_var_y.append(var_y[j:])

from torch.nn.utils.rnn import pad_sequence
batch_var_x = pad_sequence(batch_var_x)
batch_var_y = pad_sequence(batch_var_y)

放入pad_sequence的序列必须从长到短放置,随着反向传播的进行,PyTorch会逐步忽略完成梯度计算的短序列,具体解释请看PyTorch官网

criterion = nn.MSELoss()  # L2_loss

for e in range(epochs):
    out = net(batch_var_x)

    loss = criterion(out, batch_var_y)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

评估

就像前面所说的:使用前9年的数据作为输入,预测得到下一个与的客流,并将此预测结果加到输入序列中,从而逐步预测后3年的客流。就像修路一样,走在刚刚铺好的路面往前推进

最终完整代码

import numpy as np
import torch
from torch import nn
import matplotlib.pyplot as plt

def run_train_lstm():
    inp_dim = 3
    out_dim = 1
    mid_dim = 8
    mid_layers = 1
    batch_size = 12 * 4
    mod_dir = '.'

    '''load data'''
    data = load_data()
    data_x = data[:-1, :] # 0~142
    data_y = data[1:, 0] # 1~143
    assert data_x.shape[1] == inp_dim

    train_size = int(len(data_x) * 0.75)

    train_x = data_x[:train_size]
    train_y = data_y[:train_size]
    train_x = train_x.reshape((train_size, inp_dim))
    train_y = train_y.reshape((train_size, out_dim))

    '''build model'''
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    net = RegLSTM(inp_dim, out_dim, mid_dim, mid_layers).to(device)
    criterion = nn.MSELoss()
    optimizer = torch.optim.Adam(net.parameters(), lr=1e-2)

    '''train'''
    var_x = torch.tensor(train_x, dtype=torch.float32).to(device)
    var_y = torch.tensor(train_y, dtype=torch.float32).to(device)

    batch_var_x = list()
    batch_var_y = list()

    for i in range(batch_size):
        j = train_size - i
        batch_var_x.append(var_x[j:])
        batch_var_y.append(var_y[j:])

    from torch.nn.utils.rnn import pad_sequence
    batch_var_x = pad_sequence(batch_var_x)
    batch_var_y = pad_sequence(batch_var_y)

    print("Training Start")
    for e in range(500):
        out = net(batch_var_x)

        loss = criterion(out, batch_var_y)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if e % 64 == 0:
            print('Epoch: {:4}, Loss: {:.5f}'.format(e, loss.item()))
    torch.save(net.state_dict(), '{}/net.pth'.format(mod_dir))
    print("Save in:", '{}/net.pth'.format(mod_dir))

    '''eval'''
    net.load_state_dict(torch.load('{}/net.pth'.format(mod_dir), map_location=lambda storage, loc: storage))
    net = net.eval()

    test_x = data_x.copy()
    test_x[train_size:, 0] = 0
    test_x = test_x[:, np.newaxis, :]
    test_x = torch.tensor(test_x, dtype=torch.float32, device=device)

    eval_size = 1
    zero_ten = torch.zeros((mid_layers, eval_size, mid_dim), dtype=torch.float32, device=device)
    test_y, hc = net.output_y_hc(test_x[:train_size], (zero_ten, zero_ten))
    test_x[train_size + 1, 0, 0] = test_y[-1]
    for i in range(train_size + 1, len(data) - 2):
        test_y, hc = net.output_y_hc(test_x[i:i + 1], hc)
        test_x[i + 1, 0, 0] = test_y[-1]
    pred_y = test_x[1:, 0, 0]
    pred_y = pred_y.cpu().data.numpy()

    diff_y = pred_y[train_size:] - data_y[train_size:-1]
    l1_loss = np.mean(np.abs(diff_y))
    l2_loss = np.mean(diff_y ** 2)
    print("L1: {:.3f}    L2: {:.3f}".format(l1_loss, l2_loss))

    plt.plot(pred_y, 'r', label='pred')
    plt.plot(data_y, 'b', label='real', alpha=0.3)
    plt.plot([train_size, train_size], [-1, 2], color='k', label='train | pred')
    plt.legend(loc='best')
    plt.savefig('lstm_reg.png')

class RegLSTM(nn.Module):
    def __init__(self, inp_dim, out_dim, mid_dim, mid_layers):
        super(RegLSTM, self).__init__()

        self.lstm = nn.LSTM(inp_dim, mid_dim, mid_layers)  # lstm
        self.fc = nn.Sequential(
            nn.Linear(mid_dim, mid_dim),
            nn.ReLU(),
            nn.Linear(mid_dim, out_dim),
        )

    def forward(self, x):
        y = self.lstm(x)[0]  # y, (h, c) = self.lstm(x)

        seq_len, batch_size, hid_dim = y.shape
        y = y.view(-1, hid_dim)
        y = self.fc(y)
        y = y.view(seq_len, batch_size, -1)
        return y

    """
    Examples::
        >>> rnn = nn.LSTM(10, 20, 2)
        >>> input = torch.randn(5, 3, 10)
        >>> h0 = torch.randn(2, 3, 20)
        >>> c0 = torch.randn(2, 3, 20)
        >>> output, (hn, cn) = rnn(input, (h0, c0))
    """

    def output_y_hc(self, x, hc):
        y, hc = self.lstm(x, hc)  # y, (h, c) = self.lstm(x)

        seq_len, batch_size, hid_dim = y.shape
        y = y.view(-1, hid_dim)
        y = self.fc(y)
        y = y.view(seq_len, batch_size, -1)
        return y, hc

def load_data():
    # passengers number of international airline, 1949-01~1960-12 per month
    seq_number = np.array(
        [112., 118., 132., 129., 121., 135., 148., 148., 136., 119., 104.,
         118., 115., 126., 141., 135., 125., 149., 170., 170., 158., 133.,
         114., 140., 145., 150., 178., 163., 172., 178., 199., 199., 184.,
         162., 146., 166., 171., 180., 193., 181., 183., 218., 230., 242.,
         209., 191., 172., 194., 196., 196., 236., 235., 229., 243., 264.,
         272., 237., 211., 180., 201., 204., 188., 235., 227., 234., 264.,
         302., 293., 259., 229., 203., 229., 242., 233., 267., 269., 270.,
         315., 364., 347., 312., 274., 237., 278., 284., 277., 317., 313.,
         318., 374., 413., 405., 355., 306., 271., 306., 315., 301., 356.,
         348., 355., 422., 465., 467., 404., 347., 305., 336., 340., 318.,
         362., 348., 363., 435., 491., 505., 404., 359., 310., 337., 360.,
         342., 406., 396., 420., 472., 548., 559., 463., 407., 362., 405.,
         417., 391., 419., 461., 472., 535., 622., 606., 508., 461., 390.,
         432.], dtype=np.float32)
    # plt.plot(seq_number)
    # plt.ion()
    seq_number = seq_number[:, np.newaxis] # add a new dimension

    # 12 years
    seq_year = np.arange(12)
    # 12 month
    seq_month = np.arange(12)
    seq_year_month = np.transpose(
        [np.repeat(seq_year, len(seq_month)),
         np.tile(seq_month, len(seq_year))],
    )
    seq = np.concatenate((seq_number, seq_year_month), axis=1)

    # normalization
    seq = (seq - seq.mean(axis=0)) / seq.std(axis=0)
    return seq

if __name__ == '__main__':
    torch.manual_seed(1)
    run_train_lstm()

原文地址:https://www.cnblogs.com/mathor/p/12416567.html

时间: 2024-08-03 14:29:04

LSTM时间序列预测的相关文章

基于 Keras 用 LSTM 网络做时间序列预测

基于 Keras 用 LSTM 网络做时间序列预测 本文主要参考了 Jason Brownlee 的博文 Time Series Prediction with LSTM Recurrent Neural Networks in Python with Keras 原文使用 python 实现模型,这里是用 R 时间序列预测是一类比较困难的预测问题. 与常见的回归预测模型不同,输入变量之间的"序列依赖性"为时间序列问题增加了复杂度. 一种能够专门用来处理序列依赖性的神经网络被称为 递归

时间序列深度学习:状态 LSTM 模型预测太阳黑子

时间序列深度学习:状态 LSTM 模型预测太阳黑子 本文翻译自<Time Series Deep Learning: Forecasting Sunspots With Keras Stateful Lstm In R> 原文链接 由于数据科学机器学习和深度学习的发展,时间序列预测在预测准确性方面取得了显着进展.随着这些 ML/DL 工具的发展,企业和金融机构现在可以通过应用这些新技术来解决旧问题,从而更好地进行预测.在本文中,我们展示了使用称为 LSTM(长短期记忆)的特殊类型深度学习模型,

Python中利用LSTM模型进行时间序列预测分析 - 预测爱尔兰的电力消耗

此示例中,神经网络用于使用2011年4月至2013年2月期间的数据预测都柏林市议会公民办公室的能源消耗. 每日数据是通过总计每天提供的15分钟间隔的消耗量来创建的. LSTM简介 LSTM(或长期短期存储器网络)允许分析具有长期依赖性的顺序或有序数据.当涉及到这项任务时,传统的神经网络不足,在这方面,LSTM将用于预测这种情况下的电力消耗模式. 与ARIMA等模型相比,LSTM的一个特殊优势是数据不一定需要是固定的(常数均值,方差和自相关),以便LSTM对其进行分析 - 即使这样做可能会导致性能

在Python中使用LSTM和PyTorch进行时间序列预测

原文链接:http://tecdat.cn/?p=8145 顾名思义,时间序列数据是一种随时间变化的数据类型.例如,24小时内的温度,一个月内各种产品的价格,一年中特定公司的股票价格.诸如长期短期记忆网络(LSTM)之类的高级深度学习模型能够捕获时间序列数据中的模式,因此可用于对数据的未来趋势进行预测.在本文中,您将看到如何使用LSTM算法使用时间序列数据进行将来的预测. 数据集和问题定义 让我们先导入所需的库,然后再导入数据集: import torch import torch.nn as

facebook开源的prophet时间序列预测工具---识别多种周期性、趋势性、节假日效应,以及部分异常值

from:https://www.zhihu.com/question/56585493/answer/234300942 在今年三月prophet刚发布的时候就简单用过,但最近才想起去读paper-- 首先,prophet是一个工业级应用,而不是说在时间序列预测的模型上有非常大的创新. 记得今年在参加一次猫眼电影票房预测的内部分享时,旁边坐了一个外卖的PM.结束时对方问我,有什么方法可以预测外卖的订单量.我当时想了想,诸如Holt-Winters指数平滑.ARIMA.或者deep learni

转 时间序列预测示例

介绍 时间序列(简称TS)被认为是分析领域比较少人知道的技能.(我也是几天前才知道它).但是你一定知道最近的小型编程马拉松就是基于时间序列发展起来的,我参加了这项活动去学习了解决时间序列问题的基本步骤,在这儿我要分享给大家.这绝对能帮助你在编程马拉松中获得一个合适的模型. 文章之前,我极力推荐大家阅读<基于R语言的时间序列建模完整教程>A Complete Tutorial on Time Series Modeling in R,它就像这篇文章的前篇.它关注基本概念和基于R语言,我将重点使用

腾讯技术工程 | 基于Prophet的时间序列预测

预测未来永远是一件让人兴奋而又神奇的事.为此,人们研究了许多时间序列预测模型.然而,大部分的时间序列模型都因为预测的问题过于复杂而效果不理想.这是因为时间序列预测不光需要大量的统计知识,更重要的是它需要将问题的背景知识融入其中.为此,Prophet充分的将两者融合了起来,提供了一种更简单.灵活的预测方式,并且在预测准确率上达到了与专业分析师相媲美的程度.如果你还在为时间序列预测而苦恼,那就一起走进兴奋而又神奇的Prophet世界吧. 前言 时间序列预测一直是预测问题中的难点,人们很难找到一个适用

前馈全连接神经网络和函数逼近、时间序列预测、手写数字识别

https://www.cnblogs.com/conmajia/p/annt-feed-forward-fully-connected-neural-networks.html Andrew Kirillov 著Conmajia 译2019 年 1 月 12 日 原文发表于 CodeProject(2018 年 9 月 28 日). 中文版有小幅修改,已获作者本人授权. 本文介绍了如何使用 ANNT 神经网络库生成前馈全连接神经网络并应用到问题求解. 全文约 12,000 字,建议阅读时间 3

用Python进行时间序列预测的7种方法

数据准备 数据集(JetRail高铁的乘客数量)下载. 假设要解决一个时序问题:根据过往两年的数据(2012 年 8 月至 2014 年 8月),需要用这些数据预测接下来 7 个月的乘客数量. import pandas as pd import numpy as np import matplotlib.pyplot as plt df = pd.read_csv('train.csv') df.head() df.shape 依照上面的代码,我们获得了 2012-2014 年两年每个小时的乘