时间序列预测是一个重要的科学和商业问题,因此最近通过使用基于深度学习 而不是经典方法的模型也涌现出诸多创新。ARIMA 等经典方法与新颖的深度学习方法之间的一个重要区别如下。
关于基于深度学习进行时间序列预测的论文: https://dl.acm.org/doi/abs/10.1145/3533382
《预测: 方法与实践》在线课本的中文版: https://otexts.com/fppcn/
通常,经典方法针对数据集中的每个时间序列单独拟合。这些通常被称为“单一”或“局部”方法。然而,当处理某些应用程序的大量时间序列时,在所有可用时间序列上训练一个“全局”模型是有益的,这使模型能够从许多不同的来源学习潜在的表示。
一些经典方法是点值的 (point-valued)(意思是每个时间步只输出一个值),并且通过最小化关于基本事实数据的 L2 或 L1 类型的损失来训练模型。然而,由于预测经常用于实际决策流程中,甚至在循环中有人的干预,让模型同时也提供预测的不确定性更加有益。这也称为“概率预测”,而不是“点预测”。这需要对可以采样的概率分布进行建模。
所以简而言之,我们希望训练全局概率模型,而不是训练局部点预测模型。深度学习非常适合这一点,因为神经网络可以从几个相关的时间序列中学习表示,并对数据的不确定性进行建模。
在概率设定中学习某些选定参数分布的未来参数很常见,例如高斯分布 (Gaussian) 或 Student-T,或者学习条件分位数函数 (conditional quantile function),或使用适应时间序列设置的共型预测 (Conformal Prediction) 框架。方法的选择不会影响到建模,因此通常可以将其视为另一个超参数。通过采用经验均值或中值,人们总是可以将概率模型转变为点预测模型。
正如人们所想象的那样,在对本来就连续的时间序列数据建模方面,研究人员提出了使用循环神经网络 (RNN) (如 LSTM 或 GRU) 或卷积网络 (CNN) 的模型,或利用最近兴起的基于 Transformer 的训练方法,都很自然地适合时间序列预测场景。
在这篇博文中,我们将利用传统 vanilla Transformer (参考 Vaswani 等 2017 年发表的论文) 进行单变量概率预测 (univariate probabilistic forecasting) 任务 (即预测每个时间序列的一维分布) 。 由于 Encoder-Decoder Transformer 很好地封装了几个归纳偏差,所以它成为了我们预测的自然选择。
传统 vanilla Transformer 论文链接: https://arxiv.org/abs/1706.03762
首先,使用 Encoder-Decoder 架构在推理时很有帮助。通常对于一些记录的数据,我们希望提前预知未来的一些预测步骤。可以认为这个过程类似于文本生成任务,即给定上下文,采样下一个词元 (token) 并将其传回解码器 (也称为“自回归生成”) 。类似地,我们也可以在给定某种分布类型的情况下,从中抽样以提供预测,直到我们期望的预测范围。这被称为贪婪采样 (Greedy Sampling)/搜索,此处 有一篇关于 NLP 场景预测的精彩博文。 https://hf.co/blog/how-to-generate
其次,Transformer 帮助我们训练可能包含成千上万个时间点的时间序列数据。由于注意力机制的时间和内存限制,一次性将 所有 时间序列的完整历史输入模型或许不太可行。因此,在为随机梯度下降 (SGD) 构建批次时,可以考虑适当的上下文窗口大小,并从训练数据中对该窗口和后续预测长度大小的窗口进行采样。可以将调整过大小的上下文窗口传递给编码器、预测窗口传递给 causal-masked 解码器。这样一来,解码器在学习下一个值时只能查看之前的时间步。这相当于人们训练用于机器翻译的 vanilla Transformer 的过程,称为“教师强制 (Teacher Forcing)”。
Transformers 相对于其他架构的另一个好处是,我们可以将缺失值 (这在时间序列场景中很常见) 作为编码器或解码器的额外掩蔽值 (mask),并且仍然可以在不诉诸于填充或插补的情况下进行训练。这相当于 Transformers 库中 BERT 和 GPT-2 等模型的 attention_mask
,在注意力矩阵 (attention matrix) 的计算中不包括填充词元。
由于传统 vanilla Transformer 的平方运算和内存要求,Transformer 架构的一个缺点是上下文和预测窗口的大小受到限制。关于这一点,可以参阅 Tay 等人于 2020 年发表的调研报告 。此外,由于 Transformer 是一种强大的架构,与 其他方法 相比,它可能会过拟合或更容易学习虚假相关性。
Tay 等 2020 年发表的调研报告地址: https://arxiv.org/abs/2009.06732
上述关于其他预测时间线方法的论文地址: https://openreview.net/pdf?id=D7YBmfX_VQy
🤗 Transformers 库带有一个普通的概率时间序列 Transformer 模型,简称为 Time Series Transformer。在这篇文章后面的内容中,我们将展示如何在自定义数据集上训练此类模型。
Time Series Transformer 模型文档: https://hf.co/docs/transformers/model_doc/time_series_transformer
首先,让我们安装必要的库: 🤗 Transformers、🤗 Datasets、🤗 Evaluate、🤗 Accelerate 和 GluonTS。
GluonTS 的 GitHub 仓库: https://github.com/awslabs/gluonts
正如我们将展示的那样,GluonTS 将用于转换数据以创建特征以及创建适当的训练、验证和测试批次。
加载数据集
在这篇博文中,我们将使用 Hugging Face Hub 上提供的“tourism_monthly”数据集。该数据集包含澳大利亚 366 个地区的每月旅游量。
“tourism_monthly” 数据集地址: https://hf.co/datasets/monash_tsf
此数据集是 Monash Time Series Forecasting 存储库的一部分,该存储库是来自多个领域的时间序列数据集的集合。它可以看作是时间序列预测的 GLUE 基准。
Monash Time Series Forecasting 存储库链接: https://forecastingdata.org/
可以看出,数据集包含 3 个片段: 训练、验证和测试。
每个示例都包含一些键,其中“start”和“target”是最重要的键。让我们看一下数据集中的第一个时间序列:
start
仅指示时间序列的开始 (作为日期时间) ,而 target
包含时间序列的实际值。
start
将有助于将时间相关的特征添加到时间序列值中,作为模型的额外输入 (例如“一年中的月份”) 。因为我们知道数据的频率是“每月”,所以知道例如第二个值的时间戳为“1979-02-01”,等等。
验证集包含与训练集相同的数据,只是“prediction_length”的时间更长。这使我们能够根据真实情况验证模型的预测。
与验证集相比,测试集还是一个“prediction_length”长数据 (或者与用于在多个滚动窗口上进行测试的训练集相比,“prediction_length”长数据的若干倍) 。
初始值与相应的训练示例完全相同:
但是,与训练示例相比,此示例具有“prediction_length=24”附加值。让我们验证一下。
让我们拆分数据:
将 start
更新为 pd.Period
我们要做的第一件事是使用数据的 freq
将每个时间序列的 start
特征转换为 pandas Period
索引:
我们现在使用 datasets
的 set_transform
功能来执行此操作:
set_transform
文档地址: https://hf.co/docs/datasets/v2.7.0/en/package_reference/main_classes
定义模型
接下来,让我们实例化一个模型。该模型将从头开始训练,因此我们不会在这里使用from_pretrained
方法,而是从 config
中随机初始化模型。
我们为模型指定了几个附加参数:
prediction_length
(在我们的例子中,24
个月) : 这是 Transformer 的解码器将学习预测的范围;
context_length
: 如果未指定 context_length
,模型会将 context_length
(编码器的输入) 设置为等于 prediction_length
;
给定频率的“滞后”: 这些指定我们“回头看”的程度,作为附加功能添加。例如对于“每日”频率,我们可能会考虑回顾“[1, 2, 7, 30, ...]”,或者换句话说,回顾 1, 2, ... 天,而对于“分钟”数据,我们可能会考虑 [1, 30, 60, 60*24, ...]
等;
时间特征的数量: 在我们的例子中,这将是“2”,因为我们将添加“MonthOfYear”和“Age”特征;
静态分类特征的数量: 在我们的例子中,这将只是“1”,因为我们将添加一个“时间序列 ID”特征;
基数: 每个静态分类特征的值的数量,作为一个列表,对于我们的案例来说将是“[366]”,因为我们有 366 个不同的时间序列
嵌入维度: 每个静态分类特征的嵌入维度,作为列表,例如“[3]”意味着模型将为每个“366”时间序列 (区域) 学习大小为“3”的嵌入向量.
让我们使用 GluonTS 为给定频率 (“每月”) 提供的默认滞后:
这意味着我们将回顾每个时间步长达 37 个月的时间,作为附加功能。
我们还检查 GluonTS 为我们提供的默认时间功能:
在这种情况下,只有一个特征,即“一年中的月份”。这意味着对于每个时间步长,我们将添加月份作为标量值 (例如,如果时间戳为“一月”,则为“1”;如果时间戳为“二月”,则为“2”,等等) 。
我们现在准备好定义模型需要的所有内容了:
请注意,与 🤗 Transformers 库中的其他模型类似,TimeSeriesTransformerModel
对应于没有任何顶部前置头的编码器-解码器 Transformer,而 TimeSeriesTransformerForPrediction
对应于顶部有一个前置头 (distribution head) 的 TimeSeriesTransformerModel
。默认情况下,该模型使用 Student-t 分布 (但这是可配置的):
上述两个模型的文档链接: https://hf.co/docs/transformers/model_doc/time_series_transformer
这是与用于 NLP 的 Transformers 的一个重要区别,其中头部通常由一个固定的分类分布组成,实现为 nn.Linear
层。
接下来,我们定义数据的转换,特别是时间特征的创建 (基于数据集或通用数据集) 。
同样,我们将为此使用 GluonTS 库。我们定义了一个“转换链” (有点类似于图像的“torchvision.transforms.Compose”) 。它允许我们将多个转换组合到一个流水线中。
下面的转换带有注释,以解释它们的作用。在高层次上,我们将迭代数据集的各个时间序列并添加/删除字段或特征:
InstanceSplitter
对于训练、验证、测试步骤,接下来我们创建一个“InstanceSplitter”,用于从数据集中对窗口进行采样 (因为由于时间和内存限制,我们无法将整个历史值传递给 Transformer)。
实例拆分器从数据中随机采样大小为“context_length”和后续大小为“prediction_length”的窗口,并将“past_”或“future_”键附加到各个窗口的任何时间键。这确保了 values
将被拆分为 past_values
和后续的 future_values
键,它们将分别用作编码器和解码器的输入。time_series_fields
参数中的任何键都会发生同样的情况:
创建 PyTorch 数据加载器
接下来,需要创建 PyTorch DataLoaders。它允许我们批量处理成对的 (输入, 输出),即 (past_values
, future_values
)。
可以看出,我们没有将 input_ids
和 attention_mask
提供给编码器 (NLP 模型就是这种情况) ,而是提供 past_values
,以及 past_observed_mask、
past_time_features
、static_categorical_features
和static_real_features
。
解码器输入包括“future_values”、“future_observed_mask”和“future_time_features”。 future_values
可以看作是 NLP 中的 decoder_input_ids
的等价物。 我们可以参考 Time Series Transformer 文档 以获得对它们中每一个的详细解释。
让我们对刚刚创建的批次执行一次前向传递:
目前,该模型返回了损失值。这是由于解码器会自动将“future_values”向右移动一个位置以获得标签。这允许计算预测值和标签之间的损失。
另请注意,解码器使用 Causal Mask 来避免预测未来,因为它需要预测的值在“future_values”张量中。
是时候训练模型了!我们将使用标准的 PyTorch 训练循环。
我们将在这里使用 🤗 Accelerate 库,它会自动将模型、优化器和数据加载器放置在适当的“设备”上。
🤗 Accelerate 文档地址: https://hf.co/docs/accelerate/index
在推理时,建议使用 generate()
方法进行自回归生成,类似于 NLP 模型。
预测涉及从测试实例采样器获取数据,该采样器将从数据集中每个时间序列的最后一个“context_length”大小的值窗口中采样,并将其传递给模型。请注意,我们把提前已知的“future_time_features”传递给解码器。
该模型将从预测分布中自回归采样一定数量的值,并将它们传回解码器以返回预测输出:
该模型输出一个结构的张量 (batch_size
, number of samples
, prediction length
)。
在这种情况下,我们将在接下来的 24 个月内获得 100 个可能的值 (对于大小为 64 的批次中的每个示例):
我们将垂直堆叠它们,以获得测试数据集中所有时间序列的预测:
我们可以根据测试集中存在的样本值,根据真实情况评估生成的预测。这里我们使用数据集中的每个时间序列的 MASE 和 sMAPE 指标来评估:
MASE 文档地址: https://hf.co/spaces/evaluate-metric/mase
sMAPE 文档地址: https://hf.co/spaces/evaluate-metric/smape
我们还可以绘制数据集中每个时间序列的单独指标,并观察到少数时间序列对最终测试指标的影响很大:
为了根据基本事实测试数据绘制任何时间序列的预测,我们定义了以下辅助绘图函数:
例如:
plot(334)
我们如何与其他模型进行比较? Monash Time Series Repository 有一个测试集 MASE 指标的比较表,我们可以将其添加到:
请注意,使用我们的模型,我们击败了所有已知的其他模型 (另请参见相应 论文 中的表 2) ,并且我们没有做任何超参数优化。我们仅仅花了 40 个完整训练调参周期来训练 Transformer。
上文对于此数据集的预测方法论文: https://openreview.net/pdf?id=wEc1mgAjU-
当然,我们需要小心,因为似乎 “你需要的就是 XGBoost” 。我们只是很好奇,想看看神经网络能带我们走多远,以及 Transformer 是否会在这个领域发挥作用。这个特定的数据集似乎表明它绝对值得探索。
得出“你需要的就是 XGBoost”结论的论文地址: https://www.sciencedirect.com/science/article/pii/S0169207021001679
我们鼓励读者尝试我们的 Jupyter Notebook 和来自 Hugging Face Hub 的其他时间序列数据集,并替换适当的频率和预测长度参数。对于您的数据集,需要将它们转换为 GluonTS 的惯用格式,在他们的 文档 里有非常清晰的说明。我们还准备了一个示例 Notebook,向您展示如何将数据集转换为 🤗 数据集格式。
Time Series Transformers Notebook: https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/time-series-transformers.ipynb
Hub 中的 Monash Time Series 数据集: https://hf.co/datasets/monash_tsf
GluonTS 阐述数据集格式的文档: https://ts.gluon.ai/stable/tutorials/forecasting/extended_tutorial.html
演示数据集格式转换的 Notebook: https://github.com/huggingface/notebooks/blob/main/examples/time_series_datasets.ipynb
正如时间序列研究人员所知,人们对“将基于 Transformer 的模型应用于时间序列”问题很感兴趣。传统 vanilla Transformer 只是众多基于注意力 (Attention) 的模型之一,因此需要向库中添加更多模型。
目前没有什么能妨碍我们继续探索对多变量时间序列 (multivariate time series) 进行建模,但是为此需要使用多变量分布头 (multivariate distribution head) 来实例化模型。目前已经支持了对角独立分布 (diagonal independent distributions),后续会增加其他多元分布支持。请继续关注未来的博客文章以及其中的教程。
路线图上的另一件事是时间序列分类。这需要将带有分类头的时间序列模型添加到库中,例如用于异常检测这类任务。
当前的模型会假设日期时间和时间序列值都存在,但在现实中这可能不能完全满足。例如 WOODS 给出的神经科学数据集。因此,需要对当前模型进行泛化,使某些输入在整个流水线中可选。
WOODS 主页: https://woods-benchmarks.github.io/
最后,NLP/CV 领域从大型预训练模型 中获益匪浅,但据我们所知,时间序列领域并非如此。基于 Transformer 的模型似乎是这一研究方向的必然之选,我们迫不及待地想看看研究人员和从业者会发现哪些突破!
大型预训练模型论文地址: https://arxiv.org/abs/1810.04805
英文地址:https://huggingface.co/blog/time-series-transformers
英文原文: Probabilistic Time Series Forecasting with 🤗 Transformers
译者、排版: zhongdongy (阿东)