LSTM時間序列預測模型


LSTM時間序列預測模型

  1. 長短期記憶(long short-term memory,LSTM)。本節將基於pytorch建立一個LSTM模型,以用於航班乘客數據的預測,這里將直接按照代碼塊進行解釋。

    https://stackabuse.com/time-series-prediction-using-lstm-with-pytorch-in-python/

  2. 數據的預處理

    #時間序列預測模型LSTM
    import torch
    import torch.nn as nn
    import seaborn as sns  #讀取seaborn的數據文件,需要ladder
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    from sklearn.preprocessing import MinMaxScaler
    
    flight_data = sns.load_dataset("flights")
    #print(flight_data.head())
    all_data = flight_data['passengers'].values.astype(float)
    
    #一共144行數據,這里設置每12個數據為一個間隔(1年為12月)
    
    #任務是根據前132個月來預測最近12個月內旅行的乘客人數。請記住,我們有144個月的記錄,這意味着前132個月的數據將用於訓練我們的LSTM模型,而模型性能將使用最近12個月的值進行評估。
    
    #最后待驗證的數據集(月份數目)大小,數值可以修改,記得修改最后plot對應的x范圍即可
    test_data_size = 12   
    train_data = all_data[:-test_data_size] #訓練數據
    test_data = all_data[-test_data_size:]  #測試數據
    
    #歸一化處理減小誤差
    scaler = MinMaxScaler(feature_range=(-1,1))
    train_data_normalized = scaler.fit_transform(train_data.reshape(-1,1))
    train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)
    
    #重點  創建讀取的數據列表。
    #每組數據有2個元組。前一個元組有12個月份的數據,后一個元組只有一個元素,表示第13個月份的數據,用於和基於前12個數據預測的數據求loss
    def create_inout_sequences(input_data, tw):
        inout_seq = []
        L = len(input_data)
        for i in range(L-tw):  #L-tw = 144-32 = 132個數據
            train_seq = input_data[i:i+tw]  #12個數據一組,進行訓練
            train_label = input_data[i+tw:i+tw+1]  #第12+1個數據作為label計算loss
            inout_seq.append((train_seq, train_label))  
        return inout_seq
    
    #這是每次訓練的數據(月份數目),設置為12個月,可以進行調整
    train_window = 12  #tw,設置訓練輸入的序列長度為12
    train_inout_seq = create_inout_sequences(train_data_normalized, train_window)
    

    數據集結果如下

    train_inout_seq[:5]
    [(tensor([-0.9648, -0.9385, -0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066,
              -0.8593, -0.9341, -1.0000, -0.9385]), tensor([-0.9516])),
     
     (tensor([-0.9385, -0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593,
              -0.9341, -1.0000, -0.9385, -0.9516]),tensor([-0.9033])),
     
     (tensor([-0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341,
              -1.0000, -0.9385, -0.9516, -0.9033]), tensor([-0.8374])),
     
     (tensor([-0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341, -1.0000,
              -0.9385, -0.9516, -0.9033, -0.8374]), tensor([-0.8637])),
     
     (tensor([-0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341, -1.0000, -0.9385,
              -0.9516, -0.9033, -0.8374, -0.8637]), tensor([-0.9077]))]
    
    #數據每次移動一個位置,每移動一次,上一個列表的第二個數據成為下一個列表的第一個數據,標簽label也依次向后挪動。
    
    #打印train_inout_seq列表的長度,將看到它包含120個項目。這是因為盡管訓練集包含132個元素,但是序列長度為12,這意味着第一個序列由前12個項目組成,第13個項目是第一個序列的標簽。同樣,第二個序列從第二個項目開始,到第13個項目結束,而第14個項目是第二個序列的標簽,依此類推。
    
    #包含120個項目,因為如果繼續從第120個數據讀取到132個數據,那么需要第133個數據來求loss,已經超出范圍,無法滿足了,所以最多120行。
    
  3. LSTM網絡搭建

    ​ input_size:對應於輸入中的要素數量。盡管我們的序列長度為12,但每個月我們只有1個值,即乘客總數,因此輸入大小為1。

    ​ hidden_layer_size:指定隱藏層的數量以及每層中神經元的數量。

    ​ output_size:輸出中的項目數,由於我們要預測未來1個月的乘客人數,因此輸出大小為1。

    ​ 在構造函數中,我們創建變量hidden_layer_size,lstm,linear和hidden_cell。LSTM算法接受三個輸入:先前的隱藏狀態,先前的單元狀態和當前輸入。該hidden_cell變量包含先前的隱藏狀態和單元狀態。lstm和linear層變量用於創建LSTM和線性層。

    ​ 在forward方法內部,將input_seq作為參數傳遞給lstm圖層。lstm層的輸出是當前時間步的隱藏狀態和單元狀態以及輸出。lstm圖層的輸出將傳遞到該linear圖層。預計的乘客人數存儲在predictions列表的最后一項中,並返回到調用函數。

    class LSTM(nn.Module):
        def __init__(self, input_size=1, hidden_layer_size=100, output_size=1):
            super().__init__()
            self.hidden_layer_size = hidden_layer_size
    
            self.lstm = nn.LSTM(input_size, hidden_layer_size)  #lstm層
    
            self.linear = nn.Linear(hidden_layer_size, output_size)  #全連接層
    
            self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size), #hidden_cell層
                                torch.zeros(1,1,self.hidden_layer_size))
    
        def forward(self, input_seq):
            #lstm處理序列數據,並傳遞到hidden_cell,輸出lstm_out
            #輸入數據格式:input(seq_len, batch, input_size)
            #seq_len:每個序列的長度
            #batch_size:設置為1
            #input_size:輸入矩陣特征數
            lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
            #全連接層輸出predictions
            predictions = self.linear(lstm_out.view(len(input_seq), -1))
            return predictions[-1]
    
  4. 訓練

    model = LSTM()
    loss_function = nn.MSELoss() #損失函數
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  #優化器
    
    epochs = 10
    for i in range(epochs):
        for seq, labels in train_inout_seq:
            optimizer.zero_grad()
            
            #補充作用?
            model.hidden_cell = (torch.zeros(1,1,model.hidden_layer_size),torch.zeros(1,1,model.hidden_layer_size))
            
            y_pred = model(seq)
            single_loss = loss_function(y_pred, labels)
            single_loss.backward()
            optimizer.step()
        if i%25 == 1:
            print(f'epoch:{i:3}loss: {single_loss.item():10.8f}')
    
    print(f'epoch: {i:3} loss: {single_loss.item():10.10f}')
    
  5. 預測(利用前12個點預測新點,然后將預測值作為新的輸入,滾動預測下一個點)

    fut_pred = 12  #預測fut_pred個數據  
    test_inputs = train_data_normalized[-train_window:].tolist()
    #取出最后12個月數據為列表 待預測的數據是第133個起
    model.eval()  #eval模式,不更新梯度
    #預測133~(133+11)個數據  12
    for i in range(fut_pred):
        seq = torch.FloatTensor(test_inputs[-train_window:])  #取出最后12個數據
        with torch.no_grad():
            model.hidden_cell = (torch.zeros(1,1,model.hidden_layer_size),torch.zeros(1,1,model.hidden_layer_size))
            test_inputs.append(model(seq).item())  #每次輸出一個預測值,加到列表
    
    print(test_inputs[train_window:])  #train_window起才是預測的數據(訓練集中最后一組訓練數據)
    
    #逆歸一化回原值范圍,test_inputs中排除前12個數據(訓練數據)
    actual_predictions = scaler.inverse_transform(np.array(test_inputs[train_window:] ).reshape(-1, 1))
    
  6. 繪圖

    x = np.arange(132, 132+fut_pred, 1)
    plt.title('Month vs Passenger')
    plt.ylabel('Total Passengers')
    plt.grid(True)
    plt.autoscale(axis='x', tight=True)
    plt.plot(np.arange(132,144,1), test_data)  #test_data只有12個數據真實值
    plt.plot(x, actual_predictions)
    plt.show()
    
    image-20200612184554673

TIPS

介紹幾個參數

  1. test_data_size : 原始數據集中最后待驗證的數據個數,可修改

  2. train_window : 訓練數據集中,每批次訓練的數據個數,可修改

  3. fut_pred : 待預測的數據個數

  4.  LSTM輸入數據格式:input(seq_len, batch_size, input_size)
     #seq_len/timestep:每個序列的長度
     #batch_size:設置為1
     #input_size:輸入矩陣特征數
    

這里我們可以隨意的修改,比如可以修改成用最后14個數據驗證,每次用15個月份的數據作訓練,預測100個月份的數據等等。當然一般來說,不同的問題下,最佳設置的參數不同,比如本問題中就是按1年12個月來設置是最佳的結果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM