向NeuralForecast添加模型
关于如何向NeuralForecast添加新模型的教程
本指南假设您对NeuralForecast有较深入的了解。
我们强烈建议您首先阅读“入门指南”和“NeuralForecast地图”教程!
此外,请参考 贡献指南 了解如何为NeuralForecast贡献代码的基本信息。
介绍
本教程面向希望向NeuralForecast库添加新模型的贡献者。该库现有的模块处理深度学习模型的优化、训练、选择和评估。core类简化了针对任何数据集构建整个管道的过程,适用于工业和学术界,提供了诸如fit和predict等用户友好的方法。
向NeuralForecast添加新模型比从头开始构建新的PyTorch模型更简单。您只需编写forward方法。
它具有以下额外优势:
- NeuralForecast中现有的模块已经实现了深度学习模型训练和评估的基本方面。
- 与PyTorch-Lightning和Tune库集成以实现高效优化和分布式计算。
BaseModel类提供了通用的优化组件,如早期终止和学习率调度器。- 在Github上定期进行自动性能测试,以确保质量标准。
- 用户可以轻松比较新模型与现有模型的性能和计算。
- 为用户和贡献者提供了接触大量社区的机会。
示例:简化的MLP模型
我们将通过一个示例来介绍如何添加当前MLP模型的简化版本,该版本不包含外生变量。
在给定的时间戳\(t\),MLP模型将利用最后\(L\)个历史值\(Y_{t-L:t}\)作为输入,预测单变量目标时间的下一个\(h\)个值\(Y_{t+1:t+h}\)。下图展示了模型的示意图。

0. 准备工作
请按照我们关于贡献的教程来设置您的开发环境。
以下是最重要步骤的简要列表:
- 创建
neuralforecast库的一个分支。 - 将分支克隆到您的计算机。
- 设置一个包含
neuralforecast库、核心依赖项和nbdev包的环境,以便在交互式笔记本中编写您的模型。
1. 继承基类(BaseWindows)
该库包含 三种 类型的基础模型:BaseWindows、BaseRecurrent 和 BaseMultivariate。在本教程中,我们将重点关注 BaseWindows 类,这是库中最常见的模型类型,其对应的模型包括 NBEATS、NHITS、TFT 和 PatchTST。这三种类型之间的主要区别在于 forward 方法的采样过程和输入批次,这决定了模型的类型。
如果您想添加 BaseRecurrent 或 BaseMultivariate 模型,请在我们的 GitHub 上提一个issue。
a. 采样过程
在训练期间,基类从 TimeSeriesLoader 模块接收数据集的时间序列样本。BaseWindows 模型将从随机时间戳开始,采样大小为 input_size+h 的独立窗口。
b. BaseWindows 的超参数
熟悉基类中指定的超参数,包括 h(预测期)、input_size 和优化超参数如 learning_rate、max_steps 等。以下列表呈现了与窗口采样相关的超参数:
h(h):要预测的未来值的数量。input_size(L):作为模型输入使用的历史值的数量。batch_size(bs):训练期间加载器采样的时间序列数量。valid_batch_size(v_bs):推理(验证和测试)期间加载器采样的时间序列数量。windows_batch_size(w_bs):在训练期间(来源于先前的时间序列)采样的独立窗口数量,用于形成批次。inference_windows_batch_size(i_bs):在推理期间采样的独立窗口数量,用于形成每个批次。用于控制 GPU 内存。
c. 输入和输出批次形状
forward 方法接收一个包含以下键的字典数据批次:
insample_y:时间序列的历史值。insample_mask:指示时间序列可用值的掩码(可用时为1,缺失时为0)。futr_exog:未来的外生协变量(如有)。hist_exog:历史外生协变量(如有)。stat_exog:静态外生协变量(如有)。
以下表格呈现了每个张量的形状:
张量 |
BaseWindows |
|---|---|
insample_y |
(w_bs, L) |
insample_mask |
(w_bs, L) |
futr_exog |
(w_bs, L+h, n_f) |
hist_exog |
(w_bs, L, n_h) |
stat_exog |
(w_bs,n_s) |
forward 函数应返回一个包含每个窗口下一个 h 个时间戳预测的单一张量。使用 loss 类的属性自动将输出解析为正确的形状(参见下面的示例)。
由于我们使用的是 nbdev,您可以轻松在代码中添加打印语句,并在训练期间查看张量的形状。
d. BaseWindows 的方法
BaseWindows 类包含针对所有基于窗口模型的几个常见方法,从而简化新模型的开发,防止代码重复。该类最重要的方法有:
_create_windows:将来自TimeSeriesLoader的时间序列解析为大小为input_size+h的独立窗口。_normalization:基于scaler类型对每个窗口进行归一化。_inv_normalization:对预测结果进行反归一化。training_step:模型的训练步骤,在训练期间由 PyTorch-Lightning 的Trainer类调用(fit方法)。validation_step:模型的验证步骤,在验证期间由 PyTorch-Lightning 的Trainer类调用。predict_step:模型的预测步骤,在推理期间由 PyTorch-Lightning 的Trainer类调用(predict方法)。
2. 创建模型文件和类
在熟悉了 BaseWindows 类的基础知识之后,下一步是创建您的特定模型。
主要步骤如下:
- 在
nbs文件夹中创建文件(https://github.com/Nixtla/neuralforecast/tree/main/nbs)。文件名应为models.YOUR_MODEL_NAME.ipynb。 - 添加
nbdev文件的头部。 - 在文件中导入库。
- 定义
__init__方法,包含模型的继承和特定超参数,并实例化架构。 - 定义
forward方法,它接收输入批次字典并返回预测结果。
a. 模型类
首先,在nbdev文件的顶部添加以下两个单元格。
#| default_exp models.mlp将mlp更改为你的模型名称,使用小写字母和下划线。稍后当你运行nbdev_export时,它将在neuralforecast/models/目录中创建一个YOUR_MODEL.py脚本。
%load_ext autoreload
%autoreload 2接下来,添加模型的依赖项。
#| export
from typing import Optional
import torch
import torch.nn as nn
from neuralforecast.losses.pytorch import MAE
from neuralforecast.common._base_windows import BaseWindows不要忘记在这个单元格中添加#| export标签。
接下来,创建带有 init 和 forward 方法的类。以下示例展示了简化的 MLP 模型的例子。我们将在代码后解释重要细节。
#| export
class MLP(BaseWindows): # <<---- 继承自 BaseWindows
def __init__(self,
# 继承的超参数没有默认值
h,
input_size,
# 模型特定的超参数
num_layers = 2,
hidden_size = 1024,
# 继承的超参数有默认值
exclude_insample_y = False,
loss = MAE(),
valid_loss = None,
max_steps: int = 1000,
learning_rate: float = 1e-3,
num_lr_decays: int = -1,
early_stop_patience_steps: int =-1,
val_check_steps: int = 100,
batch_size: int = 32,
valid_batch_size: Optional[int] = None,
windows_batch_size = 1024,
inference_windows_batch_size = -1,
step_size: int = 1,
scaler_type: str = 'identity',
random_seed: int = 1,
num_workers_loader: int = 0,
drop_last_loader: bool = False,
**trainer_kwargs):
# 继承 BaseWindows 类
super(MLP, self).__init__(h=h,
input_size=input_size,
..., # <<--- 添加所有继承的超参数
random_seed=random_seed,
**trainer_kwargs)
# 架构
self.num_layers = num_layers
self.hidden_size = hidden_size
# 多层感知器
layers = [nn.Linear(in_features=input_size, out_features=hidden_size)]
layers += [nn.ReLU()]
for i in range(num_layers - 1):
layers += [nn.Linear(in_features=hidden_size, out_features=hidden_size)]
layers += [nn.ReLU()]
self.mlp = nn.ModuleList(layers)
# 带有依赖于损失的维度的适配器
self.out = nn.Linear(in_features=hidden_size,
out_features=h * self.loss.outputsize_multiplier) ## <<--- 使用 outputsize_multiplier 调整输出大小
def forward(self, windows_batch): # <<--- 接收 windows_batch 字典
# 解析 windows_batch
insample_y = windows_batch['insample_y'].clone()
# MLP
y_pred = self.mlp(insample_y)
# 重塑并映射到损失域
y_pred = y_pred.reshape(batch_size, self.h, self.loss.outputsize_multiplier)
y_pred = self.loss.domain_map(y_pred)
return y_pred- 不要忘记在每个单元格上添加
#| export标签。 - 较大的架构,如变换器,可能需要通过使用中间函数来拆分
forward。
重要注意事项
基类有许多超参数,模型必须为所有超参数提供默认值(h和input_size除外)。如果您不确定使用什么默认值,我们建议您从现有模型中复制大多数优化和采样超参数的默认值。您可以随时更改默认值。
forward步骤末尾的reshape方法用于调整输出形状。loss类包含一个outputsize_multiplier属性,用于根据loss自动调整预测的输出大小。例如,对于多分位数损失(MQLoss),模型需要为每个时间段输出每个分位数。
最后,请始终在forward的末尾包含y_pred = self.loss.domain_map(y_pred)。这对于将输出映射到损失函数的域(和形状)是必要的。例如,如果损失函数是MAE,那么它将形状为(batch_size, h, 1)的输出映射到(batch_size, h)。
b. 测试和文档
nbdev允许在开发过程中测试和记录模型。它允许用户在笔记本内迭代开发,在相同环境中测试代码。请参考现有模型,例如完整的MLP模型 here。这些文件已经包含了在开发过程中使用的测试、文档和使用示例。
c. 使用nbdev将新模型导出到库中
根据贡献指南,下一步是将开发笔记本中的新模型导出到neuralforecast文件夹中的实际脚本。
要导出模型,请在终端中运行nbdev_export。您应该会在neuralforecast/models/文件夹中看到一个包含您模型的新文件。
3. 核心类和附加文件
最后,将模型添加到 core 类和附加文件中:
手动将模型添加到以下 初始化文件。
使用 这里的
nbdev文件 将模型添加到core类中:- 将模型添加到初始模型列表中:
from neuralforecast.models import ( GRU, LSTM, RNN, TCN, DilatedRNN, MLP, NHITS, NBEATS, NBEATSx, TFT, VanillaTransformer, Informer, Autoformer, FEDformer, StemGNN, PatchTST )- 将模型添加到
MODEL_FILENAME_DICT字典中(用于save和load函数)。
4. 将模型添加到文档中
将模型添加到必要的文档页面中非常重要,以便每个人都能找到文档:
5. 上传到 GitHub
祝贺你!该模型已经准备好,可以按照上述步骤在库中使用。
请按照我们的贡献指南的最后步骤将模型上传到 GitHub:这里。
其中一位维护者会审查 PR,如有必要会请求更改,并将其合并到库中。
快速检查清单
Give us a ⭐ on Github