实战案例:利用 Transformer 网络进行时间序列模型预测(附完整 Python 代码)

我最近读了一篇非常有趣的论文:Deep Transformer Models for Time Series Forecasting: The Influenza Prevalence Case。这可能是一个有趣的项目,从零开始实施类似的东西,以了解更多关于时间序列预测。

预测任务:

在时间序列预测中,目标是根据时间序列的历史价值预测其未来价值。时间序列预测任务的一些例子如下:

  • 预测流感流行个案:Deep Transformer Models for Time Series Forecasting: The Influenza Prevalence Case

  • 能源产量预测:Energy consumption forecasting using a stacked non-parametric Bayesian approach

  • 天气预报:MetNet: A Neural Weather Model for Precipitation Forecasting

例如,我们可以将一个城市的能源消耗量数据存储几个月,然后训练一个模型,该模型将能够预测该城市未来的能源消耗。这可以用来估计能源需求,因此能源公司可以使用这个模型来估计在任何特定时间需要生产的能源的最佳价值。

源码&技术交流

本文项目源码、数据、技术交流提升,均可加交流群获取,群友已超过2000人,添加时最好的备注方式为:来源+兴趣方向,方便找到志同道合的朋友

方式①、添加微信号:dkl88191,备注:来自CSDN +研究方向
方式②、微信搜索公众号:Python学习与数据挖掘,后台回复:tf时间序列

时间序列预测实例

我们将使用的模型是一个编解码 Transformer,其中编码器部分作为输入的历史时间序列,而解码器部分以自回归的方式预测未来的价值。

解码器使用注意机制与编码器连接。通过这种方式,解码器可以学会在进行预测之前“关注”时间序列中最有用的部分历史值。

解码器使用 masked self-attention,使网络不能在训练运行过程中通过预测未来值来预测过去值来作弊。

编码器子网络:

解码器子网络:

完整模型:

自回归编/解码 Transformer

这个体系结构可以使用 PyTorch 构建,方法如下:

encoder_layer = nn.TransformerEncoderLayer(
    d_model=channels,
    nhead=8,
    dropout=self.dropout,
    dim_feedforward=4 * channels,
)
decoder_layer = nn.TransformerDecoderLayer(
    d_model=channels,
    nhead=8,
    dropout=self.dropout,
    dim_feedforward=4 * channels,
)

self.encoder = torch.nn.TransformerEncoder(encoder_layer, num_layers=8)
self.decoder = torch.nn.TransformerDecoder(decoder_layer, num_layers=8)

数据

每次我实现一种新的方法时,我都喜欢首先在合成数据上进行尝试,以便更容易理解和调试。这降低了数据的复杂性,并且更加关注于实现/算法。

我编写了一个小脚本,可以生成具有不同周期、偏移量和模式的非平凡时间序列。

def generate_time_series(dataframe):

    clip_val = random.uniform(0.3, 1)

    period = random.choice(periods)

    phase = random.randint(-1000, 1000)

    dataframe["views"] = dataframe.apply(
        lambda x: np.clip(
            np.cos(x["index"] * 2 * np.pi / period + phase), -clip_val, clip_val
        )
        * x["amplitude"]
        + x["offset"],
        axis=1,
    ) + np.random.normal(
        0, dataframe["amplitude"].abs().max() / 10, size=(dataframe.shape[0],)
    )

    return dataframe

生成的时间序列示例

然后,该模型同时对所有这些时间序列进行训练:

训练损失

结果

我们现在使用这个模型来预测这些时间序列的未来价值,结果有点喜忧参半:

错误的

错误预测的例子

正确的

正确预测的例子

结果并不像我预期的那么好,特别是考虑到通常很容易对合成数据做出好的预测,但是他们仍然是让人有所期待的。

该模型的预测有点不同步与轻微的振幅高估了一些不良的例子。在好的例子中,除去噪音,这个预测非常符合实际情况。

我可能需要调试我的代码多一点,并在优化超参数之前,我可以期望得到更好的结果。

  • 6
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
好的,下面是一个简单的用Transformer进行时间序列预测Python代码,包含数据准备、模型搭建、训练和预测可视化等步骤: ```python import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler import torch from torch import nn from torch.utils.data import Dataset, DataLoader # 准备数据 df = pd.read_csv('data.csv', index_col=0) scaler = MinMaxScaler() data = scaler.fit_transform(df.values) train_data = data[:200] test_data = data[200:] # 定义数据集类 class TimeSeriesDataset(Dataset): def __init__(self, data, seq_len): self.data = data self.seq_len = seq_len def __len__(self): return len(self.data) - self.seq_len def __getitem__(self, idx): x = self.data[idx:idx+self.seq_len] y = self.data[idx+self.seq_len] return x, y # 定义模型 class TransformerModel(nn.Module): def __init__(self, input_size, output_size, num_layers, hidden_size, num_heads, dropout): super().__init__() self.encoder = nn.Sequential( nn.Linear(input_size, hidden_size), nn.ReLU(), nn.Linear(hidden_size, hidden_size), nn.ReLU(), nn.Linear(hidden_size, hidden_size) ) self.decoder = nn.Sequential( nn.Linear(1, hidden_size), nn.ReLU(), nn.Linear(hidden_size, hidden_size), nn.ReLU(), nn.Linear(hidden_size, output_size) ) self.transformer = nn.Transformer( d_model=hidden_size, nhead=num_heads, num_encoder_layers=num_layers, num_decoder_layers=num_layers, dropout=dropout ) def forward(self, x, y): x = self.encoder(x.unsqueeze(0)) y = self.decoder(y.unsqueeze(0)) x = x.transpose(0, 1) y = y.transpose(0, 1) out = self.transformer(x, y) out = out.transpose(0, 1) out = out.squeeze(0) return out # 训练模型 model = TransformerModel(input_size=10, output_size=1, num_layers=1, hidden_size=32, num_heads=2, dropout=0.1) criterion = nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) train_dataset = TimeSeriesDataset(train_data, seq_len=10) train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) num_epochs = 100 for epoch in range(num_epochs): for x, y in train_loader: optimizer.zero_grad() y_pred = model(x, y[:, 0]) loss = criterion(y_pred, y[:, 1]) loss.backward() optimizer.step() print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, loss.item())) # 预测并可视化结果 model.eval() x_test = test_data[:10] y_test = test_data[10:, 0] y_pred = [] for i in range(len(y_test)): with torch.no_grad(): x = torch.from_numpy(x_test.astype(np.float32)) y = torch.from_numpy(np.array([y_test[i]]).astype(np.float32)) y_pred_i = model(x, y).item() y_pred.append(y_pred_i) x_test = np.concatenate([x_test[1:], np.array([y_test[i], y_pred_i]).reshape(1, -1)], axis=0) y_pred = scaler.inverse_transform(np.array(y_pred).reshape(-1, 1)) y_test = scaler.inverse_transform(y_test.reshape(-1, 1)) df_pred = pd.DataFrame(y_pred, index=df.index[210:], columns=['pred']) df_test = pd.DataFrame(y_test, index=df.index[210:], columns=['test']) df_pred.plot() df_test.plot() ``` 这个代码中的数据是从一个名为"data.csv"的csv文件中读取的,数据的第一列是时间戳,后面的列是一些时间序列数据。代码中用到的是单变量时间序列数据,如果有多变量时间序列数据,需要在数据准备和模型定义的时候进行相应的修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值