📢 转载信息
原文链接:https://machinelearningmastery.com/transformer-vs-lstm-for-time-series-which-works-better/
原文作者:Iván Palomares Carrascosa
在本文中,您将学习如何针对下一日单变量时间序列预测,在真实公共交通数据集上构建、训练和比较 LSTM 和 Transformer 模型。
我们将涵盖的主题包括:
- 将时间序列结构化和窗口化以进行监督学习。
- 在 PyTorch 中实现紧凑的 LSTM 和 Transformer 架构。
- 使用 MAE(平均绝对误差)和 RMSE(均方根误差)在保留数据上评估和比较模型。
好了,全速前进。
Transformer 与 LSTM 在时间序列中的比较:哪个效果更好?
图片来源:Editor
引言
从每日天气测量或交通传感器读数到股票价格,时间序列数据几乎无处不在。当这些时间序列数据集变得更具挑战性时,具有更高复杂度的模型——例如集成方法甚至深度学习架构——可能比经典的时间序列分析和预测技术更方便的选择。
本文的目的是展示如何训练和使用两种深度学习架构来处理时间序列数据——长短期记忆网络(LSTM)和Transformer。主要重点不仅是利用这些模型,还包括理解它们在处理时间序列时的差异,以及一个架构是否明显优于另一个。建议具备 Python 和机器学习基础知识。
问题设置与准备
对于这次说明性的比较,我们将考虑一个单变量时间序列的预测任务:给定过去 N 个时间步的顺序数据,预测第 (N+1) 个值。
具体来说,我们将使用芝加哥公共交通网络中自 2001 年以来的公交和轨道交通乘客的每日记录的 芝加哥乘车数据集的公开可用版本。
第一段代码导入了所需的库和模块并加载了数据集。我们将导入 pandas、NumPy、Matplotlib 和 PyTorch——所有这些都用于繁重的工作——以及我们将依赖其进行评估的 scikit-learn 指标。
|
1
2
3
4
5
6
7
8
9
10
11
|
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from sklearn.metrics import mean_squared_error, mean_absolute_error
url = "https://data.cityofchicago.org/api/views/6iiy-9s97/rows.csv?accessType=DOWNLOAD"
df = pd.read_csv(url, parse_dates=["service_date"])
print(df.head())
|
由于数据集包含疫情后的乘客数量真实数据——这可能会因其分布与疫情前数据存在显著差异而严重误导我们模型的预测能力——我们将过滤掉 2020 年 1 月 1 日及以后的记录。
|
1
2
3
4
5
6
7
|
df_filtered = df[df['service_date'] <= '2019-12-31']
print("Filtered DataFrame head:")
display(df_filtered.head())
print("\nShape of the filtered DataFrame:", df_filtered.shape)
df = df_filtered
|
一个简单的绘图即可展示过滤后的数据外观:
|
1
2
3
4
5
6
|
df.sort_values("service_date", inplace=True)
ts = df.set_index("service_date")["total_rides"].fillna(0)
plt.plot(ts)
plt.title("CTA Daily Total Rides")
plt.show()
|
芝加哥乘车时间序列数据集绘图
接下来,我们将时间序列数据分成训练集和测试集。重要的是,在时间序列预测任务中——与分类和回归不同——这种划分不能随机进行,而必须以纯粹的顺序方式进行。换句话说,所有训练实例按时间顺序排列在前,测试实例排在后面。此代码将时间序列的前 80% 作为训练集,剩余 20% 用于测试。
|
1
2
3
4
5
6
|
n = len(ts)
train = ts[:int(0.8*n)]
test = ts[int(0.8*n):]
train_vals = train.values.astype(float)
test_vals = test.values.astype(float)
|
此外,原始时间序列必须转换为带标签的序列 (x, y),跨越固定的时间窗口,以便在它们之上正确训练基于神经网络的模型。例如,如果我们使用 N=30天 的时间窗口,第一个实例将跨越时间序列的前 30 天,要预测的关联标签是第 31 天,依此类推。这为监督学习任务提供了适当的带标签格式,同时不丢失其重要的时间意义:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
def create_sequences(data, seq_len=30):
X, y = [], []
for i in range(len(data)-seq_len):
X.append(data[i:i+seq_len])
y.append(data[i+seq_len])
return np.array(X), np.array(y)
SEQ_LEN = 30
X_train, y_train = create_sequences(train_vals, SEQ_LEN)
X_test, y_test = create_sequences(test_vals, SEQ_LEN)
# Convert our formatted data into PyTorch tensors
X_train = torch.tensor(X_train).float().unsqueeze(-1)
y_train = torch.tensor(y_train).float().unsqueeze(-1)
X_test = torch.tensor(X_test).float().unsqueeze(-1)
y_test = torch.tensor(y_test).float().unsqueeze(-1)
|
我们现在可以开始训练、评估和比较我们的 LSTM 和 Transformer 模型了!
模型训练
在建模阶段,我们将使用 PyTorch 库,因为它提供了定义适用于预测任务的循环 LSTM 层和仅编码器 Transformer 层的必要类。
首先,我们有一个基于 LSTM 的 RNN 架构,如下所示:
|
1
2
3
4
5
6
7
8
9
10
11
|
class LSTMModel(nn.Module):
def __init__(self, hidden=32):
super().__init__()
self.lstm = nn.LSTM(1, hidden, batch_first=True)
self.fc = nn.Linear(hidden, 1)
def forward(self, x):
out, _ = self.lstm(x)
return self.fc(out[:, -1])
lstm_model = LSTMModel()
|
对于下一日时间序列预测的仅编码器 Transformer,我们有:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class SimpleTransformer(nn.Module):
def __init__(self, d_model=32, nhead=4):
super().__init__()
self.embed = nn.Linear(1, d_model)
enc_layer = nn.TransformerEncoderLayer(d_model=d_model, nhead=nhead, batch_first=True)
self.transformer = nn.TransformerEncoder(enc_layer, num_layers=1)
self.fc = nn.Linear(d_model, 1)
def forward(self, x):
x = self.embed(x)
x = self.transformer(x)
return self.fc(x[:, -1])
transformer_model = SimpleTransformer()
|
请注意,两种架构中的最后一层遵循相似的模式:其输入形状是隐藏表示的维度(在我们的例子中为 32),并使用单个神经元来执行下一日总乘车量的单个预测。
现在是时候训练模型并使用测试数据评估两个模型的性能了:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
def train(model, X, y, epochs=10):
model.train()
opt = torch.optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.MSELoss()
for epoch in range(epochs):
opt.zero_grad()
out = model(X)
loss = loss_fn(out, y)
loss.backward()
opt.step()
return model
lstm_model = train(lstm_model, X_train, y_train)
transformer_model = train(transformer_model, X_train, y_train)
|
我们将使用两种常见的指标来比较模型在单变量时间序列预测任务中的表现:平均绝对误差(MAE)和均方根误差(RMSE)。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
lstm_model.eval()
transformer_model.eval()
pred_lstm = lstm_model(X_test).detach().numpy().flatten()
pred_trans = transformer_model(X_test).detach().numpy().flatten()
true_vals = y_test.numpy().flatten()
rmse_lstm = np.sqrt(mean_squared_error(true_vals, pred_lstm))
mae_lstm = mean_absolute_error(true_vals, pred_lstm)
rmse_trans = np.sqrt(mean_squared_error(true_vals, pred_trans))
mae_trans = mean_absolute_error(true_vals, pred_trans)
print(f"LSTM RMSE={rmse_lstm:.1f}, MAE={mae_lstm:.1f}")
print(f"Trans RMSE={rmse_trans:.1f}, MAE={mae_trans:.1f}")
|
🚀 想要体验更好更全面的AI调用?
欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。
评论区