工具系列:时间序列预测工具Dart介绍_TiDE时间序列密集编码器

时间序列深度编码器

本笔记本介绍了如何使用Darts的TiDEModel,并将其与NHiTSModel进行了基准测试。

TiDE(时间序列密集编码器)是一种纯深度学习编码器-解码器架构。它的特殊之处在于时间解码器可以帮助减轻异常样本对预测的影响(论文中的图4)。

请参阅原始论文和模型描述:http://arxiv.org/abs/2304.08424

# 导入fix_pythonpath_if_working_locally函数
from utils import fix_pythonpath_if_working_locally

# 调用fix_pythonpath_if_working_locally函数,用于修复本地Python路径
fix_pythonpath_if_working_locally()

# 在Jupyter Notebook中使用matplotlib绘图时,需要使用%matplotlib inline命令
%matplotlib inline
# 加载autoreload扩展,可以在代码修改后自动重新加载模块
%load_ext autoreload

# 设置autoreload的模式为2,即在代码修改后自动重新加载模块
%autoreload 2

# 设置matplotlib在notebook中显示图形
%matplotlib inline
# 导入所需的库
import torch
import numpy as np
import pandas as pd
import shutil
import matplotlib.pyplot as plt
import warnings
import logging

# 禁用警告和日志
warnings.filterwarnings("ignore")
logging.disable(logging.CRITICAL)

# 导入Darts库中的模型和数据集
from darts.models import NHiTSModel, TiDEModel
from darts.datasets import AusBeerDataset

# 导入Darts库中的数据处理工具
from darts.dataprocessing.transformers.scaler import Scaler

# 导入PyTorch Lightning库中的EarlyStopping回调函数
from pytorch_lightning.callbacks.early_stopping import EarlyStopping

# 导入Darts库中的评估指标
from darts.metrics import mae, mse

# 加载澳大利亚啤酒数据集
data = AusBeerDataset()

# 将数据集划分为训练集和测试集
train, val = data.split_before(pd.Timestamp('01-01-2010'))

# 对数据进行标准化处理
scaler = Scaler()
train_transformed = scaler.fit_transform(train)
val_transformed = scaler.transform(val)

# 使用TiDE模型进行时间序列预测
model = TiDEModel(input_chunk_length=24, output_chunk_length=12, n_rnn_layers=2, n_dense_layers=2, n_cells=32, cell_type='GRU')
es = EarlyStopping(monitor='val_loss', patience=5)
model.fit(train_transformed, epochs=100, batch_size=32, verbose=True, callbacks=[es], val_split=0.2)

# 对测试集进行预测
pred_series = model.predict(n=len(val_transformed))

# 将预测结果反向标准化
pred_series = scaler.inverse_transform(pred_series)

# 计算MAE和MSE指标
mae_val = mae(val, pred_series)
mse_val = mse(val, pred_series)

# 输出MAE和MSE指标
print(f'MAE: {mae_val:.4f}')
print(f'MSE: {mse_val:.4f}')

# 绘制预测结果和实际结果的对比图
plt.plot(val, label='actual')
plt.plot(pred_series, label='forecast')
plt.legend()
plt.show()

模型参数设置

模板代码很无聊,特别是在训练多个模型以比较性能的情况下。为了避免这种情况,我们使用一个通用配置,可以与任何Darts TorchForecastingModel一起使用。

这些参数有一些有趣的地方:

  • **梯度裁剪:**通过为批处理设置梯度上限来减轻反向传播期间的梯度爆炸。

  • **学习率:**模型学习的大部分内容都在早期时期完成。随着训练的进行,减少学习率通常有助于微调模型。话虽如此,它也可能导致显着的过度拟合。

  • **提前停止:**为了避免过度拟合,我们可以使用提前停止。它监视验证集上的指标,并根据自定义条件在指标不再改善时停止训练。

# 定义优化器参数
optimizer_kwargs = {
    "lr": 1e-3,  # 学习率
}

# 定义 PyTorch Lightning Trainer 参数
pl_trainer_kwargs = {
    "gradient_clip_val": 1,  # 梯度裁剪值
    "max_epochs": 200,  # 最大迭代次数
    "accelerator": "auto",  # 自动选择加速器
    "callbacks": [],  # 回调函数
}

# 定义学习率调度器
lr_scheduler_cls = torch.optim.lr_scheduler.ExponentialLR  # 指数学习率调度器
lr_scheduler_kwargs = {
    "gamma": 0.999,  # 学习率衰减系数
}

# 定义早停法则(需要在后面的模型中重新设置)
# 当验证集损失连续10个epoch没有下降超过1e-3时,停止训练
early_stopping_args = {
    "monitor": "val_loss",  # 监控指标
    "patience": 10,  # 忍耐次数
    "min_delta": 1e-3,  # 最小变化量
    "mode": "min",  # 模式
}

# 定义通用模型参数
common_model_args = {
    "input_chunk_length": 12,  # 输入数据的时间步长
    "output_chunk_length": 12,  # 输出数据的时间步长
    "optimizer_kwargs": optimizer_kwargs,  # 优化器参数
    "pl_trainer_kwargs": pl_trainer_kwargs,  # PyTorch Lightning Trainer 参数
    "lr_scheduler_cls": lr_scheduler_cls,  # 学习率调度器
    "lr_scheduler_kwargs": lr_scheduler_kwargs,  # 学习率调度器参数
    "likelihood": None,  # 概率预测的似然函数
    "save_checkpoints": True,  # 是否保存检查点
    "force_reset": True,  # 是否强制重置模型
    "batch_size": 256,  # 批次大小
    "random_state": 42,  # 随机种子
}

数据加载和准备

我们考虑澳大利亚每季度啤酒销售量(单位为兆升)。

在训练之前,我们将数据分为训练集、验证集和测试集。模型将从训练集中学习,使用验证集确定何时停止训练,并最终在测试集上进行评估。

为了避免从验证集和测试集中泄漏信息,我们根据训练集的属性对数据进行缩放。

# 导入AusBeerDataset数据集类
# 从该类中加载数据集并存储在series变量中
series = AusBeerDataset().load()

# 将series数据集按照0.6的比例分割成训练集和临时集
# 训练集存储在train变量中,临时集存储在temp变量中
train, temp = series.split_after(0.6)

# 将temp临时集按照0.5的比例分割成验证集和测试集
# 验证集存储在val变量中,测试集存储在test变量中
val, test = temp.split_after(0.5)
# 绘制训练集的图像,并添加标签为"train"
train.plot(label="train")

# 绘制验证集的图像,并添加标签为"val"
val.plot(label="val")

# 绘制测试集的图像,并添加标签为"test"
test.plot(label="test")

# 创建一个Scaler对象,使用默认的sklearn的MinMaxScaler进行数据缩放
scaler = Scaler()

# 对训练数据进行缩放,并将缩放后的结果赋值给train变量
train = scaler.fit_transform(train)

# 对验证数据进行缩放,并将缩放后的结果赋值给val变量
val = scaler.transform(val)

# 对测试数据进行缩放,并将缩放后的结果赋值给test变量
test = scaler.transform(test)

模型配置

使用已经建立的共享参数,我们可以看到NHiTS和TiDE的默认参数被使用。唯一的例外是,TiDE被测试了一下,包括和不包括可逆实例归一化

然后我们遍历模型字典并训练所有的模型。当使用早期停止时,保存检查点非常重要。这使我们能够继续超过最佳模型配置,然后在训练完成后恢复最佳权重。

# 创建模型
# 创建NHiTS模型,使用common_model_args参数,模型名称为"hi"
model_nhits = NHiTSModel(**common_model_args, model_name="hi")

# 创建TiDE模型,使用common_model_args参数,不使用可逆实例归一化,模型名称为"tide0"
model_tide = TiDEModel(
    **common_model_args, use_reversible_instance_norm=False, model_name="tide0"
)

# 创建TiDE模型,使用common_model_args参数,使用可逆实例归一化,模型名称为"tide1"
model_tide_rin = TiDEModel(
    **common_model_args, use_reversible_instance_norm=True, model_name="tide1"
)

# 将三个模型放入字典中,键为模型名称,值为对应的模型对象
models = {
    "NHiTS": model_nhits,
    "TiDE": model_tide,
    "TiDE+RIN": model_tide_rin,
}
# train the models and load the model from its best state/checkpoint
# 训练模型并从最佳状态/检查点加载模型

for name, model in models.items():
    # 对于每个模型,需要重置early stopping
    pl_trainer_kwargs["callbacks"] = [
        EarlyStopping(
            **early_stopping_args,
        )
    ]

    # 使用训练数据集和验证数据集对模型进行训练
    model.fit(
        series=train,
        val_series=val,
        verbose=False,
    )

    # 从检查点加载模型返回一个新的模型对象,将其存储在models字典中
    models[name] = model.load_from_checkpoint(model_name=model.model_name, best=True)
# 预测接下来的 `pred_steps` 个点,这些点是在 `pred_input` 结束后的
pred_steps = common_model_args["output_chunk_length"] * 2
pred_input = test[:-pred_steps]

# 创建一个图形窗口和一个坐标轴对象
fig, ax = plt.subplots(figsize=(15, 5))

# 绘制输入数据的图像
pred_input.plot(label="input")

# 绘制测试数据的图像
test[-pred_steps:].plot(label="ground truth", ax=ax)

# 创建一个字典来存储每个模型的预测结果
result_accumulator = {}

# 对于每个模型,进行预测并计算/存储指标
for model_name, model in models.items():
    # 预测未来的数据
    pred_series = model.predict(n=pred_steps, series=pred_input)

    # 绘制预测结果的图像
    pred_series.plot(label=model_name, ax=ax)

    # 存储模型的指标
    result_accumulator[model_name] = {
        "mae": mae(test, pred_series),
        "mse": mse(test, pred_series),
    }

结果

在这种情况下,普通的TiDE与NHiTs的准确性相似。包括可逆实例归一化(RINorm)极大地帮助改善了TiDE的预测(请记住,这只是一个例子,并不总是保证提高性能)。

# 导入pandas库
import pandas as pd

# 将result_accumulator字典转换为DataFrame
results_df = pd.DataFrame.from_dict(result_accumulator, orient="index")

# 绘制DataFrame的条形图
results_df.plot.bar()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数智笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值