scikit-learn y MLflow

En esta sección veremos como todos los modelos de sklearn tiene la misma API para entrenar todo tipo de modelos (en este caso de regresión). Veremos cómo usar los métodos .fit() y .predict(). Además veremos cómo usar MLflow para guardar métricas y parámetros de todos los modelos que corramos. Si estás haciendo esta sección en el mismo notebook de la sección anterior, puedes saltar hasta Transformación de Datos.

Empezaremos cargando los datos y el preprocesador que construimos en la sección anterior.

import dill
import numpy as np
import pandas as pd

from sklearn.model_selection import train_test_split
from sklearn.base import BaseEstimator, TransformerMixin

En este bloque de código vamos a copiar los transformers de la sección anterior. Normalmente los importaríamos de un archivo .py por los dejaremos en el notebook por simplicidad.

class TransformerFechas(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self
    def transform(self, X, y=None):
        columna_fecha = pd.to_datetime(X["pickup_datetime"])
        fecha_df = pd.DataFrame()
        fecha_df["weekday"] = columna_fecha.dt.weekday
        fecha_df["hour"] = columna_fecha.dt.hour
        return fecha_df

class TransformerDistancia(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self

    def transform(self, X, y=None):
        X_init = X[["pickup_latitude", "pickup_longitude"]].to_numpy()
        X_final = X[["dropoff_latitude", "dropoff_longitude"]].to_numpy()

        # Distancia de Haversine
        distancia = self.distancia_haversine(X_init=X_init, X_final=X_final)
        distancia_df = pd.DataFrame()
        distancia_df["distancia"] = distancia
        return distancia_df
    
    def distancia_haversine(self, X_init, X_final):
        # Convertir de decimal a radianes
        X_init = np.radians(X_init)
        X_final = np.radians(X_final)

        # haversine formula 
        dlat = X_final[:, 0] - X_init[:, 0] 
        dlon = X_final[:, 1] - X_init[:, 1]
        a = np.sin(dlat / 2) ** 2 + np.cos(X_init[:, 0]) * np.cos(X_final[:, 0]) * np.sin(dlon / 2) ** 2
        c = 2 * np.arcsin(np.sqrt(a))
        r = 6371 # Radius of earth in kilometers. Use 3956 for miles. Determines return value units.
        return c * r

Aquí cargamos los datos y el preprocesador entrenado de la sección anterior.

Ya no es necesario hacer .fit() para aplicar las transformaciones al dataframe de entrada porque toda la información quedó almacenada en el archivo preprocesser.pkl y se carga al usar dill.load().

Transformación de Datos

Entrenar Modelos

Baseline con DummyRegressor

Una opción que nos ofrece sklearn es entrenar modelos dummy. Estos son modelos que predicen lo mismo para todos los casos (en este caso el promedio) y nos sirven como una medida de cuál es el rendimiento mínimo para un problema. Si por alguna razón nuestro modelo tiene peor desempeño que el modelo dummy, tenemos que revisar nuestro modelo porque probablemente tenemos errores en la implementación.

En este caso vamos a usar el DummyRegressor que siempre predice la media de los datos de entrenamiento. La función evaluar_predicciones es una ayuda para poder calcular varias métricas de un modelo usando metricas incluídas de scikit-learn.

Baseline con regresión lineal

Otra buena medida es siempre empezar con un modelo lineal. Así tenemos una medida de cómo se desempeña un modelo sencillo.

Algo para notar es que sin importar el modelo, los modelos de sklearn siempre siguen el mismo proceso.

1. Inicializar modelo con la clase de sklearn.

2. Ejecutar función .fit(X_train, y_train.

3. Ejecutar función .predict(X) para generar las predicciones.

Esta consistencia en el proceso simplifica el uso de diferentes modelos.

circle-check

Checkpoint #1

circle-info

Solución Checkpoint #1

¿Cómo comparar modelos más allá de un print? MLFlow 🙌

Imprimiendo los resultados nos podemos dar cuenta del modelo con mejores resultados. Sin embargo, comparar los resultados usando print es difícil cuando el número de modelos empieza a crecer. Además idealmente queremos que todos los modelos queden guardados para poder retomarlos después. Para todo esto podemos usar MLflow.

MLflowarrow-up-right es una librería open-source que nos ayuda a manejar todo el ciclo de modelos de machine learning. En este caso vamos a ver cómo podemos usar MLflow para guardar resultados del desempeño de modelos para determinar cuál modelo es el mejor.

Vamos a correr los mismos modelos que acabamos de comparar pero esta vez vamos a usar MLflow para ver los resultados.

mlflow.sklearn.autolog() automáticamente nos ayuda a guardar varias métricas y parámetros del modelo. Sin embargo, no incluye valores para datos de validación. Para guardar métricas que no se incluyen en .autolog vamos a usar la función mlflow.log_metric dentro del context manager de run.

Vamos primero a usar el modelo dummy y vamos a poner run_name="dummy" para poder verlo con el nombre correcto en MLflow.

Una vez termine de correr esta celda debemos abrir la interfaz de MLflow para ver los resultados. Deberíamos encontrar una nueva carpeta llamada mlruns en la ubicación donde corrió este notebook. Una vez estemos en la carpeta donde está mlruns, debemos ir a un terminal a esa ubicación y ejecutamos el comando

Ahí nos debería salir el mensaje de que está iniciando un servidor y dar la ruta para acceder. (normalmente la ruta es http://127.0.0.1:5000arrow-up-right). Copiamos esa dirección en un navegador y ahí ya deberíamos ver la interfaz de MLflow.

Terminal iniciando interfaz de MLflow

En la interfaz de MLflow estarán los modelos que corramos usando MLflow y podemos filtrar u ordenar por métricas o parámetros que consideramos importantes. En general, con la interfaz de MLflow tenemos una base de datos de modelos que podemos analizar fácilmente.

Además, si hacemos click un alguna de las runs (click en la columna Start Time) podemos ver que tenemos los datos más detallados y los artifacts de cada run. Los artifacts pueden ser todo tipo de archivos (por ejemplo imágenes y CSVs) que nos ayudan a guardar lo relevante de cada caso como el modelo o el ambiente de conda desde el que corrimos el modelo.

Ahora corramos nuevamente la regresión lineal para que quede registrada en MLflow. En este caso vamos a guardar nuestro preprocesador que quede asociado a cada run usando .log_artifact.

Ahora que tenemos la regresión lineal y el modelo dummy en MLflow, vamos a probar con un modelo más complejo como el Random Forest. Por ahora vamos a dejar los parámetros por defecto que trae la clase RandomForestRegressor excepto n_jobs que lo vamos a poner con el parámetro n_jobs=2. Poner n_jobs=2 hace que el modelo corra en paralelo en 2 procesadores.

Entrenar el random forest puede tomar algunos minutos así que es un buen momento para resolver cualquier duda o tomar un descanso y estirar las piernas :)

circle-check

Checkpoint #2

circle-info

Solución Checkpoint #2

Con esas herramientas puedes buscar más modelos de regresión de sklearnarrow-up-right o mejorar los hiperparámetros de los modelos que usamos para intentar mejorar las métricas que obtuvimos hasta el momento. Incluso librerías como XGBoostarrow-up-right o LightGBMarrow-up-right ofrecen la opción de crear modelos con la API de sklearn. A pesar de que cada modelo puede usar técnicas muy diferentes, el código va a ser casi idéntico gracias a la consistencia en la API de scikit-learn.

Last updated

Was this helpful?