Más sobre forecasting en: cienciadedatos.net


Introducción

La mayoría de los algoritmos de machine learning se ejecutan en CPU (unidades centrales de procesamiento), procesadores de propósito general capaces de gestionar una amplia variedad de tareas. Sin embargo, las CPU no están optimizadas para las operaciones matriciales altamente paralelizadas de las que dependen muchos algoritmos, lo que a menudo da lugar a tiempos de entrenamiento más lentos y una escalabilidad limitada. En cambio, las GPU (unidades de procesamiento gráfico) están diseñadas específicamente para el procesamiento paralelo y son capaces de realizar miles de operaciones matemáticas simultáneas. Esto las hace especialmente adecuadas para entrenar e implantar modelos de machine learning a gran escala.

Varias librerías de machine learning permiten la ejecución en la GPU, entre ellas XGBoost, LightGBM, CatBoost y CuML. Al aprovechar las capacidades de la GPU, estas librerías pueden reducir drásticamente los tiempos de entrenamiento y mejorar la escalabilidad. En las siguientes secciones se muestra cómo ejecutar skforecast con aceleración en la GPU para entrenar modelos de forecasting.

ℹ️ Note

La ventaja en el rendimiento al utilizar una GPU depende en gran medida de la tarea específica y del tamaño del conjunto de datos. En general, la aceleración mediante GPU ofrece los mayores beneficios al trabajar con conjuntos de datos grandes y modelos complejos, donde sus capacidades de procesamiento paralelo pueden reducir significativamente los tiempos de entrenamiento.

  • En el forecasting recursivo (ForecasterRecursive y ForecasterRecursiveMultiseries), la fase de predicción debe ejecutarse de forma secuencial, ya que cada paso de tiempo depende de la predicción anterior. Esta dependencia inherente impide la paralelización durante la inferencia, lo que explica por qué el ajuste del modelo es sustancialmente más rápido en una GPU, mientras que la predicción puede ser incluso más lenta en comparación con una CPU. Para superar esta limitación, skforecast cambia automáticamente el regresor para que utilice la CPU durante la predicción, incluso si fue entrenado en una GPU.
  • Los forecasters directos (ForecasterDirect, ForecasterDirectMultivariate) no dependen de predicciones anteriores durante la inferencia. Esta independencia permite que tanto el entrenamiento como la predicción se beneficien completamente de la aceleración mediante GPU.

ℹ️ Note

A pesar de las importantes ventajas que ofrecen las GPUs para acelerar los cálculos de *machine learning*, el acceso a ellas suele ser limitado debido a los altos costos u otras restricciones prácticas. Afortunadamente, Google Colaboratory (Colab), un entorno gratuito de notebooks Jupyter, permite a los usuarios ejecutar código Python en la nube, con acceso a GPUs. Los siguientes enlaces proporcionan acceso a notebooks de Google Colab que demuestran cómo usar skforecast con aceleración por GPU.

Librerías

Las librerías necesarias para ejecutar el código de este tutorial son:

# Librerías
# ==============================================================================
import numpy as np
import pandas as pd
import torch
import psutil
import xgboost
from xgboost import XGBRegressor
import lightgbm
from lightgbm import LGBMRegressor
import catboost
from catboost import CatBoostRegressor
import cuml
from sklearn.ensemble import RandomForestRegressor
import warnings
import skforecast
from skforecast.recursive import ForecasterRecursive
from skforecast.model_selection import backtesting_forecaster, TimeSeriesFold

print(f"skforecast : {skforecast.__version__}")
print(f"xgboost    : {xgboost.__version__}")
print(f"lightgbm   : {lightgbm.__version__}")
print(f"catboost   : {catboost.__version__}")
print(f"cuml       : {cuml.__version__}")
# Mostrar información sobre la GPU y la CPU
# ==============================================================================
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print('Using device:', device)

if device.type == 'cuda':
    print(torch.cuda.get_device_name(0))
    print('Memory Usage:')
    print('Allocated :', round(torch.cuda.memory_allocated(0) / 1024**3, 1), 'GB')
    print('Reserved  :', round(torch.cuda.memory_reserved(0) / 1024**3, 1), 'GB')

print(f"CPU RAM Free: {psutil.virtual_memory().available / 1024**3:.2f} GB")

Datos

Se simula una serie temporal con un millón de observaciones.

# Datos
# ==============================================================================
n = 1_000_000
data = pd.Series(
    data  = np.random.normal(size=n), 
    index = pd.date_range(start="1990-01-01", periods=n, freq="h"),
    name  = 'y'
)
data.head(2)

XGBoost

Para ejecutar un modelo de XGBoost (versión 2.0 o superior) en una GPU, se debe establecer el argumento device='cuda' durante la inicialización.

# Suppress warnings
# ==============================================================================
warnings.filterwarnings(
    "ignore",
    message=".*Falling back to prediction using DMatrix.*",
    category=UserWarning,
    module="xgboost"
)
# Crear y entrenar un forecaster con un XGBRegressor usando GPU
# ==============================================================================
forecaster = ForecasterRecursive(
                 estimator = XGBRegressor(
                                 n_estimators = 1000,
                                 device       = 'cuda',
                                 verbosity    = 1
                             ),
                 lags = 50
             )

start_time = pd.Timestamp.now()
forecaster.fit(y=data)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Training time using GPU: {elapsed_time}")

# Predict
# ==============================================================================
start_time = pd.Timestamp.now()
forecaster.predict(steps=100)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Prediction time using GPU: {elapsed_time}")

# Backtesting
# ==============================================================================
cv = TimeSeriesFold(
         steps              = 100,
         initial_train_size = 990_000,
         refit              = False,
         verbose            = False
     )
start_time = pd.Timestamp.now()
_ = backtesting_forecaster(
        forecaster = forecaster,
        y          = data,
        cv         = cv,
        metric     = 'mean_absolute_error'

    )
elapsed_time = pd.Timestamp.now() - start_time

print(f"Backtesting time using GPU: {elapsed_time}")
# Crear y entrenar un forecaster con un XGBRegressor usando CPU
# ==============================================================================
forecaster = ForecasterRecursive(
                 estimator = XGBRegressor(n_estimators=1000),
                 lags      = 50
             )

start_time = pd.Timestamp.now()
forecaster.fit(y=data)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Training time using CPU: {elapsed_time}")

# Predict
# ==============================================================================
start_time = pd.Timestamp.now()
forecaster.predict(steps=100)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Prediction time using CPU: {elapsed_time}")

# Backtesting
# ==============================================================================
start_time = pd.Timestamp.now()
_ = backtesting_forecaster(
        forecaster = forecaster,
        y          = data,
        cv         = cv,
        metric     = 'mean_absolute_error'

    )
elapsed_time = pd.Timestamp.now() - start_time

print(f"Backtesting time using CPU: {elapsed_time}")

LightGBM

# Suppress warnings
# ==============================================================================
warnings.filterwarnings(
    "ignore",
    message="'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.",
    category=FutureWarning,
    module="sklearn.utils.deprecation"
)

Si se está utilizando Google Colab, ejecute lo siguiente en una celda del notebook para asegurarse de que LightGBM pueda utilizar la GPU NVIDIA al ejecutarse en Google Colab.

!mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd
# Crear y entrenar un forecaster con un LGBMRegressor usando GPU
# ==============================================================================
forecaster = ForecasterRecursive(
                 estimator = LGBMRegressor(n_estimators=1000, device='gpu', verbose=-1),
                 lags      = 50
             )

start_time = pd.Timestamp.now()
forecaster.fit(y=data)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Training time using GPU: {elapsed_time}")

# Predict
# ==============================================================================
start_time = pd.Timestamp.now()
forecaster.predict(steps=100)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Prediction time using GPU: {elapsed_time}")

# Backtesting
# ==============================================================================
start_time = pd.Timestamp.now()
_ = backtesting_forecaster(
        forecaster = forecaster,
        y          = data,
        cv         = cv,
        metric     = 'mean_absolute_error'

    )
elapsed_time = pd.Timestamp.now() - start_time

print(f"Backtesting time using GPU: {elapsed_time}")
# Crear y entrenar un forecaster con un LGBMRegressor usando CPU
# ==============================================================================
forecaster = ForecasterRecursive(
                 estimator = LGBMRegressor(n_estimators=1000, device='cpu', verbose=-1),
                 lags      = 50
             )

start_time = pd.Timestamp.now()
forecaster.fit(y=data)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Training time using CPU: {elapsed_time}")

# Predict
# ==============================================================================
start_time = pd.Timestamp.now()
forecaster.predict(steps=100)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Prediction time using CPU: {elapsed_time}")

# Backtesting
# ==============================================================================
start_time = pd.Timestamp.now()
_ = backtesting_forecaster(
        forecaster = forecaster,
        y          = data,
        cv         = cv,
        metric     = 'mean_absolute_error'

    )
elapsed_time = pd.Timestamp.now() - start_time

print(f"Backtesting time using CPU: {elapsed_time}")

CatBoost

# Crear y entrenar un forecaster con un CatBoostRegressor usando GPU
# ==============================================================================
forecaster = ForecasterRecursive(
                 estimator = CatBoostRegressor(n_estimators=1000, task_type='GPU', silent=True, allow_writing_files=False),
                 lags      = 50
             )

start_time = pd.Timestamp.now()
forecaster.fit(y=data)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Training time using GPU: {elapsed_time}")

# Predict
# ==============================================================================
start_time = pd.Timestamp.now()
forecaster.predict(steps=100)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Prediction time using GPU: {elapsed_time}")

# Backtesting
# ==============================================================================
start_time = pd.Timestamp.now()
_ = backtesting_forecaster(
        forecaster = forecaster,
        y          = data,
        cv         = cv,
        metric     = 'mean_absolute_error'

    )
elapsed_time = pd.Timestamp.now() - start_time

print(f"Backtesting time using GPU: {elapsed_time}")
# Crear y entrenar un forecaster con un CatBoostRegressor usando CPU
# ==============================================================================
forecaster = ForecasterRecursive(
                 estimator = CatBoostRegressor(n_estimators=1000, task_type='CPU', silent=True, allow_writing_files=False),
                 lags      = 50
             )

start_time = pd.Timestamp.now()
forecaster.fit(y=data)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Training time using CPU: {elapsed_time}")

# Predict
# ==============================================================================
start_time = pd.Timestamp.now()
forecaster.predict(steps=100)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Prediction time using CPU: {elapsed_time}")

# Backtesting
# ==============================================================================
start_time = pd.Timestamp.now()
_ = backtesting_forecaster(
        forecaster = forecaster,
        y          = data,
        cv         = cv,
        metric     = 'mean_absolute_error'

    )
elapsed_time = pd.Timestamp.now() - start_time

print(f"Backtesting time using CPU: {elapsed_time}")

RAPIDS cuML

cuML es una librería para ejecutar algoritmos de machine learning en GPUs con una API que sigue de cerca la API de scikit-learn. Para usar cuML con skforecast, necesitas instalar la librería RAPIDS cuML. El proceso de instalación puede variar dependiendo de tu entorno y la versión de CUDA que tengas instalada. Puedes encontrar instrucciones detalladas de instalación en la documentación de RAPIDS.

# Reducir el tamaño de los datos para reducir el tiempo de ejecución
# ==============================================================================
data = data.iloc[:100_000].copy()
# Crear y entrenar un forecaster con un RandomForestRegressor usando GPU
# ==============================================================================
forecaster = ForecasterRecursive(
                estimator = cuml.ensemble.RandomForestRegressor(
                                n_estimators=200,
                                max_depth=5,
                                output_type='numpy'
                            ),
                lags = 20
             )

start_time = pd.Timestamp.now()
forecaster.fit(y=data)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Training time using GPU: {elapsed_time}")

# Predict
# ==============================================================================
start_time = pd.Timestamp.now()
forecaster.predict(steps=100)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Prediction time using GPU: {elapsed_time}")

# Backtesting
# ==============================================================================
cv = TimeSeriesFold(
         steps              = 100,
         initial_train_size = 90_000,
         refit              = False,
         verbose            = False
     )
start_time = pd.Timestamp.now()
_ = backtesting_forecaster(
        forecaster = forecaster,
        y          = data,
        cv         = cv,
        metric     = 'mean_absolute_error'

    )
elapsed_time = pd.Timestamp.now() - start_time

print(f"Backtesting time using GPU: {elapsed_time}")
# Crear y entrenar un forecaster con un RandomForestRegressor usando CPU
# ==============================================================================
forecaster = ForecasterRecursive(
                RandomForestRegressor(n_estimators=200, max_depth=5),
                lags = 20
             )

start_time = pd.Timestamp.now()
forecaster.fit(y=data)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Training time using CPU: {elapsed_time}")

# Predict
# ==============================================================================
start_time = pd.Timestamp.now()
forecaster.predict(steps=100)
elapsed_time = pd.Timestamp.now() - start_time

print(f"Prediction time using CPU: {elapsed_time}")

# Backtesting
# ==============================================================================
cv = TimeSeriesFold(
         steps              = 100,
         initial_train_size = 90_000,
         refit              = False,
         verbose            = False
     )
start_time = pd.Timestamp.now()
_ = backtesting_forecaster(
        forecaster = forecaster,
        y          = data,
        cv         = cv,
        metric     = 'mean_absolute_error'

    )
elapsed_time = pd.Timestamp.now() - start_time

print(f"Backtesting time using CPU: {elapsed_time}")

Información de sesión

import session_info
session_info.show(html=False)

Instrucciones para citar

¿Cómo citar este documento?

Si utilizas este documento o alguna parte de él, te agradecemos que lo cites. ¡Muchas gracias!

Acelerar modelos de forecasting con GPU por Joaquín Amat Rodrigo y Javier Escobar Ortiz, disponible bajo una licencia Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0 DEED) en https://cienciadedatos.net/documentos/py65-acelerar-modelos-forecasting-gpu.html

¿Cómo citar skforecast?

Si utilizas skforecast, te agradeceríamos mucho que lo cites. ¡Muchas gracias!

Zenodo:

Amat Rodrigo, Joaquin, & Escobar Ortiz, Javier. (2024). skforecast (v0.19.0). Zenodo. https://doi.org/10.5281/zenodo.8382788

APA:

Amat Rodrigo, J., & Escobar Ortiz, J. (2024). skforecast (Version 0.19.0) [Computer software]. https://doi.org/10.5281/zenodo.8382788

BibTeX:

@software{skforecast, author = {Amat Rodrigo, Joaquin and Escobar Ortiz, Javier}, title = {skforecast}, version = {0.19.0}, month = {03}, year = {2025}, license = {BSD-3-Clause}, url = {https://skforecast.org/}, doi = {10.5281/zenodo.8382788} }

¿Te ha gustado el artículo? Tu ayuda es importante

Tu contribución me ayudará a seguir generando contenido divulgativo gratuito. ¡Muchísimas gracias! 😊

Become a GitHub Sponsor Become a GitHub Sponsor

Creative Commons Licence

Este documento creado por Joaquín Amat Rodrigo y Javier Escobar Ortiz tiene licencia Attribution-NonCommercial-ShareAlike 4.0 International.

Se permite:

  • Compartir: copiar y redistribuir el material en cualquier medio o formato.

  • Adaptar: remezclar, transformar y crear a partir del material.

Bajo los siguientes términos:

  • Atribución: Debes otorgar el crédito adecuado, proporcionar un enlace a la licencia e indicar si se realizaron cambios. Puedes hacerlo de cualquier manera razonable, pero no de una forma que sugiera que el licenciante te respalda o respalda tu uso.

  • No-Comercial: No puedes utilizar el material para fines comerciales.

  • Compartir-Igual: Si remezclas, transformas o creas a partir del material, debes distribuir tus contribuciones bajo la misma licencia que el original.