原文:
towardsdatascience.com/n-hits-making-deep-learning-for-time-series-forecasting-more-efficient-d00956fc3e93
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9b205db30777252568b1271c0f355864.png
N-HiTS 的架构(图片来自Challu 和 Olivares 等人)。
2020 年,N-BEATS 是第一个在时间序列预测中优于统计和混合模型的深度学习模型。
两年后,在 2022 年,一个新的模型将 N-BEATS 从其宝座上拉了下来。Challu 和 Olivares 等人发布了深度学习模型 N-HiTS。他们解决了 N-BEATS 在更长期预测中的两个不足:
减少准确性
增加计算。
N-HiTS 代表NeuralHierarchical Interpolation forTimeSeries Forecasting。
该模型建立在 N-BEATS 及其神经网络基扩展理念之上。神经网络基扩展发生在分层堆叠的几个块中。
在这篇文章中,我将介绍 N-HiTS 背后的架构,特别是与 N-BEATS 的不同之处。但不必害怕,深入探讨将会易于理解。然而,仅仅理解 N-HiTS 的工作原理是不够的。因此,我将向您展示如何轻松地在 Python 中实现 N-HiTS 模型,并调整其超参数。
如果核心思想相同,N-BEATS 和 N-HiTS 之间有什么区别?
差异在于每个模型如何处理每个堆叠的输入和输出。N-HiTS 的主要思想是结合不同时间尺度的预测。
为了做到这一点,N-HiTS 应用了
输入的多速率数据采样。
输出的分层插值。
通过这个 N-HiTS 在更长的预测范围内实现了更好的准确性和更低的计算成本。
多速率数据采样迫使堆叠专门化于短期或长期效应。因此,这些堆叠学习相应组件变得更加容易。对长期行为的关注导致与 N-BEATS 相比,长期预测得到改善。
分层插值允许每个块在不同的时间尺度上进行预测。然后模型将预测插值以匹配每个块的时间尺度到最终的预测。重采样和插值减少了可学习的参数数量。这导致了一个更轻的模型,具有更短的训练时间。
既然我们已经知道了 N-HiTS 的不同之处,让我们看看其架构是如何包含这些变化的。
N-HiTS 是如何详细工作的?
N-HiTS 模型具有以下架构:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9b205db30777252568b1271c0f355864.png
N-HiTS 的架构(图片来自Challu 和 Olivares 等人)。
如我们所见,与 N-BEATS 相比有许多相似之处。
首先,N-HiTS 将时间序列分为回望期和预测期。其次,模型由多层堆栈和块组成,生成回溯和预测。在每个块中,多层感知器为回溯和预测生成基函数系数。回溯显示了块捕获的时间序列的部分。在我们将时间序列传递到块之前,我们移除前一个块的回溯。这样,每个块学习到不同的模式,因为我们只传递块与块之间的残差。模型通过所有块的预测之和生成最终预测。
关于相似之处,我将保持在这个细节水平。更多信息,请参阅我的 N-BEATS 文章。
N-BEATS – 第一个为时间序列预测工作的可解释深度学习模型
但让我们更深入地探讨差异:多速率数据采样和分层插值。
输入的多速率信号采样
N-HiTS 通过 MaxPool 层在块级别进行多速率采样。
MaxPool 层通过在选择的核大小内取最大值来平滑输入。因此,核大小决定了采样的速率。核大小越大,平滑效果越强。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4ca38f97f6bc647a5df5d33ac9eb8bc9.png
MaxPool 层的核大小越大,输入信号的平滑效果越强。因此,大的核大小强调长期效应。(图片由作者提供)
我们在堆栈级别定义 MaxPool 层的核大小。因此,同一堆栈内的每个块都有相同的核大小。
对于重采样,N-HiTS 使用自上而下的方法。第一堆栈通过较大的核大小关注长期效应。后堆栈通过较小的核大小关注短期效应。
输出的分层插值
N-HiTS 使用分层插值来减少每个堆栈的预测次数,即基数。较小的基数会导致长期预测的计算需求减少。
这是什么意思?
假设我们想要预测时间序列的下一个 24 小时。我们期望模型输出 24 个预测(每个小时一个)。如果我们想要预测接下来两周的小时数据,我们需要 336 个预测(14 * 24)。这说得通,对吧?
但这变成了问题所在。让我们以 N-BEATS 模型为例。最终的预测是每个堆栈部分预测的组合。因此,每个堆栈必须预测 336 个值,这计算起来很昂贵。N-BEATS 不是唯一一个在较长的预测范围内遭受同样问题的模型。其他深度学习方法,如 Transformer 或循环神经网络,也面临同样的问题。
N-HiTS 通过让每个堆栈在不同的时间尺度上进行预测来克服这一挑战。然后,N-HiTS 使用插值将每个堆栈的时间尺度与最终输出相匹配。
对于这一点,N-HiTS 使用了表达能力比的概念。这个比率决定了预测范围内的预测数量。小的表达能力比率意味着堆栈做出的预测较少。因此,堆栈具有较小的基数。例如,我们选择 1/2 的表达能力比率。这导致堆栈预测我们最终预测中每第二个值。
表达能力比率将输出与输入的重采样相关联。结合输入的重采样,每个堆栈因此以不同的频率工作。因此,每个堆栈可以专门处理以不同速率的时间序列。
N-HiTS 的作者建议靠近输入的堆栈应专注于长期效应。因此,这些堆栈应该具有较小的表达能力比率。例如,我们可以有三个堆栈。第一个堆栈专门处理周行为,第二个堆栈处理日行为,第三个堆栈处理小时行为。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3b51faac874a5026f7da52deff2ba9cf.png
每个堆栈在不同的时间尺度上进行预测。因此,每个堆栈有不同的基数。在这里,堆栈 1 的基数为 3,堆栈 2 的基数为 5,堆栈 3 的基数为 10。最终的预测是每个堆栈预测的总和。相比之下,在 N-BEATS 模型中,每个堆栈将具有相同的基数,即基数为 10。(图片由作者提供)
但表达能力的合理选择是什么?
这取决于时间序列。作者推荐两种选择。
在堆栈之间使用指数增长的表达能力比率,以减少参数数量同时处理广泛的频率
使用时间序列的已知周期,例如每日、每周等。
使用 N-HiTS 进行预测示例
现在我们知道了 N-HiTS 是如何工作的,让我们将模型应用于一个预测任务。
正如我在N-BEATS 文章中提到的,我们将预测德国未来两周的批发电力价格。我们使用“欧洲批发电力价格”数据,这些数据由Ember提供,并带有 CC-BY-4.0 许可。我们将使用 Nixtla 的neuralforecast库中的 N-HiTS 实现。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e9dfa71d7a88abb2767a20df2159684c.png
德国电力批发价格(图片由作者提供,数据由Ember提供)。
在不进行详细的数据探索的情况下,我们可以看到两个季节性成分:
每日:早上和晚上电价较高,因为这些时段的电力消耗通常更高。
每周:工作日的价格高于周末,因为通常工作日的电力消耗更高。
由于我在N-BEATS 文章中使用了相同的 dataset,我们可以重用所有用于数据准备、训练-测试分割、结果绘图和基准模型的代码。因此,我不会在这里展示这些代码片段。
在我们进入代码之前,请注意,我并不是试图得到尽可能准确的预测,而是展示我们如何应用 N-HiTS。
基准模型
但让我们从一个简单的模型开始作为我们的基准。
为什么你应该始终从基准模型开始
我将使用我在N-BEATS 文章中使用的相同的季节性朴素模型。因此,我不会深入细节,只展示结果。
使用训练集中最后一周的数据作为我们的预测结果,得到的 MAE 为 17.84。这已经相当不错了。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/aafd845e34304f35886c87319c1c46bb.png
季节性朴素基准模型的预测(图片由作者提供)。
训练 N-HiTS 模型
让我们训练我们的第一个 N-HiTS 模型。因为我们使用 Nixtla 的neuralforecast库,所以实现起来很简单。我们初始化我们的 N-HiTS 模型,定义我们的预测和回望期。在这种情况下,我使用一周的回望期。
然后,我们有几种定制选项。我们可以定制
通过选择堆叠和块的数量、MLP 层的尺寸、激活函数、MaxPooling 的核大小、池化类型等来选择模型。
通过选择损失函数、学习率、批量大小等进行的训练。
我们输入数据的缩放。
请参阅Nixtla 的文档以获取完整描述。
与 N-BEATS 模型相比,我们可以看到一些差异。我们有更多的参数来定制我们的模型。我们可以通过选择核大小和池化类型来自定义多速率数据采样。我们可以通过选择插值类型和表达能力比率来自定义分层插值。在代码片段中,我已经对一些超参数进行了调整。