Blog de HAQM Web Services (AWS)

Industrializa la previsión de generación de energía de tus plantas solares utilizando HAQM SageMaker Unified Studio – Parte 1

Por José Sánchez Romero, Arquitecto de Soluciones senior en AWS y Ana Suja, Arquitecta de Soluciones en AWS.

 

En esta serie de dos blogs aprenderás a desarrollar un sistema de predicción energética para plantas solares haciendo uso de HAQM SageMaker Unified Studio. La nueva herramienta de AWS que fue presentada en re:Invent 2024 es un entorno de desarrollo integrado (IDE) que optimiza la gestión de datos y procesos de inteligencia artificial (IA). Este servicio unificado facilita a los equipos de desarrollo la administración centralizada de recursos y componentes de IA en toda la organización.

En esta primera parte te guiaremos paso a paso por el proceso de creación de un modelo de aprendizaje automático (ML por sus siglas en inglés) que te permitirá predecir la producción energética de una planta solar. En la segunda parte, te enseñaremos a construir, entrenar, desplegar y gestionar modelos de previsión de la producción a escala para tus distintas plantas.

1. El reto de la previsión de la producción de energía solar

Uno de los retos a los que se enfrentan las unidades de gestión de energía de las compañías que producen y/o comercializan electricidad es conocer la previsión de generación de las plantas. Cuando hablamos de plantas solares fotovoltaicas, la generación de energía tiene una dependencia directa con la irradiancia, energía proporcionada por la radiación electromagnética procedente del sol medida en vatios/m2.

Los modelos analíticos, tanto lineales como no lineales, permiten realizar predicciones basadas en la irradiancia esperada, sin embargo, estos modelos presentan limitaciones al no considerar factores operativos importantes como la degradación progresiva de equipos, las fluctuaciones de temperatura local, los patrones meteorológicos específicos de cada zona o la acumulación de polvo en paneles solares

Por esta razón, la industria ha incorporado técnicas de ML a sus predicciones que complementan y mejoran los cálculos analíticos. Estos modelos destacan por su capacidad de adaptar la previsión a las condiciones específicas de cada instalación.

2. Implementación paso a paso: Desarrollo del modelo predictivo con HAQM SageMaker Unified Studio

HAQM SageMaker Unified Studio Workflows es una herramienta integrada en HAQM SageMaker Unified Studio que facilita el desarrollo y despliegue de modelos predictivos. Los workflows permiten a desarrolladores y especialistas en MLOps (Machine Learning Operations) crear flujos de trabajo reproducibles y escalables. Workflows es una herramienta pensada para la gestión centralizada de las diferentes tareas que forman parte del proceso de entrenamiento y despliegue, la integración eficiente y nativa de datos y procesos y la colaboración entre equipos de trabajo.

El proceso de implementación del flujo de trabajo que vamos a construir considera las siguientes tareas:

  1. Preparación del proyecto en HAQM SageMaker Unified Studio
  2. Generación de datos sintéticos
  3. Desarrollo del flujo de trabajo, incluyendo el preprocesamiento de datos, el entrenamiento del modelo y el despliegue del modelo
  4. Evaluación de resultados

2.1 Preparación de un proyecto en HAQM SageMaker Unified Studio

Para comenzar a utilizar HAQM SageMaker Unified Studio puedes seguir los pasos de la documentación. Primero debes pedir acceso a tu administrador (o crear un dominio si eres tú el administrador – accede a HAQM SageMaker Unified Studio), una vez hayas accedido, deberás crear un proyecto. Sigue los pasos para crear un nuevo proyecto en la documentación. Al crear el proyecto, elige un perfil análisis de datos y desarrollo de modelos de IA-ML.

Al crear un proyecto con el perfil de datos y desarrollo de modelos de IA-ML, el proyecto queda preconfigurado con:

En este blog, usaremos el bucket de HAQM S3 que se crea automáticamente en el proyecto.

Figura 1 – Bucket de HAQM S3 generado automáticamente por HAQM SageMaker Unified Studio.

2.2. Generación de datos sintéticos usando la IA generativa

El desarrollo de modelos ML para predecir la generación de energía solar requiere datos históricos de producción de la planta y meteorología histórica. La falta de estos datos suele retrasar el desarrollo de los proyectos. Sin embargo, la IA generativa ofrece una solución a este problema mediante la creación de datos sintéticos de calidad, lo que posibilita el desarrollo paralelo del modelo de ML y la infraestructura tecnológica donde se desplegará.

Para predecir la generación solar utilizamos la función analítica simplificada:

Po = Ppeak(G/Gstandard) – α (Tc – Tstandard)

Donde:

  • Po: potencia eléctrica generada
  • G: irradiancia
  • Tc: temperatura de célula solar
  • Ppeak, Gstandard, α, Tstandard: parámetros del fabricante

Para este proyecto generamos datos utilizando un script Python 3.11 desarrollado por Antrophic Claude Haiku v1 a través de HAQM Bedrock. El código genera datos sintéticos basados en previsiones meteorológicas de Solcast incluyendo irradiancia y temperatura, aunque podrían incorporarse variables adicionales para mejorar la precisión del modelo. El dataset de Solcast se usa en el código como input.csv.

import pandas as pd
import numpy as np
from datetime import datetime

# Leer el archivo input.csv 
input_data = pd.read_csv('input.csv')

# Convertir la columna time a datetime
input_data['time'] = pd.to_datetime(input_data['time'], format='%Y-%m-%dT%H:%M:%SZ')

# Convertir time a formato 'YYYY-MM-dd HH:mm:ss'
input_data['time'] = input_data['time'].dt.strftime('%Y-%m-%d %H:%M:%S')


# Convertir los tipos de datos
input_data['G'] = input_data['G'].astype(float)
input_data['T'] = input_data['T'].astype(float)

# Constantes
Gstandard = 1000
Ppeak = 545
Tstandard = 25
alpha = -0.348

# Calcular la potencia de salida
input_data['Po'] = Ppeak * (input_data['G'] / Gstandard) - alpha * (input_data['T'] - Tstandard)

# Añadir un 2% de ruido aleatorio a la variable Po
input_data['Po'] = input_data['Po'] * (1 + 0.02 * np.random.randn(len(input_data)))

# Crear el dataframe de salida
output_data = pd.DataFrame({'time': input_data['time'], 'Po': input_data['Po']})

# Guardar el dataframe en un csv
output_data.to_csv('output.csv', index=False)

Mediante este procedimiento simulamos datos para una planta solar con el siguiente resultado:

Figura 2 – Potencia e irradiancia normalizadas como función del tiempo

 

La estructura de los datos está reflejada en la Tabla 1:

Tabla 1 – Juego de datos de ejemplo generado por el script

Po time G T
0.000000 2022-07-10 23:00:00 0 64
0.674127 2023-07-13 15:00:00 0 90
0.000000 2023-07-16 05:00:00 100 78
0.609646 2022-07-17 16:00:00 70 88
0.835598 2022-07-01 15:00:00 30 93

Una vez generados los datos los almacenamos en el bucket de HAQM S3 junto a la información meteorológica obtenida de Solcast, ficheros outpoutpower.csv y clima.csv.

Figura 3 – Estructura de carpetas por defecto donde se recibirán de forma continuada los datos históricos para el entrenamiento del modelo.

2.3 Construcción del workflow

Los workflows en HAQM SageMaker Unified Studio nos permiten automatizar y organizar tareas complejas de manera eficiente, ahorrando tiempo y reduciendo errores en nuestros proyectos de ML. Utilizan Apache Airflow para orquestar rutinas de código.

Para crear un workflow, accede al menú “Build” –> “Orchestration” –> “Workflows”:

Figura 4 – Creación de un workflow en HAQM SageMaker Unified Studio

Al seleccionar ‘Create workflow in editor‘ en el espacio ‘Local space‘, accederás a la consola de HAQM SageMaker Unified Studio.

El flujo de trabajo que hemos diseñado consta de tres tareas principales:

  • Preprocesamiento (script ‘preprocessing.ipynb‘): Limpieza y preparación de datos
  • Entrenamiento (script ‘solarplanttrainXGB.ipynb‘): Construcción del modelo utilizando el algoritmo XGBoost (Extreme Gradient Boosting).
  • Despliegue (script ‘solarplantdeployandtest.ipynb‘): Creación del endpoint de inferencia
from airflow.decorators import dag
from airflow.utils.dates import days_ago
from workflows.airflow.providers.amazon.aws.operators.sagemaker_workflows \
    import NotebookOperator

# Establecer el calendario del flujo de trabajo a None (activación manual)
WORKFLOW_SCHEDULE = None

# Definir las rutas a los notebooks de SageMaker
PREPRO_NOTEBOOK_PATH = 'src/preprocessing.ipynb'
TRAIN_NOTEBOOK_PATH = 'src/solarplanttrainXGB.ipynb'
DEPLOY_NOTEBOOK_PATH = 'src/solarplantdeployandtest.ipynb'

default_args = {
    'owner': 'xxxx@yyyy.com',
}

@dag(
    dag_id='workflow_solar_2',
    default_args=default_args,
    schedule_interval=WORKFLOW_SCHEDULE,
    start_date=days_ago(2),
    is_paused_upon_creation=False,
    tags=['proyecto_solarv3', ' xxxx@yyyy.com '],
    catchup=False
)
def notebook_task_wf():
    def task1():
        notebook1 = NotebookOperator(
            task_id="preprocessing",
            input_config={'input_path': PREPRO_NOTEBOOK_PATH, 'input_params': {}},
            output_config={'output_formats': ['NOTEBOOK']},
            wait_for_completion=True,
            poll_interval=5
        )
        return notebook1

    def task2():
        notebook2 = NotebookOperator(
            task_id="train",
            input_config={'input_path': TRAIN_NOTEBOOK_PATH, 'input_params': {}},
            output_config={'output_formats': ['NOTEBOOK']},
            wait_for_completion=True,
            poll_interval=5
        )
        return notebook2

    def task3():
        notebook2 = NotebookOperator(
            task_id="deploytest",
            input_config={'input_path': DEPLOY_NOTEBOOK_PATH, 'input_params': {}},
            output_config={'output_formats': ['NOTEBOOK']},
            wait_for_completion=True,
            poll_interval=5
        )
        return notebook2

    task1() >> task2() >> task3()

notebook_task_wf = notebook_task_wf()

Cada una de estas tareas se define como una función dentro del flujo de trabajo utilizando la sintaxis propia de programación de Apache Airflow. Las tareas se unen creando dependencias de ejecución secuencial: preprocesamiento (task 1) –> entrenamiento (task 2) –> despliegue (task 3).

2.3.1 Preprocesamiento

El preprocesamiento de datos es fundamental para obtener un juego de datos adecuado para entrenar el algoritmo y construir el modelo. En proyectos orientados a la predicción de energía solar, las tareas más comunes a realizar en esta etapa son:

  1. Completar datos faltantes en series temporales mediante técnicas de imputación
  2. Eliminar valores atípicos (como producción cero cuando existe irradiancia)
  3. Corregir errores de sensores (lecturas nocturnas o valores negativos)

En nuestro caso el script ‘preprocessing.ipynb’ integra los juegos de datos de potencia y clima, y genera nuevos juegos de datos para entrenamiento, prueba y validación.

import pandas as pd
from sklearn.model_selection import train_test_split

# Leer los datos climáticos y de producción de energía
df1 = pd.read_csv('clima.csv')  # datos climáticos
df2 = pd.read_csv('outputpower.csv')  # datos de producción de energía

df1['time'] = pd.to_datetime(df1['time'])
df2['time'] = pd.to_datetime(df2['time'])
df1['time'] = df1['time'].dt.tz_localize(None)
df2['time'] = df2['time'].dt.tz_localize(None)

# Combinar los dos DataFrames basándose en la columna de tiempo
merged_df = pd.merge(df1, df2, on='time', how='outer')

# Dividir el DataFrame combinado en conjuntos de entrenamiento, prueba y validación
train, test = train_test_split(merged_df, test_size=0.2)
train, validation = train_test_split(train, test_size=0.2)

# Preparar los datos de entrenamiento, prueba y validación
train = train[['Po','time','G','T']]
train = train.drop('time', axis=1)
test = test[['Po','time','G','T']]
test = test.drop('time', axis=1)
validation = validation[['Po','time','G','T']]
validation = validation.drop('time', axis=1)

El script se ejecuta utilizando el marco de desarrollo de HAQM SageMaker para el preprocesamiento de datos en contenedores.

# Configurar el Procesador de SageMaker
from sagemaker.sklearn.processing import SKLearnProcessor

sklearn_processor = SKLearnProcessor(
    framework_version="0.23-1",
    role=role,
    instance_type="ml.m5.xlarge",
    instance_count=1
)

sklearn_processor.run(
     code="preprocessing.py",
     arguments=[
        "--folder", "xxxxx/xxxxxxx/solar/planta001",
        "--fileclima", "clima.csv",
        "--fileoutputpower", "outputpower.csv"]
)

2.3.2 Entrenamiento del modelo

El entrenamiento del modelo se realiza mediante un script que sigue los siguientes pasos:

  1. Establece una sesión de HAQM SageMaker y asume el rol de ejecución que autoriza al script el acceso a datos y recursos
  2. Configura el contenedor Docker con XGBoost y los hiperparámetros profundidad del árbol, tasa de aprendizaje, rondas de entrenamiento

El entrenamiento del modelo se realiza mediante un script que sigue los siguientes pasos:

import sagemaker
from sagemaker import get_execution_role
from sagemaker.inputs import TrainingInput
from sagemaker.estimator import Estimator
from sagemaker.image_uris import retrieve

# Configurar la sesión de HAQM SageMaker y obtener el rol de ejecución
sagemaker_session = sagemaker.Session()
role = get_execution_role()
region = sagemaker_session.boto_region_name

# Definir las rutas S3 para los datos de entrenamiento, validación y prueba
s3_bucket = 'your-s3-bucket'
s3_prefix = 'your-s3-prefix'

s3_input_train = TrainingInput(f"s3://{s3_bucket}/{s3_prefix}/train.csv", content_type='csv')
s3_input_validation = TrainingInput(f"s3://{s3_bucket}/{s3_prefix}/validation.csv", content_type='csv')
s3_input_test = TrainingInput(f"s3://{s3_bucket}/{s3_prefix}/test.csv", content_type='csv')

# Obtener el contenedor Docker apropiado para el algoritmo XGBoost
container = retrieve("xgboost", sagemaker_session.boto_region_name, "latest")

# Crear el estimador XGBoost y establecer los hiperparámetros
xgb = Estimator(
    container,
    role,
    instance_count=1,
    instance_type="ml.c4.4xlarge",
    output_path=f"s3://{s3_bucket}/{s3_prefix}/output",
    sagemaker_session=sagemaker_session,
)

xgb.set_hyperparameters(
    max_depth=15,
    learning_rate=0.01,
    eta=0.3,
    gamma=5,
    min_child_weight=5,
    subsample=0.8,
    verbosity=0,
    objective="reg:linear",
    num_round=300,
    eval_metric="rmse",
)

# Entrenar el modelo XGBoost
xgb.fit({"train": s3_input_train, "test": s3_input_test, "validation": s3_input_validation})

# Guardar el artefacto del modelo en S3
keyori = f"{s3_prefix}/output/{xgb._current_job_name}/output/model.tar.gz"
keydest = f"{s3_prefix}/output/model.tar.gz"
s3 = sagemaker_session.boto_session.resource('s3')
source = {'Bucket': s3_bucket, 'Key': keyori}
s3.meta.client.copy(source, s3_bucket, keydest)

El modelo entrenado se almacena automáticamente en HAQM S3 en la ruta indicada en la variable output_path.

2.3.3 Despliegue

El último paso en el proceso es el despliegue del modelo entrenado para realizar inferencia y pruebas con un conjunto de datos de test que no fue utilizado durante la fase de entrenamiento.

Para llevar a cabo este paso, se programa un tercer script llamado «solarplantdeployandtest.ipynb». Este script permite crear un punto de inferencia para el modelo, es decir, una instancia de servicio que pueda recibir nuevos datos de entrada y generar predicciones.

import sagemaker
from datetime import datetime

# Configurar la sesión de HAQM SageMaker y obtener el rol de ejecución
sagemaker_session = sagemaker.Session()
role = sagemaker.get_execution_role()
region = sagemaker_session.boto_region_name

# Obtener el contenedor Docker apropiado para el algoritmo
image_name = sagemaker.image_uris.retrieve("xgboost", region, "latest")

# Especificar la ubicación del artefacto del modelo entrenado en S3
s3_bucket = 'your-s3-bucket'
s3_prefix = 'your-s3-prefix'
model_data = f's3://{s3_bucket}/{s3_prefix}/output/model.tar.gz'

# Crear un nombre único para el modelo
now = datetime.now()
formatted_date = now.strftime("%d-%m-%Y-%H-%M-%S")
model_name = f"xgboostsolar-{formatted_date}"

# Crear la instancia del Modelo SageMaker usando el artefacto del modelo entrenado
model = sagemaker.Model(
    role=role,
    model_data=model_data,
    image_uri=image_name,
    sagemaker_session=sagemaker_session,
    name=model_name
)

endpoint = modelprefix+formatted_date

predictor = model.deploy(
    initial_instance_count=1, 
    instance_type="ml.m5.large",
    endpoint_name=endpoint
)

2. 4 Inferencia y prueba

Una vez el modelo está desplegado, para probarlo se puede ejecutar el siguiente código que permite llamar al punto de inferencia con datos de prueba no utilizados en la fase de entrenamiento y validación.

import numpy as np
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

# Evaluar el modelo en el conjunto de prueba
y_true = test['Po']
y_pred = predictor.predict(test[['G', 'T']])

mae = mean_absolute_error(y_true, y_pred)
mse = mean_squared_error(y_true, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_true, y_pred)

# Evaluar el modelo en datos históricos de una planta de 4MW
historical_data = pd.read_csv('4MW_plant_data.csv')
y_true_historical = historical_data['Po']
y_pred_historical = predictor.predict(historical_data[['G', 'T']])

mae_historical = mean_absolute_error(y_true_historical, y_pred_historical)
mse_historical = mean_squared_error(y_true_historical, y_pred_historical)
rmse_historical = np.sqrt(mse_historical)

print(f"MAE: {mae_historical:.4f}")
print(f"RMSE: {rmse_historical:.4f}")

El script calcula el error absoluto medio (MAE) para los datos de prueba que resulta en 0.0037, y el error cuadrático medio (RMSE) que resulta en 0.0007 sobre un rango de valores de 1, valores que son bajos y que indican una buena precisión. El modelo se prueba también con datos reales no sintéticos disponibles para una planta de 4MW. En este caso el MAE resultante es de 0.078 y el RMSE de 0.18 sobre 4MW, errores en porcentajes del 0.2% y 4.5% respectivamente.

Figura 5 – Potencia de salida de la planta real (rojo) e inferida (azul), ambas normalizadas para irradiancias del juego de datos de test

Conclusiones

En este blog hemos construido un flujo de trabajo automatizado utilizando los workflows de HAQM SageMaker Unified Studio para predecir la producción de energía de una planta solar utilizando ML. El modelo generado ha mostrado una buena precisión con datos reales y nos permite sentar las bases para continuar con el proceso de industrialización. El objetivo último no es tanto generar modelos de predicción de alta precisión sino automatizar el despliegue de modelos de ML para múltiples plantas, lo que abordaremos en la segunda parte de esta serie de blogs. El enfoque desarrollado permite a los científicos de datos centrarse en el desarrollo de los modelos y a los ingenieros de plataforma centrarse en la industrialización del despliegue y operación de los mismos.

Acerca de los autores

  José Sánchez Romero es Arquitecto de Soluciones senior en AWS con especialización en el diseño e implementación de soluciones para el sector de la energía. Atesora más de 20 años de experiencia en consultoría tecnológica.
Ana Suja es Arquitecta de Soluciones en AWS. Trabaja para apoyar a la industria española en su camino a la nube. Ana está especialmente interesada en la sostenibilidad y en cómo la tecnología de AWS puede ayudar a sus clientes en su transformación digital y de sostenibilidad empresarial.