變壓器模型在自然語言處理領域取得巨大成功後,也開始應用於時序預測任務。其自注意力機制能有效捕捉長期依賴關係,提升預測準確度。本文以航空乘客數量預測為例,逐步講解如何使用變壓器模型進行時序資料分析,並探討 PatchTST 模型的架構、分塊技術、自監督表示學習等核心概念。同時,文章也涵蓋了資料前處理、模型訓練、超引數調整、預測評估以及結果視覺化等實務操作,並提供 Python 程式碼和圖表輔助說明,讓讀者能更輕鬆地理解和應用變壓器模型於時序預測任務中。此外,文章也討論了損失函式設計、例項正規化等技術細節,以及 PatchTST 模型在監督學習和自監督學習中的應用場景,提供更全面的技術視野。
時序預測的變壓器模型
在處理時序預測問題時,變壓器(Transformer)模型展現了強大的能力。變壓器最初被設計用於自然語言處理任務,但其架構也非常適合處理時序資料。本篇文章將探討如何利用變壓器模型來進行時序預測,並提供具體的實作案例。
匯入必要的模組
首先,我們需要匯入一些必要的 Python 模組來進行資料處理和模型訓練。這些模組包括 NumPy、Pandas、Matplotlib、NeuralForecast 以及一些評估指標。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import MLP, NLinear
from neuralforecast.losses.pytorch import MQLoss, DistributionLoss, MAE
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast.utils import AirPassengersDF, augment_calendar_df
資料集載入與前處理
接下來,我們將載入並前處理時序資料集。這裡我們使用的是 AirPassengersDF 資料集,這個資料集包含了 12 年的每月航空乘客數量。我們將最後一年的資料用於測試,剩下的 11 年資料用於模型訓練。
# 載入資料集並重置索引
Y_df = AirPassengersDF()
Y_df = Y_df.reset_index(drop=True)
Y_df.head()
# 分割訓練和測試資料集
Y_train_df = Y_df[Y_df.ds <= '1959-12-31']
Y_test_df = Y_df[Y_df.ds > '1959-12-31']
模型訓練與超引數設定
我們使用 NLinear 模型來進行時序預測。這個模型是一個簡單且高效的線性模型,適合作為基礎模型進行比較。以下是一些超引數的設定:
horizon:預測的時間步長。input_size:自迴歸輸入的大小。loss:損失函式。scaler_type:標準化方法。learning_rate:學習率。max_steps:最大訓練步數。val_check_steps:驗證損失檢查間隔。early_stop_patience_steps:早停耐心度。
horizon = 12
model = NLinear(
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)
內容解密:
上述程式碼首先定義了預測的時間步長 horizon 為 12,即我們要預測未來 12 個月的乘客數量。接著我們建立了一個 NLinear 模型例項,並設定了各種超引數。例如,input_size=12 意味著我們使用過去 12 個月的資料作為自迴歸輸入。損失函式選擇了平均絕對誤差(MAE),標準化方法選擇了Robust Scaler。學習率設定為 0.001,最大訓練步數為 500。驗證損失檢查間隔為 50 步,早停耐心度為 2 步。
預測與評估
完成模型訓練後,我們可以使用訓練好的模型進行預測。以下是預測和評估的程式碼:
# 預測未來時間步長
forecasts = nf.predict()
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)
adj_r2 = 1 - (1 - r2) * (len(y_true) - 1) / (len(y_true) - y_true.shape[1] - 1)
return {
'MSE': mse,
'RMSE': rmse,
'MAPE': mape,
'R2': r2,
'Adjusted R2': adj_r2
}
error_metrics = calculate_error_metrics(Y_test_df[['y']], forecasts['NLinear'])
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['NLinear']
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()
內容解密:
在這段程式碼中,我們首先使用訓練好的模型進行預測,並顯示前幾個預測值。接著我們定義了一個函式 calculate_error_metrics 用於計算各種誤差指標,包括均方誤差(MSE)、均方根誤差(RMSE)、平均絕對百分比誤差(MAPE)、R平方(R²)以及調整後的 R平方(Adjusted R²)。然後我們使用這些指標評估模型的精確度。
最後,我們將過去的實際值、預測值和實際值繪製在同一張圖上,以便直觀地比較預測結果與實際結果。
PatchTST 模型概述
PatchTST 是一種支援多變數時序預測和自監督表示學習的變壓器模型。它根據將時序資料分割成子序列級別的塊(patches),這些塊作為變壓器的輸入令牌。
此圖示展示了 PatchTST 模型概述:
graph TD;
A[多變數時序資料] --> B[分割成不同頻道];
B --> C[分享相同變壓器主幹];
C --> D[獨立前向過程];
內容解密:
多變數時序資料被分割成不同頻道(channel),這些頻道分享相同的變壓器主幹結構,但前向過程是獨立進行的。這種設計使得 PatchTST 能夠更好地捕捉每個頻道中的獨特特徵和模式。
PatchTST 的技術細節
PatchTST 的核心概念是「分塊」技術。透過將時序資料分割成小塊(patches),我們可以更有效地提取區域性資訊和語義資訊。
此圖示展示了 PatchTST 的技術細節:
graph TD;
A[原始單變數時序] --> B[Instance Norm + Patching];
B --> C[Flatten + Linear Head];
內容解密:
原始單變數時序資料首先透過例項標準化操作和分塊過程。這些分塊被用作變壓器的輸入令牌。然後經過平坦化和線性頭部操作來生成最終輸出。
分塊技術
傳統變壓器中的點態注意力機制試圖從單個時間步取得資訊,這在時序資料中並不理想。PatchTST 則透過將單變數輸入分割成重疊或不重疊的塊來改進這一點。
此圖示展示了分塊技術:
graph TD;
A[原始單變數時序 x(i)] --> B[分割成重疊或不重疊的塊];
B --> C[減少計算複雜度];
內容解密:
原始單變數時序被分割成重疊或不重疊的塊,每個塊包含一定長度的時間步。這種方法可以顯著減少計算複雜度和記憶使用量,從而提升模型效率。
自監督表示學習
PatchTST 支援自監督表示學習。透過遮蔽某些塊並重建這些遮蔽區域,模型可以更好地捕捉時序資料中的特徵。
內容解密:
自監督表示學習透過遮蔽某些塊並要求模型重建這些遮蔽區域來提升表示能力。這種方法有助於捕捉更多語義資訊和特徵。
停止規則與注意事項
在本文中,玄貓對於每一段程式碼都加上「#### 內容解密」標題,並詳細解釋其作用、邏輯及設計考量。透過具體案例及詳細解說,玄貓希望能夠幫助讀者更好地理解時序預測中的技術細節及應用技巧。
如果有任何問題或需要進一步解釋的地方,請隨時告訴玄貓。
使用變壓器進行時間序列分析
瞭解變壓器架構
變壓器架構自2017年推出以來,已經成為處理時間序列資料的強大工具。它的核心組成部分包括自注意力機制、前馳識別器(Feed-Forward Networks)和位置編碼(Positional Encoding)。這些元素共同作用,使得變壓器能夠捕捉時間序列中的長期依賴關係和複雜模式。
損失函式設計
在時間序列預測中,選擇合適的損失函式至關重要。常見的損失函式包括均方誤差(Mean Squared Error, MSE),它能夠量化預測值與真實值之間的差異。MSE 的計算方式如下:
[ L = \frac{1}{M} \sum_{i=1}^{M} | \hat{y}_i - y_i |^2 ]
其中,( \hat{y}_i ) 是預測值,( y_i ) 是真實值,( M ) 是時間序列的數量。透過平均每個時間序列的損失,我們可以得到整體的目標損失。
例項正規化
例項正規化(Instance Normalization)是一種技術,用於減少訓練資料和測試資料之間的分佈差異。其原理是將每個時間序列例項 ( x(i) ) 正規化為零均值和單位標準差。在正規化後,為了確保預測結果的合理性,我們會將原本的均值和標準差加回到預測值中。
PatchTST 的應用場景
PatchTST(Patch-based Time Series Transformer)不僅可以用於監督學習中的時間序列預測,還可以應用於自監督學習中。在自監督學習中,PatchTST 使用相同的編碼器來捕捉資料的抽象表示。不同於監督學習中的重疊補丁,自監督學習中每個輸入序列都被分割成不重疊的補丁。這樣做是為了確保觀察到的補丁不包含被遮蔽補丁的資訊。
具體來說,我們會隨機選擇一部分補丁並將其遮蔽為零值。模型的訓練目標是透過最小化重建遮蔽補丁的損失來學習資料表示。
此圖示
graph TD;
A[原始時間序列] --> B[分割成非重疊補丁];
B --> C[隨機選擇並遮蔽補丁];
C --> D[模型重建遮蔽補丁];
內容解密:
- A:代表原始時間序列資料。
- B:將原始時間序列分割成非重疊的補丁。
- C:從這些補丁中隨機選擇一部分並將其遮蔽為零值。
- D:模型根據未遮蔽的部分來重建被遮蔽的補丁。
實踐操作
接下來,我們將探討如何將這些理論概念轉化為實際程式碼實作。我們將使用「乘客人數」資料集作為示範。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import PatchTST
from neuralforecast.losses.pytorch import DistributionLoss
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
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']
dataset, *_ = TimeSeriesDataset.from_df(Y_train_df)
# 初始化 PatchTST 模型
horizon = 12
model = PatchTST(
h=horizon,
input_size=104,
patch_len=12,
stride=24,
revin=False,
hidden_size=16,
n_heads=4,
scaler_type='robust',
loss=DistributionLoss(distribution='StudentT', level=[80, 90]),
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, static_df=None, val_size=12)
內容解密:
- Import 函式庫:首先匯入所需的 Python 函式庫。
- 載入資料集:從
neuralforecast.utils中載入「乘客人數」資料集。 - 初始化模型:設定 PatchTST 模型引數,包括預測視野
horizon、input_size、patch_len、stride、隱藏層大小hidden_size和注意力頭數n_heads。 - 訓練模型:使用訓練資料集訓練模型。
# 預測未來資料
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)-len(y_pred)-1)
return mse, rmse, mape, r2, adjusted_r2
metrics = calculate_error_metrics(Y_test_df['y'], forecasts['PatchTST'])
print(f"MSE: {metrics[0]}, RMSE: {metrics[1]}, MAPE: {metrics[2]}, r2: {metrics[3]}, adjusted_r2: {metrics[4]}")
內容解密:
- 預測未來資料:使用訓練好的模型進行預測。
- 評估模型準確性:計算均方誤差(MSE)、均方根誤差(RMSE)、平均絕對百分比誤差(MAPE)和 R^2 分數來評估模型效能。
# 視覺化預測結果
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))
plt.plot(Y_train_df["y"], label="Past time series values")
plt.plot(forecasts['PatchTST'], label="Forecast")
plt.plot(Y_test_df["y"], label="Actual time series values")
plt.title('AirPassengers Forecast')
plt.ylabel('Monthly Passengers')
plt.xlabel('Timestamp [t]')
plt.legend()
plt.show()
內容解密:
- 視覺化預測結果:繪製過去、預測和真實乘客人數資料,直觀地比較模型預測與實際情況。
