橘智橘智
FakeOrange
预计阅读时间:5分钟51秒

探索TiDE的架构并在Python中应用于预测项目

使用TiDE进行时间序列预测

0
0


前言



本文属于搬运内容,原作者:Marco Peixeiro(Salute!)原文链接在文章末尾。



在我们探索时间序列预测领域的最新进展时,我们发现了N-HiTS、PatchTST、TimeGPT以及TSMixer。

尽管已经有许多努力将Transformer架构应用于预测任务,但事实证明,考虑到计算需求,Transformer的表现相对平庸。


事实上,简单的线性模型已经在许多基准数据集上超过了复杂的基于Transformer的模型(见Zheng等,2022年)。


因此,2023年4月,谷歌的研究人员提出了TiDE:一个采用多层感知机(MLP)构建的长期预测模型,具有编码器-解码器架构。


在他们的论文《长期预测与TiDE:时间序列密集编码器》中,作者证明,该模型在与其他基于Transformer和MLP的模型(如PatchTST和N-HiTS)的比较中,达到了最先进的结果。


在本文中,我们首先探索TiDE的架构和内部工作原理。然后,我们将在Python中应用该模型,并进行我们自己的小规模预测实验。


要了解TiDE的更多细节,请务必阅读原始论文。原始论文解读在此!



探索TiDE



TiDE代表“时间序列密集编码器”。该模型基于编码器-解码器概念,但没有Transformer模型中的自注意力机制。


相反,它依赖于多层感知机(MLP)来实现更快的训练和推理时间,同时保持良好的性能。


在训练过程中,该模型将历史数据与协变量一起编码。然后,它将解码学习到的表示,并结合已知的未来协变量进行预测。



TiDE架构



TiDE的架构如下图所示:


data/78df2c1f-e442-415d-a382-fa7925af0c4b/3c4b60cf-2363-4562-ac82-ff5547aef01fimage.png
图片来源:A. Das, W. Kong, A. Leach, S. Mathur, R. Sen, R. Yu,《长期预测与TiDE:时间序列密集编码器》


从上面的图中,我们可以看到,模型将每个时间序列视为一个独立的通道,这意味着每次都会传递一个时间序列及其协变量。


我们还可以看到,模型有三个主要组成部分:编码器、解码器和时间解码器,所有这些都依赖于残差块架构。


这个图包含了很多信息,接下来我们将更详细地探讨每个组件。



探索残差块



如前所述,残差块是TiDE架构的基础层。


data/78df2c1f-e442-415d-a382-fa7925af0c4b/2bcaba89-5d85-4165-962a-d56f6a525b18image.png
图片来源:A. Das, W. Kong, A. Leach, S. Mathur, R. Sen, R. Yu,《长期预测与TiDE:时间序列密集编码器》


从图中可以看出,残差块是一个具有一个隐藏层和ReLU激活函数的多层感知机(MLP)。接下来是一个丢弃层、一个跳跃连接和最后的层归一化步骤。


然后,这个组件在整个网络中被重复使用,用于编码、解码并进行预测。



理解编码器



在这一步,模型将时间序列的过去值和协变量映射到一个密集表示。


第一步是进行特征投影。在这一步,使用残差块将动态协变量(随着时间变化的外生变量)映射到一个较低维度的投影空间。


请记住,在进行多元预测时,我们需要使用特征的未来值。因此,模型必须处理一个回溯窗口和一个预测序列。


这些序列可能非常长,因此通过将其投影到较低维度的空间中,我们能够保持序列的长度可控,并允许模型处理较长的序列,无论是历史窗口还是预测的时间范围。


第二步是将序列的过去值与其属性以及过去和未来协变量的投影进行拼接。然后,将拼接后的数据送入编码器,编码器实际上是由多个残差块堆叠而成。


因此,编码器负责学习输入的表示,可以看作是一个学习到的嵌入表示。


完成后,嵌入表示被传送到解码器。



理解解码器



在这一部分,解码器的任务是接收编码器学到的表示并生成预测。


第一步是密集解码器,它也由一系列残差块构成。它接受编码后的信息并输出一个矩阵,这个矩阵将被送入时间解码器。


解码后的输出与投影特征堆叠在一起,以捕捉未来协变量的直接影响。例如,假期是特定事件,可能对某些时间序列产生重要影响。通过这种残差连接,模型可以捕捉并利用这些信息。


第二步是时间解码器,生成预测。在这里,时间解码器只是一个输出大小为1的残差块,这样我们就能得到给定时间序列的预测结果。



现在我们理解了TiDE的每个关键组件,接下来让我们在一个小的预测项目中应用TiDE。



使用TiDE进行预测



现在,让我们在一个小的预测项目中应用TiDE,并将其性能与TSMixer进行比较。


有趣的是,TSMixer也是一个基于MLP的多元预测架构,由Google的研究人员开发,但它在TiDE之前的一个月就发布了。所以我觉得将这两种模型进行比较是很有意思的。


如果你想了解TSMixer的更多细节,确保阅读我专门介绍它的文章。(待更新!)


在这个项目中,我们使用Etth1数据集,这个数据集是根据创作共用许可证发布的。


这是一个流行的时间序列预测基准数据集,广泛用于文献研究。它记录了一个电力变压器的每小时油温和其他协变量,非常适合进行多元预测。


这个实验的完整源代码可以在GitHub上找到。戳这里!



导入库并读取数据



自然的第一步是导入项目所需的库,并读取数据。


虽然TiDE原始论文的源代码可以在GitHub上公开访问,但我选择使用Darts中提供的实现。它为我们提供了更大的灵活性,并且拥有原始仓库中没有的超参数优化功能。


因此,让我们导入Darts以及其他常用的包。


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from darts import TimeSeries
from darts.datasets import ETTh1Dataset


然后,我们可以读取数据。幸运的是,Darts提供了学术界广泛使用的标准数据集,比如Etth1数据集。


series = ETTh1Dataset().load()


最后,我们将数据集拆分,并为测试集保留最后96个时间步的数据。


train, test = series[:-96], series[-96:]

现在我们已经准备好训练TiDE模型了。



训练TiDE



要使用TiDE,我们只需从Darts库中导入它。在训练之前,我们还需要手动对数据进行缩放,以确保更快且更稳定的训练过程。


from darts.models.forecasting.tide_model import TiDEModel
from darts.dataprocessing.transformers import Scaler

train_scaler = Scaler()
scaled_train = train_scaler.fit_transform(train)


然后,我们初始化模型并指定其参数。这里,我使用了论文中为这个数据集提供的相同优化参数。


tide = TiDEModel(
    input_chunk_length=720, 
    output_chunk_length=96,
    num_encoder_layers=2,
    num_decoder_layers=2,
    decoder_output_dim=32,
    hidden_size=512,
    temporal_decoder_hidden=16,
    use_layer_norm=True,
    dropout=0.5,
    random_state=42
)


接下来,我们可以直接训练模型。请注意,我只训练了30个周期,如果你有更多的时间和计算资源,可以增加训练的周期数。


tide.fit(
    scaled_train,
    epochs=30
)


训练完成后,我们可以获取模型的预测结果。由于我们对训练数据进行了缩放,模型输出的预测也会是缩放后的。因此,我们需要反转缩放变换。


scaled_pred_tide = tide.predict(n=96)

pred_tide = train_scaler.inverse_transform(scaled_pred_tide)


完美!接下来我们可以评估TiDE模型的性能。



评估性能



为了评估模型的性能,我们将预测值和实际值存储在一个DataFrame中。


preds_df = pred_tide.pd_dataframe()
test_df = test.pd_dataframe()


如果需要,我们可以可视化预测结果。为了简单起见,我这里只画出四列数据。


cols_to_plot = ['OT', 'HULL', 'MUFL', 'MULL']

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12,8))

for i, ax in enumerate(axes.flatten()):
    col = cols_to_plot[i]
        
    ax.plot(test_df[col], label='Actual', ls='-', color='blue')
    ax.plot(preds_df[col], label='TiDE', ls='--', color='green')
    
    ax.legend(loc='best')
    ax.set_xlabel('Date')
    ax.set_title(col)
    
plt.tight_layout()
fig.autofmt_xdate()


data/78df2c1f-e442-415d-a382-fa7925af0c4b/ce1baf3f-3736-46c7-9cc1-aa99684dcc42image.png



可视化TiDE的预测结果



从上面的图中,我们可以看到,TiDE在预测每个时间序列方面表现相当不错。


当然,评估性能的最好方式是计算误差指标,因此我们可以计算平均绝对误差(MAE)和均方误差(MSE)。


from darts.metrics import mae, mse

tide_mae = mae(test, pred_tide)
tide_mse = mse(test, pred_tide)

print(tide_mae, tide_mse)


这给我们提供了 MAE(平均绝对误差)为1.19,MSE(均方误差)为3.58。



为了保持文章的合理长度,我将不再详细介绍TSMixer的实现。(之后将更新细节在新的文章)


目前,TSMixer没有现成的可用实现,因此我们需要手动完成许多步骤。再次提醒,想了解更多细节的读者可以阅读我专门介绍TSMixer的文章。


现在,我们只报告TiDE和TSMixer在Etth1数据集上进行多元预测的表现,预测时段为96个时间步。



TiDE和TSMixer在Etth1数据集上进行多元预测时,96个epochs预测的性能对比



我们可以看到,TiDE取得了最佳的表现。


data/78df2c1f-e442-415d-a382-fa7925af0c4b/043adc0e-4c2a-47b4-bb3f-b0f4b653b70cimage.png


从上图可以看出,TiDE取得了最低的MAE和MSE,意味着它在性能上超越了TSMixer。


当然,这并不是一次全面的实验,因此并不意味着TiDE始终优于TSMixer。


尽管这两个模型都基于MLP架构,但可能TiDE在TSMixer的基础上做了一个增量性的改进。然而,你应该始终为你的特定数据集测试不同的模型,找出最适合的模型。



结论



TiDE代表时间序列密集编码器,它是一个基于MLP的模型,旨在进行长时间范围的多元预测。


它依赖于残差块单元,首先对协变量和历史数据进行编码。然后,它解码所学的表示,并生成预测。


由于它仅使用MLP,TiDE在训练时间上具有优势,并且已被证明在长期预测任务中仍能保持高性能。


当然,每个问题都是独特的,所以务必测试TiDE以及其他模型。


感谢阅读!希望你喜欢这篇文章,并且学到了一些新的东西!



原文链接


评论