深度學習模型 Transformer 在時間序列預測領域展現出優異的長序列依賴關係處理能力。本文以neuralforecast函式庫為工具,示範如何使用 iTransformer 模型預測航空旅客數量。首先,利用 AirPassengersDF 資料集,劃分訓練集和測試集,並使用 TimeSeriesDataset 構建時間序列資料集。接著,設定 iTransformer 模型的超引數,例如預測步長、輸入大小、隱藏層維度、注意力頭數、編碼器和解碼器層數等,並使用 MSE 和 MAE 作為損失函式進行模型訓練。訓練完成後,使用模型進行預測,並計算 MSE、RMSE、MAPE、R² 和調整後的 R² 等評估指標。最後,將預測結果與實際值視覺化,以評估模型的預測效能。除了 Transformer 模型,本文也介紹了 DLinear 和 NLinear 等線性模型。DLinear 結合了 Autoformer 的分解方法和 FEDformer 的線性層,擅長捕捉長期趨勢和週期性資訊,並透過動態分解和自相關機制提升預測準確性。NLinear 則專注於解決分佈轉移問題,透過簡單的正規化方法提升 Linear 模型在資料分佈變化時的效能。文章提供了 DLinear 和 NLinear 的程式碼例項,包含資料載入、模型訓練、預測和評估等步驟,並透過圖表展示預測結果。這些線性模型在特定場景下可能比複雜的 Transformer 模型更有效,展現了簡單方法的優勢。

使用Transformer進行時間序列預測

在時間序列預測中,Transformer模型因其強大的處理長依賴關係的能力,已成為一個熱門的選擇。這篇文章將探討如何使用neuralforecast函式庫來構建和訓練iTransformer模型,並展示其在預測月度航空旅客數量上的應用。

資料載入與預處理

首先,我們需要載入資料。這裡我們使用neuralforecast.utils中的AirPassengersDF資料集,這個資料集包含了12年的月度航空旅客數量。我們將最後一年的資料用作測試集,剩下的11年資料用作訓練集。

from neuralforecast.utils import AirPassengersDF as Y_df

Y_train_df = Y_df[Y_df.ds <= '1959-12-31']
Y_test_df = Y_df[Y_df.ds > '1959-12-31']

from neuralforecast.tsdataset import TimeSeriesDataset
dataset, *_ = TimeSeriesDataset.from_df(Y_train_df)

架構及引數設定

接下來,我們需要構建iTransformer模型。iTransformer是一種根據Transformers的時間序列預測模型,具備處理長依賴關係的能力。以下是一些關鍵引數:

  • h:預測的未來時間步長(horizon)。
  • input_size:自迴歸輸入的大小。
  • n_series:時間序列的數量。
  • hidden_size:模型的隱藏層維度。
  • n_heads:注意力機制中的頭數。
  • e_layers:編碼器層數。
  • d_layers:解碼器層數。
  • d_ff:前馳全連線層的維度。
  • factor:注意力機制中的縮放因子。
  • dropout:Dropout率。
  • use_norm:是否使用標準化。
  • lossvalid_loss:訓練和驗證時使用的損失函式。
from neuralforecast.models import iTransformer
from neuralforecast.losses.pytorch import MSE, MAE

horizon = 12
model = iTransformer(
    h=horizon,
    input_size=24,
    n_series=2,
    hidden_size=128,
    n_heads=2,
    e_layers=2,
    d_layers=1,
    d_ff=4,
    factor=1,
    dropout=0.1,
    use_norm=True,
    loss=MSE(),
    valid_loss=MAE(),
    batch_size=32
)
model.fit(dataset=dataset, val_size=12)

內容解密:

這段程式碼定義了iTransformer模型並進行訓練。以下是每個引數的作用:

  • h=horizon:設定預測未來12個月的目標。
  • input_size=24:自迴歸輸入大小為24,表示模型將使用過去24個月的資料進行預測。
  • n_series=2:設定兩個時間序列進行訓練。
  • hidden_size=128:隱藏層維度為128,決定了模型的複雜度。
  • n_heads=2:注意力機制中的頭數為2,允許模型同時處理多個依賴關係。
  • e_layers=2, d_layers=1, d_ff=4:編碼器和解碼器層數分別為2和1,前馳全連線層維度為4。
  • factor=1, dropout=0.1, use_norm=True:設定注意力機制縮放因子、Dropout率和是否使用標準化。
  • loss=MSE(), valid_loss=MAE():訓練和驗證時使用均方誤差(MSE)和平均絕對誤差(MAE)。
  • batch_size=32:每批次包含32個不同序列。

模型預測與評估

訓練完成後,我們可以使用模型進行預測。以下是預測過程及評估指標計算:

y_hat = model.predict(dataset=dataset)
Y_test_df['iTransformers'] = y_hat

內容解密:

這段程式碼使用訓練好的iTransformer模型進行未來12個月的預測。以下是每行程式碼的詳細說明:

y_hat = model.predict(dataset=dataset)

執行上述指令會利用已訓練好的iTransformer模型去進行預測工作。

Y_test_df['iTransformers'] = y_hat

將模型生成的預測值儲存到測試資料集中新增的一列,供後續對比與分析之用。

接下來我們計算評估指標:

from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score

def calculate_error_metrics(y_true, y_pred):
    mse = mean_squared_error(y_true, y_pred)
    rmse = mse**0.5
    mape = mean_absolute_percentage_error(y_true, y_pred)
    r2 = r2_score(y_true, y_pred)
    n = len(y_true)
    k = 1  # 假設只有一個特徵
    adjusted_r2 = 1 - (1 - r2) * (n - 1) / (n - k - 1)
    return {
        'MSE': mse,
        'RMSE': rmse,
        'MAPE': mape,
        'r2': r2,
        'adjusted_r2': adjusted_r2
    }

metrics = calculate_error_metrics(Y_test_df[['y']], Y_test_df['iTransformers'])
print(metrics)

內容解密:

這段程式碼計算了多個評估指標來評估模型的效能。以下是每個指標的詳細說明:

mse = mean_squared_error(y_true, y_pred)

均方誤差(MSE),衡量平均預測誤差平方值。

rmse = mse**0.5

均方根誤差(RMSE),MSE 的平方根,提供更直觀的誤差尺度。

mape = mean_absolute_percentage_error(y_true, y_pred)

平均絕對百分比誤差(MAPE),衡量平均預測誤差相對於真實值的百分比。

r2 = r2_score(y_true, y_pred)

決定係數(R²),衡量模型對於真實值變異的解釋程度。

adjusted_r2 = 1 - (1 - r2) * (n - 1) / (n - k - 1)

調整後的決定係數(Adjusted R²),考慮了模型複雜度對R² 的影響。

預測結果視覺化

最後,我們將實際值與預測值進行視覺化對比:

import matplotlib.pyplot as plt

Y_train_df.set_index('ds', inplace=True)
Y_test_df.set_index('ds', inplace=True)

plt.figure(figsize=(20, 3))
y_past = Y_train_df["y"]
y_pred = Y_test_df['iTransformers']
y_test = Y_test_df["y"]

plt.plot(y_past, label="過去時序值")
plt.plot(y_pred, label="預測")
plt.plot(y_test, label="實際時序值")

plt.title('航空旅客預測', fontsize=10)
plt.ylabel('月度旅客人數', fontsize=10)
plt.xlabel('時間戳 [t]', fontsize=10)
plt.legend()
plt.show()

內容解密:

這段程式碼生成了實際值與預測值的對比圖表。以下是每行程式碼的詳細說明:

import matplotlib.pyplot as plt

引入Matplotlib函式庫,用於繪製圖表。

Y_train_df.set_index('ds', inplace=True)
Y_test_df.set_index('ds', inplace=True)

將時間戳設為索引以便於繪圖。

plt.figure(figsize=(20, 3))

建立一個大小為(20, 3) 的圖表。

y_past = Y_train_df["y"]
y_pred = Y_test_df['iTransformers']
y_test = Y_test_df["y"]

分別提取過去時序值、預測值和實際時序值。

plt.plot(y_past, label="過去時序值")
plt.plot(y_pred, label="預測")
plt.plot(y_test, label="實際時序值")

繪製過去時序值、預測值和實際時序值。

plt.title('航空旅客預測', fontsize=10)
plt.ylabel('月度旅客人數', fontsize=10)
plt.xlabel('時間戳 [t]', fontsize=10)
plt.legend()
plt.show()

設定圖表標題、軸標籤和顯示圖例,然後顯示圖表。

DLinear 概述

DLinear 是一種根據線性迴歸的時間序列預測模型,專注於提取長期趨勢和週期性資訊。它結合了 Autoformer 的趨勢與季節性分解方法以及 FEDformer 的線性層,能夠在有明確趨勢的時間序列上顯著提升效能。

DLinear 的特色:

動態分解:DLinear 使用動態分解方法來處理趨勢和季節性成分,這些成分在每次迭代中都會更新和精煉。

自相關機制:利用自相關機制發現根據週期性依賴關係。

Autoformer 概述

Autoformer 是一種根據自相關機制的時間序列預測模型。它透過分解時間序列成趨勢與季節性成分來提升模型能力。Autoformer 的編碼器主要處理季節性部分,而解碼器則負責結合趨勢週期成分和自相關機制來精煉預測結果。

Autoformer 的架構:

編碼器:專注於季節性部分,幫助解碼器利用過去季節資訊來精煉預測。

解碼器:結合趨勢週期成分和自相關機制來提升預測準確性。

融合:透過逐步精煉趨勢週期元件並消除幹擾資訊來發現根據週期性依賴關係。

DLinear 與 Autoformer 對比

DLinear 和 Autoformer 在處理時間序列預測時有不同的特點:

特色 DLinear Autoformer
分解方法 動態分解(移動平均核心) 分解層加強功能
自相關機制 根據週期性依賴 自動相關機制提升準確度
編碼器 無特定編碼器 編碼器專注季節性部分
風格 根據線性迴歸 根據轉換器

與改進建議

根據線性迴歸的 DLinear 模型在某些情況下可能會優於複雜轉換器模型。然而,當面臨複雜且高變異性的時序資料時,仍需考慮轉換器或其他非線性方法以取得更佳效果。此外,DLinear 的成功應用也顯示出簡單有效方法在某些情況下可能會超越複雜模型。因此未來可以考慮結合多種方法以應對不同型別的時間序列資料挑戰。

使用Transformer進行時間序列分析

自相關機制

自相關機制透過序列間的連線擴充套件資訊利用,從而發現根據週期的依賴關係。這一過程透過計算序列的自相關性來實作,並透過時間延遲聚合方式將相似的子序列進行聚合。

具體來說,快速傅裡葉變換(Fast Fourier Transform)用於計算自相關函式 ( R(T) ),這個函式反映了時間延遲的相似性。接著,根據選定的延遲 ( T ),將相似的子過程滾動到相同的索引位置,並根據 ( R(T) ) 進行聚合。最終的預測結果是兩個精煉分解元件的總和。

時間延遲聚合

時間延遲聚合透過估計週期連線子序列。如圖3-14(右)所示,時間延遲聚合可以根據選定的時間延遲來滾動序列。這一操作可以對齊處於估計週期相同相位位置的相似子序列,這與自我注意機制中的點積聚合不同。最終,它透過 softmax 正規化的置信度進行子序列聚合。

DLinear結構

DLinear 的結構可以簡單表示為 ( X = H_s + H_t ),其中 ( H_s ) 和 ( H_t ) 分別代表分解後的趨勢和剩餘特徵。DLinear 擅長捕捉短期和長期的時間關係,且由於每個分支僅包含一個線性層,因此它在記憶和引數使用上比現有的 Transformer 模型更加高效。

DLinear實戰

讓我們將 DLinear 的理論基礎轉化為實際的程式碼實作。首先,匯入必要的函式庫:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import DLinear
from neuralforecast.losses.pytorch import MAE
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast.utils import AirPassengersDF

接著,載入資料集並將最後一年的資料保留作為測試集:

Y_df = AirPassengersDF
Y_df = Y_df.reset_index(drop=True)
Y_train_df = Y_df[Y_df.ds <= '1959-12-31']
Y_test_df = Y_df[Y_df.ds > '1959-12-31']

現在,我們來訓練 DLinear 模型並定義其超引數:

horizon = 12
model = DLinear(
    h=horizon,
    input_size=12,
    loss=MAE(),
    scaler_type='robust',
    learning_rate=1e-3,
    max_steps=500,
    val_check_steps=50,
    early_stop_patience_steps=2
)
nf = NeuralForecast(models=[model], freq='M')
nf.fit(df=Y_train_df, val_size=12)

預測未來 12 個月份:

forecasts = nf.predict()
print(forecasts.head())

評估模型準確性:

def calculate_error_metrics(y_true, y_pred):
    mse = mean_squared_error(y_true, y_pred)
    rmse = np.sqrt(mse)
    mape = mean_absolute_percentage_error(y_true, y_pred)
    r2 = r2_score(y_true, y_pred)
    adjusted_r2 = 1 - (1 - r2) * (len(y_true) - 1) / (len(y_true) - 2 - 1)
    return {
        "MSE": mse,
        "RMSE": rmse,
        "MAPE": mape,
        "r2": r2,
        "adjusted_r2": adjusted_r2
    }

error_metrics = calculate_error_metrics(Y_test_df[['y']], forecasts['DLinear'])
print(error_metrics)

最後,我們來視覺化預測結果:

Y_train_df.set_index('ds', inplace=True)
forecasts.set_index('ds', inplace=True)
Y_test_df.set_index('ds', inplace=True)

plt.figure(figsize=(20, 3))
y_past = Y_train_df["y"]
y_pred = forecasts['DLinear']
y_test = Y_test_df["y"]

plt.plot(y_past, label="Past time series values")
plt.plot(y_pred, label="Forecast")
plt.plot(y_test, label="Actual time series values")
plt.title('AirPassengers Forecast', fontsize=10)
plt.ylabel('Monthly Passengers', fontsize=10)
plt.xlabel('Timestamp [t]', fontsize=10)
plt.legend()

此圖示展示了模型預測與實際資料之間的對比,顯示出模型預測結果與實際情況非常接近。

NLinear模型

NLinear 是 LTSF-Linear 家族中的一員,專門設計用於在資料集中存在分佈轉移時提升 Linear 模型的效能。NLinear 首先將輸入減去序列中的最後一個值,然後透過線性層處理輸入,最後在進行最終預測之前將減去的部分加回去。這種減法和加法操作是輸入序列的一種簡單正規化方式。

NLinear 通常能夠在大多數情況下以很大優勢超越所有根據 Transformer 的方法。透過從看回視窗中最後一個值進行簡單正規化,能夠顯著減輕分佈轉移問題。

分佈轉移是指訓練資料的統計特性與測試資料之間存在顯著差異。當模型在某一組資料上進行訓練但應用於具有不同特徵的資料時,這種情況就會發生。常見的分佈轉移型別包括協變數轉移、標籤轉移和概念漂移。如果不妥善處理這些轉移型別,可能會導致效能下降和不可靠預測。

NLinear實戰

讓我們將 NLinear 的理論基礎轉化為實際的程式碼實作。首先,匯入必要的函式庫(略),然後載入資料集並進行資料準備(略)。

現在,我們來訓練 NLinear 模型並定義其超引數(略)。

接著進行預測並評估模型準確性(略)。

最後,視覺化預測結果(略)。

內容解密:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import DLinear
from neuralforecast.losses.pytorch import MAE
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast.utils import AirPassengersDF

Y_df = AirPassengersDF.reset_index(drop=True)
Y_train_df = Y_df[Y_df.ds <= '1959-12-31']
Y_test_df = Y_df[Y_df.ds > '1959-12-31']

horizon = 12

model = DLinear(
    h=horizon,
    input_size=12,
    loss=MAE(),
    scaler_type='robust',
    learning_rate=1e-3,
    max_steps=500,
    val_check_steps=50,
    early_stop_patience_steps=2
)

nf = NeuralForecast(models=[model], freq='M')
nf.fit(df=Y_train_df, val_size=12)

forecasts = nf.predict()
print(forecasts.head())

def calculate_error_metrics(y_true, y_pred):
    mse = mean_squared_error(y_true, y_pred)
    rmse = np.sqrt(mse)
    mape = mean_absolute_percentage_error(y_true, y_pred)
    r2 = r2_score(y_true, y_pred)
    adjusted_r2 = 1 - (1 - r2) * (len(y_true) - 1) / (len(y_true) - 2 - 1)
    return {
        "MSE": mse,
        "RMSE": rmse,
        "MAPE": mape,
        "r2": r2,
        "adjusted_r2": adjusted_r2
    }

error_metrics = calculate_error_metrics(Y_test_df[['y']], forecasts['DLinear'])
print(error_metrics)

Y_train_df.set_index('ds', inplace=True)
forecasts.set_index('ds', inplace=True)
Y_test_df.set_index('ds', inplace=True)

plt.figure(figsize=(20, 3))
y_past = Y_train_df["y"]
y_pred = forecasts['DLinear']
y_test = Y_test_df["y"]

plt.plot(y_past, label="Past time series values")
plt.plot(y_pred, label="Forecast")
plt.plot(y_test, label="Actual time series values")
plt.title('AirPassengers Forecast', fontsize=10)
plt.ylabel('Monthly Passengers', fontsize=10)
plt.xlabel('Timestamp [t]', fontsize=10)
plt.legend()

內容解密:

本段程式碼首先匯入了必要的函式庫及載入資料集以進行時間序列預測。接著定義了 DLinear 模型並進行訓練、預測以及評估模型準確性。最後透過畫圖展示預測結果與實際資料之間的對比。

這段程式碼展示瞭如何使用 DLinear 模型進行時間序列預測。首先匯入必要的函式庫並載入資料集 AirPassengersDF,然後將資料集分成訓練集和測試集。

接著定義 DLinear 模型及其超引數,並使用 NeuralForecast 函式庫進行訓練及預測。最後計算評估指標並視覺化預測結果與實際資料之間的對比。

該程式碼展示瞭如何使用 NeuralForecast 函式庫及 DLinear 模型進行時間序列預測及評估模型效能。

程式邏輯清晰且易於理解:從資料準備開始逐步進行模型訓練、預測及評估指標計算;設計考量了模型準確性及視覺化效果;未來可能改進點包括更多超引數調整及不同模型比較等方面。