1. 程式人生 > >pytorch RNN用於時間序列的分析

pytorch RNN用於時間序列的分析

本文參考書籍《深度學習入門之pytorch》

首先看一下我們的資料集:

可以看出資料有遞增的趨勢,但是有很大的波動性。這裡我們嘗試用rnn來解決。

貼一下程式碼:

# -*- coding: utf-8 -*-
"""
Created on Tue Oct  9 11:28:39 2018

@author: www
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt


data_csv = pd.read_csv(r'E:\data\data.csv', usecols=[1])

plt.plot(data_csv)

#首先我們進行預處理,將資料中 na 的資料去掉,然後將資料標準化到 0 ~ 1 之間。
data_csv = data_csv.dropna()
dataset = data_csv.values
dataset = dataset.astype('float32')
max_value = np.max(dataset)
min_value = np.min(dataset)
scalar = max_value - min_value
dataset = list(map(lambda x: x / scalar, dataset))

'''
接著我們進行資料集的建立,我們想通過前面幾個月的流量來預測當月的流量,
比如我們希望通過前兩個月的流量來預測當月的流量,我們可以將前兩個月的流量
當做輸入,當月的流量當做輸出。同時我們需要將我們的資料集分為訓練集和測試
集,通過測試集的效果來測試模型的效能,這裡我們簡單的將前面幾年的資料作為
訓練集,後面兩年的資料作為測試集。
'''
def create_dataset(dataset, look_back=2):
    dataX, dataY = [], []
    for i in range(len(dataset) - look_back):
        a = dataset[i:(i + look_back)]
        dataX.append(a)
        dataY.append(dataset[i + look_back])
    return np.array(dataX), np.array(dataY)
    
# 建立好輸入輸出
data_X, data_Y = create_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:]

'''
最後,我們需要將資料改變一下形狀,因為 RNN 讀入的資料維度是 
(seq, batch, feature),所以要重新改變一下資料的維度,這裡只有一個序列,
所以 batch 是 1,而輸入的 feature 就是我們希望依據的幾個月份,這裡我們
定的是兩個月份,所以 feature 就是 2.
'''    
import torch

train_X = train_X.reshape(-1, 1, 2)
train_Y = train_Y.reshape(-1, 1, 1)
test_X = test_X.reshape(-1, 1, 2)

train_x = torch.from_numpy(train_X)
train_y = torch.from_numpy(train_Y)
test_x = torch.from_numpy(test_X)

from torch import nn
from torch.autograd import Variable

#定義模型
class lstm_reg(nn.Module):
     def __init__(self, input_size, hidden_size, output_size=1, num_layers=2):
          super(lstm_reg, self).__init__()
          
          self.rnn = nn.LSTM(input_size, hidden_size, num_layers)
          self.reg = nn.Linear(hidden_size, output_size)
          
     def forward(self, x):
          x, _ = self.rnn(x) 
          s, b, h = x.shape  #(seq, batch, hidden)
          x = x.view(s*b, h) #轉化為線性層的輸入方式
          x = self.reg(x)
          x = x.view(s, b, -1)
          return x
#定義好網路結構,輸入的維度是 2,因為我們使用兩個月的流量作為輸入,隱藏層的維度可以任意指定,這裡我們選的 4
net = lstm_reg(2, 4)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=1e-2)

#開始訓練
for e in range(1000):
     var_x = Variable(train_x)
     var_y = Variable(train_y)
     #前向傳播
     out = net(var_x)
     loss = criterion(out, var_y)
     #反向傳播
     optimizer.zero_grad()
     loss.backward()
     optimizer.step()
     if (e+1)%100==0:
          print('Epoch:{}, Loss:{:.5f}'.format(e+1, loss.item()))
     
#訓練完成之後,我們可以用訓練好的模型去預測後面的結果
net = net.eval()
data_X = data_X.reshape(-1, 1, 2)
data_X = torch.from_numpy(data_X)
var_data = Variable(data_X)
pred_test = net(var_data) # 測試集的預測結果

# 改變輸出的格式
pred_test = pred_test.view(-1).data.numpy()

# 畫出實際結果和預測的結果
plt.plot(pred_test, 'r', label='prediction')
plt.plot(dataset, 'b', label='real')
plt.legend(loc='best')

網路定義很簡單,一層是lstm層,一層是線性層,注意我們需要使用view來重新排列,因為nn.LInear不接受三維的輸入,只接受兩維的輸入,所以我們可以先將前面兩維合併到一起,然後經過線性層之後再把它們分開,最後輸出結果。建立資料時依賴前面兩個月的流量來預測第三個月的流量,所以輸入的維度是2.

從預測結果可以看出,Lstm得到了比較理想的預測結果,相比與線性迴歸等演算法,迴圈神經網路能更好的處理序列資料。