%%capture
# !pip 安装 neuralforecast hyperopt
超参数优化
深度学习模型是时间序列预测的最先进技术。它们在最近的大规模竞赛中,如 M 系列,超越了统计和树基方法,并且在工业中被越来越广泛地采用。然而,它们的性能受到超参数选择的重大影响。选择最佳配置的过程称为超参数调优,这对于实现最佳性能至关重要。
超参数调优的主要步骤是:
- 定义训练集和验证集。
- 定义搜索空间。
- 使用搜索算法采样配置,训练模型,并在验证集上进行评估。
- 选择并存储最佳模型。
通过 Neuralforecast
,我们利用 Auto
模型自动化和简化了超参数调优过程。库中的每个模型都有一个 Auto
版本(例如,AutoNHITS
、AutoTFT
),可以在默认或用户定义的搜索空间上执行自动超参数选择。
Auto
模型可以与两个后端一起使用:Ray 的 Tune
库和 Optuna
,提供用户友好和简化的 API,并具备大部分功能。
在本教程中,我们将详细展示如何使用 Tune
和 Optuna
后端实例化和训练一个带有自定义搜索空间的 AutoNHITS
模型,安装并使用 HYPEROPT
搜索算法,并使用具有最佳超参数的模型进行预测。
您可以使用Google Colab通过GPU运行这些实验。
1. 安装 Neuralforecast
2. 加载数据
在这个示例中,我们将使用 AirPassengers
,这是一个流行的数据集,包含1949年至1960年间美国每月的航空乘客数量。加载数据,使用我们在 utils
方法中提供的所需格式。有关数据输入格式的更多详细信息,请参见 https://nixtla.github.io/neuralforecast/examples/data_format.html。
from neuralforecast.utils import AirPassengersDF
= AirPassengersDF
Y_df Y_df.head()
unique_id | ds | y | |
---|---|---|---|
0 | 1.0 | 1949-01-31 | 112.0 |
1 | 1.0 | 1949-02-28 | 118.0 |
2 | 1.0 | 1949-03-31 | 132.0 |
3 | 1.0 | 1949-04-30 | 129.0 |
4 | 1.0 | 1949-05-31 | 121.0 |
3. Ray的Tune
后端
首先,我们展示如何使用 Tune
后端。这个后端基于 Ray 的 Tune
库,这是一个可扩展的超参数调优框架。它是机器学习社区中的一个流行库,许多公司和研究实验室都在使用。如果您计划使用 Optuna
后端,可以跳过此部分。
3.a 定义超参数网格
每个Auto
模型包含一个在多个大规模数据集中广泛测试的默认搜索空间。搜索空间是通过字典指定的,其中键对应模型的超参数,而值是一个Tune
函数,用于指定超参数将如何被采样。例如,使用randint
以均匀方式采样整数,使用choice
从列表中采样值。
3.a.1 默认超参数网格
默认搜索空间字典可以通过 Auto
模型的 get_default_config
函数访问。如果您希望使用默认的参数配置,但想要在不更改其他默认值的情况下更改一个或多个超参数空间,这将非常有用。
要提取默认配置,您需要定义: * h
:预测范围。 * backend
:要使用的后端。 * n_series
:可选,唯一时间序列的数量,仅在多变量模型中需要。
在这个例子中,我们将使用 h=12
,并使用 ray
作为后端。我们将使用默认的超参数空间,但仅更改 random_seed
范围和 n_pool_kernel_size
。
from ray import tune
from neuralforecast.auto import AutoNHITS
= AutoNHITS.get_default_config(h = 12, backend="ray") # 提取默认的超参数设置
nhits_config "random_seed"] = tune.randint(1, 10) # 随机种子
nhits_config["n_pool_kernel_size"] = tune.choice([[2, 2, 2], [16, 8, 1]]) # MaxPool 的核大小 nhits_config[
3.a.2 自定义超参数网格
更一般地说,用户可以通过完全指定超参数搜索空间字典,定义完全自定义的搜索空间,针对特定的数据集和任务。
在以下示例中,我们正在优化 learning_rate
和两个特定于 NHITS
的超参数:n_pool_kernel_size
和 n_freq_downsample
。此外,我们还使用搜索空间来修改默认超参数,例如 max_steps
和 val_check_steps
。
= {
nhits_config "max_steps": 100, # SGD步骤数
"input_size": 24, # 输入窗口大小
"learning_rate": tune.loguniform(1e-5, 1e-1), # 初始学习率
"n_pool_kernel_size": tune.choice([[2, 2, 2], [16, 8, 1]]), # MaxPool 的核大小
"n_freq_downsample": tune.choice([[168, 24, 1], [24, 12, 1], [1, 1, 1]]), # 插值表达能力比率
"val_check_steps": 50, # 每50步进行一次验证计算
"random_seed": tune.randint(1, 10), # 随机种子
}
配置字典在不同模型之间无法互换,因为它们具有不同的超参数。请参阅 https://nixtla.github.io/neuralforecast/models.html 以获取每个模型超参数的完整列表。
3.b 实例化 Auto
模型
要实例化一个 Auto
模型,你需要定义:
h
: 预测的时间范围。loss
: 来自neuralforecast.losses.pytorch
的训练和验证损失。config
: 超参数搜索空间。如果为None
,则Auto
类将使用预定义的建议超参数空间。search_alg
: 搜索算法(来自tune.search
),默认是随机搜索。有关不同搜索算法选项的更多信息,请参阅 https://docs.ray.io/en/latest/tune/api_docs/suggestion.html。backend
: 要使用的后端,默认是ray
。如果是optuna
,则Auto
类将使用Optuna
后端。num_samples
: 探索的配置数量。
在这个例子中,我们将视野 h
设置为 12,使用 MAE
损失进行训练和验证,并使用 HYPEROPT
搜索算法。
from ray.tune.search.hyperopt import HyperOptSearch
from neuralforecast.losses.pytorch import MAE
from neuralforecast.auto import AutoNHITS
= AutoNHITS(h=12,
model =MAE(),
loss=nhits_config,
config=HyperOptSearch(),
search_alg='ray',
backend=10) num_samples
样本数 num_samples
是一个关键参数!通常较大的值会产生更好的结果,因为我们在搜索空间中探索更多配置,但这会增加训练时间。较大的搜索空间通常会需要更多的样本。作为一般规则,我们建议将 num_samples
设置为高于 20。在这个示例中,我们出于演示目的设置为 10。
3.c 训练模型并使用 Core
类进行预测
接下来,我们使用 Neuralforecast
类来训练 Auto
模型。在此步骤中,Auto
模型将自动执行超参数调优,训练多个具有不同超参数的模型,生成验证集上的预测,并对其进行评估。根据验证集上的误差选择最佳配置。只有最佳模型会被存储并在推理过程中使用。
from neuralforecast import NeuralForecast
使用 fit
方法的 val_size
参数来控制验证集的长度。在这种情况下,我们将验证集设置为预测范围的两倍。
%%capture
= NeuralForecast(models=[model], freq='M')
nf =Y_df, val_size=24) nf.fit(df
Global seed set to 8
超参数调优的结果可以在 Auto
模型的 results
属性中找到。使用 get_dataframe
方法可以将结果获取为 pandas 数据框。
= nf.models[0].results.get_dataframe()
results results.head()
loss | time_this_iter_s | done | timesteps_total | episodes_total | training_iteration | trial_id | experiment_id | date | timestamp | ... | config/input_size | config/learning_rate | config/loss | config/max_steps | config/n_freq_downsample | config/n_pool_kernel_size | config/random_seed | config/val_check_steps | config/valid_loss | logdir | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 21.173204 | 3.645993 | False | NaN | NaN | 2 | e20dbd9b | f62650f116914e18889bb96963c6b202 | 2023-10-03_11-19-14 | 1696346354 | ... | 24 | 0.000415 | MAE() | 100 | [168, 24, 1] | [16, 8, 1] | 7 | 50 | MAE() | /Users/cchallu/ray_results/_train_tune_2023-10... |
1 | 33.843426 | 3.756614 | False | NaN | NaN | 2 | 75e09199 | f62650f116914e18889bb96963c6b202 | 2023-10-03_11-19-22 | 1696346362 | ... | 24 | 0.000068 | MAE() | 100 | [24, 12, 1] | [16, 8, 1] | 4 | 50 | MAE() | /Users/cchallu/ray_results/_train_tune_2023-10... |
2 | 17.750280 | 8.573898 | False | NaN | NaN | 2 | 0dc5925a | f62650f116914e18889bb96963c6b202 | 2023-10-03_11-19-36 | 1696346376 | ... | 24 | 0.001615 | MAE() | 100 | [1, 1, 1] | [2, 2, 2] | 8 | 50 | MAE() | /Users/cchallu/ray_results/_train_tune_2023-10... |
3 | 24.573055 | 6.987517 | False | NaN | NaN | 2 | 352e03ff | f62650f116914e18889bb96963c6b202 | 2023-10-03_11-19-50 | 1696346390 | ... | 24 | 0.003405 | MAE() | 100 | [1, 1, 1] | [2, 2, 2] | 5 | 50 | MAE() | /Users/cchallu/ray_results/_train_tune_2023-10... |
4 | 474221.937500 | 4.912362 | False | NaN | NaN | 2 | 289bdd5e | f62650f116914e18889bb96963c6b202 | 2023-10-03_11-20-00 | 1696346400 | ... | 24 | 0.080117 | MAE() | 100 | [168, 24, 1] | [16, 8, 1] | 5 | 50 | MAE() | /Users/cchallu/ray_results/_train_tune_2023-10... |
5 rows × 29 columns
接下来,我们使用predict
方法根据最佳超参数预测接下来的12个月。
= nf.predict()
Y_hat_df = Y_hat_df.reset_index()
Y_hat_df Y_hat_df.head()
Predicting DataLoader 0: 100%|██████████| 1/1 [00:00<00:00, 113.97it/s]
unique_id | ds | AutoNHITS | |
---|---|---|---|
0 | 1.0 | 1961-01-31 | 442.346680 |
1 | 1.0 | 1961-02-28 | 439.409821 |
2 | 1.0 | 1961-03-31 | 477.709930 |
3 | 1.0 | 1961-04-30 | 503.884064 |
4 | 1.0 | 1961-05-31 | 521.344421 |
4. Optuna
后端
在本节中,我们将展示如何使用 Optuna
后端。Optuna
是一个轻量级且多功能的超参数优化平台。如果您打算使用 Tune
后端,可以跳过这一节。
4.a 定义超参数网格
每个 Auto
模型包含一个在多个大规模数据集上进行广泛测试的默认搜索空间。搜索空间是通过一个返回字典的函数来指定的,其中键对应于模型的超参数,值是一个 suggest
函数,用于指定超参数将如何被采样。例如,使用 suggest_int
来均匀采样整数,使用 suggest_categorical
来采样列表中的值。有关详细信息,请参见 https://optuna.readthedocs.io/en/stable/reference/generated/optuna.trial.Trial.html 。
4.a.1 默认超参数网格
默认搜索空间字典可以通过 Auto
模型的 get_default_config
函数访问。如果您希望使用默认参数配置,但想更改一个或多个超参数空间而不更改其他默认值,这将非常有用。
要提取默认配置,您需要定义: * h
:预测时间范围。 * backend
:要使用的后端。 * n_series
:可选,唯一时间序列的数量,仅在多变量模型中需要。
在这个例子中,我们将使用 h=12
,并将 optuna
作为后端。我们将使用默认超参数空间,但只更改 random_seed
范围和 n_pool_kernel_size
。
import optuna
# 使用此选项可禁用来自Optuna的训练打印信息。 optuna.logging.set_verbosity(optuna.logging.WARNING)
= AutoNHITS.get_default_config(h = 12, backend="optuna") # 提取默认超参数设置
nhits_default_config
def config_nhits(trial):
= {**nhits_default_config(trial)}
config
config.update({"random_seed": trial.suggest_int("random_seed", 1, 10),
"n_pool_kernel_size": trial.suggest_categorical("n_pool_kernel_size", [[2, 2, 2], [16, 8, 1]])
})return config
3.a.2 自定义超参数网格
更一般地说,用户可以通过完全指定超参数搜索空间函数来定义针对特定数据集和任务的完全自定义搜索空间。
在下面的示例中,我们正在优化 learning_rate
和两个 NHITS
特有的超参数:n_pool_kernel_size
和 n_freq_downsample
。此外,我们还使用搜索空间来修改默认超参数,例如 max_steps
和 val_check_steps
。
def config_nhits(trial):
return {
"max_steps": 100, # SGD步骤数
"input_size": 24, # 输入窗口大小
"learning_rate": trial.suggest_loguniform("learning_rate", 1e-5, 1e-1), # 初始学习率
"n_pool_kernel_size": trial.suggest_categorical("n_pool_kernel_size", [[2, 2, 2], [16, 8, 1]]), # MaxPool 的核大小
"n_freq_downsample": trial.suggest_categorical("n_freq_downsample", [[168, 24, 1], [24, 12, 1], [1, 1, 1]]), # 插值表达能力比率
"val_check_steps": 50, # 每50步进行一次验证计算
"random_seed": trial.suggest_int("random_seed", 1, 10), # 随机种子
}
4.b 实例化 Auto
模型
要实例化一个 Auto
模型,您需要定义:
h
:预测视野。loss
:来自neuralforecast.losses.pytorch
的训练和验证损失。config
:超参数搜索空间。如果为None
,Auto
类将使用预定义的建议超参数空间。search_alg
:搜索算法(来自optuna.samplers
),默认是 TPESampler(树结构的 Parzen 估计器)。有关不同搜索算法选项的更多信息,请参阅 https://optuna.readthedocs.io/en/stable/reference/samplers/index.html。backend
:要使用的后端,默认为ray
。如果为optuna
,Auto
类将使用Optuna
后端。num_samples
:探索的配置数量。
= AutoNHITS(h=12,
model =MAE(),
loss=config_nhits,
config=optuna.samplers.TPESampler(),
search_alg='optuna',
backend=10) num_samples
Tune
和 Optuna
的配置字典和搜索算法不能互换!请为每个后端使用适当类型的搜索算法和自定义配置字典。
4.c 训练模型并使用 Core
类进行预测
使用fit
方法的val_size
参数来控制验证集的长度。在这种情况下,我们将验证集设置为预测范围的两倍。
%%capture
= NeuralForecast(models=[model], freq='M')
nf =Y_df, val_size=24) nf.fit(df
Global seed set to 6
Global seed set to 6
Global seed set to 1
Global seed set to 1
Global seed set to 7
Global seed set to 4
Global seed set to 9
Global seed set to 8
Global seed set to 7
Global seed set to 7
Global seed set to 6
超参数调整的结果可在 Auto
模型的 results
属性中获取。使用 trials_dataframe
方法可以将结果以 pandas 数据框的形式获取。
= nf.models[0].results.trials_dataframe()
results ='user_attrs_ALL_PARAMS') results.drop(columns
number | value | datetime_start | datetime_complete | duration | params_learning_rate | params_n_freq_downsample | params_n_pool_kernel_size | params_random_seed | state | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 2.964735e+01 | 2023-10-23 19:13:30.251719 | 2023-10-23 19:13:33.007086 | 0 days 00:00:02.755367 | 0.000074 | [24, 12, 1] | [2, 2, 2] | 2 | COMPLETE |
1 | 1 | 2.790444e+03 | 2023-10-23 19:13:33.007483 | 2023-10-23 19:13:35.823089 | 0 days 00:00:02.815606 | 0.026500 | [24, 12, 1] | [2, 2, 2] | 10 | COMPLETE |
2 | 2 | 2.193000e+01 | 2023-10-23 19:13:35.823607 | 2023-10-23 19:13:38.599414 | 0 days 00:00:02.775807 | 0.000337 | [168, 24, 1] | [2, 2, 2] | 7 | COMPLETE |
3 | 3 | 1.147799e+08 | 2023-10-23 19:13:38.600149 | 2023-10-23 19:13:41.440307 | 0 days 00:00:02.840158 | 0.059274 | [1, 1, 1] | [16, 8, 1] | 5 | COMPLETE |
4 | 4 | 2.140740e+01 | 2023-10-23 19:13:41.440833 | 2023-10-23 19:13:44.184860 | 0 days 00:00:02.744027 | 0.000840 | [168, 24, 1] | [16, 8, 1] | 5 | COMPLETE |
5 | 5 | 1.606544e+01 | 2023-10-23 19:13:44.185291 | 2023-10-23 19:13:46.945672 | 0 days 00:00:02.760381 | 0.005477 | [1, 1, 1] | [16, 8, 1] | 8 | COMPLETE |
6 | 6 | 1.301640e+04 | 2023-10-23 19:13:46.946108 | 2023-10-23 19:13:49.805633 | 0 days 00:00:02.859525 | 0.056746 | [1, 1, 1] | [16, 8, 1] | 3 | COMPLETE |
7 | 7 | 4.972713e+01 | 2023-10-23 19:13:49.806278 | 2023-10-23 19:13:52.577180 | 0 days 00:00:02.770902 | 0.000021 | [24, 12, 1] | [2, 2, 2] | 9 | COMPLETE |
8 | 8 | 2.138879e+01 | 2023-10-23 19:13:52.577678 | 2023-10-23 19:13:55.372792 | 0 days 00:00:02.795114 | 0.007136 | [1, 1, 1] | [2, 2, 2] | 9 | COMPLETE |
9 | 9 | 2.094145e+01 | 2023-10-23 19:13:55.373149 | 2023-10-23 19:13:58.125058 | 0 days 00:00:02.751909 | 0.004655 | [1, 1, 1] | [2, 2, 2] | 6 | COMPLETE |
接下来,我们使用predict
方法,根据最佳超参数预测接下来的12个月。
= nf.predict()
Y_hat_df_optuna = Y_hat_df_optuna.reset_index()
Y_hat_df_optuna Y_hat_df_optuna.head()
Predicting DataLoader 0: 100%|██████████| 1/1 [00:00<00:00, 112.75it/s]
unique_id | ds | AutoNHITS | |
---|---|---|---|
0 | 1.0 | 1961-01-31 | 445.272858 |
1 | 1.0 | 1961-02-28 | 469.633423 |
2 | 1.0 | 1961-03-31 | 475.265289 |
3 | 1.0 | 1961-04-30 | 483.228516 |
4 | 1.0 | 1961-05-31 | 516.583496 |
5. 绘图
最后,我们将 AutoNHITS
模型生成的预测与两个后端进行比较。
import pandas as pd
import matplotlib.pyplot as plt
= plt.subplots(1, 1, figsize = (20, 7))
fig, ax = pd.concat([Y_df, Y_hat_df]).reset_index()
plot_df
'ds'], plot_df['y'], label='y')
plt.plot(plot_df['ds'], plot_df['AutoNHITS'], label='Ray')
plt.plot(plot_df['ds'], Y_hat_df_optuna['AutoNHITS'], label='Optuna')
plt.plot(Y_hat_df_optuna[
'AirPassengers Forecast', fontsize=22)
ax.set_title('Monthly Passengers', fontsize=20)
ax.set_ylabel('Timestamp [t]', fontsize=20)
ax.set_xlabel(={'size': 15})
ax.legend(prop ax.grid()
参考文献
- Cristian Challu, Kin G. Olivares, Boris N. Oreshkin, Federico Garza, Max Mergenthaler-Canseco, Artur Dubrawski (2021). NHITS:用于时间序列预测的神经层次插值。被AAAI 2023接受。
- James Bergstra, Remi Bardenet, Yoshua Bengio, 和 Balazs Kegl (2011). “超参数优化算法”。在:神经信息处理系统进展。链接:https://proceedings.neurips.cc/paper/2011/file/86e8f7ab32cfd12577bc2619bc635690-Paper.pdf
- Kirthevasan Kandasamy, Karun Raju Vysyaraju, Willie Neiswanger, Biswajit Paria, Christopher R. Collins, Jeff Schneider, Barnabas Poczos, Eric P. Xing (2019). “在没有研究生的情况下调整超参数:具有可扩展性和鲁棒性的龙飞凤舞贝叶斯优化”。机器学习研究杂志。链接:https://arxiv.org/abs/1903.06694
- Lisha Li, Kevin Jamieson, Giulia DeSalvo, Afshin Rostamizadeh, Ameet Talwalkar (2016). “Hyperband:一种基于赌博的超参数优化新方法”。机器学习研究杂志。链接:https://arxiv.org/abs/1603.06560
Give us a ⭐ on Github