pytorch RNN用於時間序列的分析
阿新 • • 發佈:2018-11-09
本文參考書籍《深度學習入門之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得到了比較理想的預測結果,相比與線性迴歸等演算法,迴圈神經網路能更好的處理序列資料。