长周期预测具有挑战性,因为预测结果具有波动性且存在计算复杂度。为了解决这个问题,我们创建了 NHITS 模型,并将代码发布到 NeuralForecast 库中。NHITS 通过分层插值和多速率输入处理,使其部分输出专注于时间序列的不同频率。我们使用 Student's t-分布 对目标时间序列进行建模。NHITS 将为每个时间戳输出分布参数。

在本 Notebook 中,我们将展示如何在 ETTm2 基准数据集上使用 NHITS 进行概率预测。该数据集包含来自 2 个站点的 2 个变压器的数据点,包括负荷、油温。

我们将向您展示如何加载数据、训练模型以及执行自动超参数调优,以实现 SoTA(最先进)性能,其性能甚至超越最新的 Transformer 架构,而计算成本仅为其一小部分(快 50 倍)。

您可以使用 Google Colab 的 GPU 运行这些实验。

1. 库

!pip install neuralforecast datasetsforecast

2. 加载 ETTm2 数据

LongHorizon 类将自动下载完整的 ETTm2 数据集并进行处理。

它返回三个 Dataframe:Y_df 包含目标变量的值,X_df 包含外生日历特征,S_df 包含每个时间序列的静态特征(ETTm2 没有)。在此示例中,我们将仅使用 Y_df

如果您想使用自己的数据,只需替换 Y_df。请确保使用长格式,并且结构与我们的数据集相似。

import pandas as pd
from datasetsforecast.long_horizon import LongHorizon
# Change this to your own data to try the model
Y_df, _, _ = LongHorizon.load(directory='./', group='ETTm2')
Y_df['ds'] = pd.to_datetime(Y_df['ds'])

# For this excercise we are going to take 960 timestamps as validation and test
n_time = len(Y_df.ds.unique())
val_size = 96*10
test_size = 96*10

Y_df.groupby('unique_id').head(2)
unique_iddsy
0HUFL2016-07-01 00:00:00-0.041413
1HUFL2016-07-01 00:15:00-0.185467
57600HULL2016-07-01 00:00:000.040104
57601HULL2016-07-01 00:15:00-0.214450
115200LUFL2016-07-01 00:00:000.695804
115201LUFL2016-07-01 00:15:000.434685
172800LULL2016-07-01 00:00:000.434430
172801LULL2016-07-01 00:15:000.428168
230400MUFL2016-07-01 00:00:00-0.599211
230401MUFL2016-07-01 00:15:00-0.658068
288000MULL2016-07-01 00:00:00-0.393536
288001MULL2016-07-01 00:15:00-0.659338
345600OT2016-07-01 00:00:001.018032
345601OT2016-07-01 00:15:000.980124

重要提示

DataFrames 必须包含所有 ['unique_id', 'ds', 'y'] 列。确保 y 列没有缺失值或非数值。

接下来,绘制 HUFL 变量,并标记验证集和训练集的分割点。

import matplotlib.pyplot as plt
from utilsforecast.plotting import plot_series
u_id = 'HUFL'
fig = plot_series(Y_df, ids=[u_id])
ax = fig.axes[0]

x_plot = pd.to_datetime(Y_df[Y_df.unique_id==u_id].ds)
y_plot = Y_df[Y_df.unique_id==u_id].y.values
x_val = x_plot[n_time - val_size - test_size]
x_test = x_plot[n_time - test_size]

ax.axvline(x_val, color='black', linestyle='-.')
ax.axvline(x_test, color='black', linestyle='-.')
ax.text(x_val, 5, '  Validation', fontsize=12)
ax.text(x_test, 3, '  Test', fontsize=12)
fig

3. 超参数选择和预测

AutoNHITS 类将使用 Tune 库自动执行超参数调优,探索用户定义或默认的搜索空间。模型根据在验证集上的误差进行选择,然后存储最佳模型并在推理时使用。

AutoNHITS.default_config 属性包含一个建议的超参数空间。在这里,我们根据论文中的超参数指定了不同的搜索空间。请注意,*1000 次随机梯度步长*足以实现 SoTA 性能。您可以随意调整此空间。

import logging

import torch
from neuralforecast.auto import AutoNHITS
from neuralforecast.core import NeuralForecast
from neuralforecast.losses.pytorch import DistributionLoss
from ray import tune
logging.getLogger("pytorch_lightning").setLevel(logging.WARNING)
torch.set_float32_matmul_precision('high')
horizon = 96 # 24hrs = 4 * 15 min.

# Use your own config or AutoNHITS.default_config
nhits_config = {
       "learning_rate": tune.choice([1e-3]),                                     # Initial Learning rate
       "max_steps": tune.choice([1000]),                                         # Number of SGD steps
       "input_size": tune.choice([5 * horizon]),                                 # input_size = multiplier * horizon
       "batch_size": tune.choice([7]),                                           # Number of series in windows
       "windows_batch_size": tune.choice([256]),                                 # Number of windows in batch
       "n_pool_kernel_size": tune.choice([[2, 2, 2], [16, 8, 1]]),               # MaxPool's Kernelsize
       "n_freq_downsample": tune.choice([[168, 24, 1], [24, 12, 1], [1, 1, 1]]), # Interpolation expressivity ratios
       "activation": tune.choice(['ReLU']),                                      # Type of non-linear activation
       "n_blocks":  tune.choice([[1, 1, 1]]),                                    # Blocks per each 3 stacks
       "mlp_units":  tune.choice([[[512, 512], [512, 512], [512, 512]]]),        # 2 512-Layers per block for each stack
       "interpolation_mode": tune.choice(['linear']),                            # Type of multi-step interpolation
       "random_seed": tune.randint(1, 10),
       "scaler_type": tune.choice(['robust']),
       "val_check_steps": tune.choice([100])
    }

提示

有关不同空间选项(如列表和连续区间)的更多信息,请参阅 https://docs.rayai.org.cn/en/latest/tune/index.html

要实例化 AutoNHITS,您需要定义

  • h:预测范围
  • loss:训练损失。使用 DistributionLoss 生成概率预测。
  • config:超参数搜索空间。如果为 NoneAutoNHITS 类将使用预定义的建议超参数空间。
  • num_samples:探索的配置数量。
models = [AutoNHITS(h=horizon,
                    loss=DistributionLoss(distribution='StudentT', level=[80, 90]), 
                    config=nhits_config,
                    num_samples=5)]

通过实例化 NeuralForecast 对象并使用以下必需参数来拟合模型

  • models:模型列表。

  • freq:表示数据频率的字符串。(请参阅 panda 可用的频率。)

# Fit and predict
nf = NeuralForecast(models=models, freq='15min')

cross_validation 方法允许您模拟多个历史预测,通过用 fitpredict 方法替换 for 循环,极大地简化了管道。

对于时间序列数据,交叉验证是通过在历史数据上定义一个滑动窗口并预测其后续周期来完成的。这种形式的交叉验证使我们能够在更广泛的时间实例范围内更好地估计模型的预测能力,同时也按照模型的需要保持训练集中的数据是连续的。

cross_validation 方法将使用验证集进行超参数选择,然后生成测试集的预测结果。

Y_hat_df = nf.cross_validation(df=Y_df, val_size=val_size,
                               test_size=test_size, n_windows=None)

4. 可视化

最后,我们将预测结果与 Y_df 数据集合并并绘制预测图。

Y_hat_df
unique_iddscutoffAutoNHITSAutoNHITS-medianAutoNHITS-lo-90AutoNHITS-lo-80AutoNHITS-hi-80AutoNHITS-hi-90y
0HUFL2018-02-11 00:00:002018-02-10 23:45:00-0.922304-0.914175-1.217987-1.138274-0.708157-0.617799-0.849571
1HUFL2018-02-11 00:15:002018-02-10 23:45:00-0.954299-0.957198-1.403932-1.263984-0.618467-0.442688-1.049700
2HUFL2018-02-11 00:30:002018-02-10 23:45:00-0.987538-0.972558-1.512509-1.310191-0.621673-0.444359-1.185730
3HUFL2018-02-11 00:45:002018-02-10 23:45:00-1.067760-1.063188-1.614276-1.475302-0.665729-0.521775-1.329785
4HUFL2018-02-11 01:00:002018-02-10 23:45:00-1.001276-1.001494-1.508795-1.390156-0.629212-0.470608-1.369715
581275OT2018-02-20 22:45:002018-02-19 23:45:00-1.200041-1.200862-1.591271-1.490571-0.907190-0.779424-1.581325
581276OT2018-02-20 23:00:002018-02-19 23:45:00-1.237206-1.225333-1.618691-1.518204-0.960075-0.838512-1.581325
581277OT2018-02-20 23:15:002018-02-19 23:45:00-1.232434-1.229675-1.591164-1.481251-0.989993-0.870404-1.581325
581278OT2018-02-20 23:30:002018-02-19 23:45:00-1.259237-1.258848-1.659239-1.536979-0.985581-0.822370-1.562328
581279OT2018-02-20 23:45:002018-02-19 23:45:00-1.247161-1.251899-1.631909-1.520350-0.949529-0.832602-1.562328
Y_hat_df = Y_hat_df.reset_index(drop=True)
Y_hat_df = Y_hat_df[(Y_hat_df['unique_id']=='OT') & (Y_hat_df['cutoff']=='2018-02-11 12:00:00')]
Y_hat_df = Y_hat_df.drop(columns=['y','cutoff'])
plot_df = Y_df.merge(Y_hat_df, on=['unique_id','ds'], how='outer').tail(96*10+50+96*4).head(96*2+96*4)
plot_series(forecasts_df=plot_df.drop(columns='AutoNHITS').rename(columns={'AutoNHITS-median': 'AutoNHITS'}), level=[90])

参考文献

Cristian Challu, Kin G. Olivares, Boris N. Oreshkin, Federico Garza, Max Mergenthaler-Canseco, Artur Dubrawski (2021). NHITS: Neural Hierarchical Interpolation for Time Series Forecasting. Accepted at AAAI 2023.