Entrenamiento ingenuo de modelos en sklearn#

  • Ultima modificación: Junio 3, 2022

https://www.mlflow.org/docs/latest/quickstart.html

Carga de datos#

[1]:
def load_data():

    import pandas as pd

    url = "http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
    df = pd.read_csv(url, sep=";")

    y = df["quality"]
    x = df.copy()
    x.pop("quality")

    return x, y

Particionamiento de los datos#

[2]:
def make_train_test_split(x, y):

    from sklearn.model_selection import train_test_split

    (x_train, x_test, y_train, y_test) = train_test_split(
        x,
        y,
        test_size=0.25,
        random_state=123456,
    )
    return x_train, x_test, y_train, y_test

Cálculo de métricas de evaluación#

[3]:
def eval_metrics(y_true, y_pred):

    from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

    mse = mean_squared_error(y_true, y_pred)
    mae = mean_absolute_error(y_true, y_pred)
    r2 = r2_score(y_true, y_pred)

    return mse, mae, r2

Reporte de métricas de evaluación#

[4]:
def report(estimator, mse, mae, r2):

    print(estimator, ":", sep="")
    print(f"  MSE: {mse}")
    print(f"  MAE: {mae}")
    print(f"  R2: {r2}")

Almacenamiento del modelo#

[5]:
def save_best_estimator(estimator):

    import os
    import pickle

    if not os.path.exists("models"):
        os.makedirs("models")
    with open("models/estimator.pickle", "wb") as file:
        pickle.dump(estimator, file)

Carga del modelo#

[6]:
def load_best_estimator():

    import os
    import pickle

    if not os.path.exists("models"):
        return None
    with open("models/estimator.pickle", "rb") as file:
        estimator = pickle.load(file)

    return estimator

Entrenamiento#

[7]:
def train_estimator(alpha=0.5, l1_ratio=0.5, verbose=1):

    from sklearn.linear_model import ElasticNet

    x, y = load_data()
    x_train, x_test, y_train, y_test = make_train_test_split(x, y)
    estimator = ElasticNet(alpha=alpha, l1_ratio=l1_ratio, random_state=12345)
    estimator.fit(x_train, y_train)
    mse, mae, r2 = eval_metrics(y_test, y_pred=estimator.predict(x_test))
    if verbose > 0:
        report(estimator, mse, mae, r2)

    best_estimator = load_best_estimator()
    if best_estimator is None or estimator.score(x_test, y_test) > best_estimator.score(
        x_test, y_test
    ):
        best_estimator = estimator

    save_best_estimator(best_estimator)

Búsqueda manual de los mejores hiperparámetros#

[8]:
!ls -1 models/*
models/estimator.pickle
[9]:
train_estimator(0.5, 0.5)
ElasticNet(alpha=0.5, random_state=12345):
  MSE: 0.6349429447805036
  MAE: 0.6453803508338732
  R2: 0.0890018368226928
[10]:
train_estimator(0.2, 0.2)
ElasticNet(alpha=0.2, l1_ratio=0.2, random_state=12345):
  MSE: 0.5170837474931838
  MAE: 0.5701436798648394
  R2: 0.2581028767270219
[11]:
train_estimator(0.1, 0.1)
ElasticNet(alpha=0.1, l1_ratio=0.1, random_state=12345):
  MSE: 0.489021012335199
  MAE: 0.551252749110561
  R2: 0.29836649473051535
[12]:
train_estimator(0.1, 0.05)
ElasticNet(alpha=0.1, l1_ratio=0.05, random_state=12345):
  MSE: 0.48683363717622585
  MAE: 0.5493759222336462
  R2: 0.30150487868829456
[13]:
train_estimator(0.3, 0.2)
ElasticNet(alpha=0.3, l1_ratio=0.2, random_state=12345):
  MSE: 0.5322180010211477
  MAE: 0.5793993870194708
  R2: 0.23638867818623654

Chequeo#

[14]:
def check_estimator():

    x, y = load_data()
    x_train, x_test, y_train, y_test = make_train_test_split(x, y)
    estimator = load_best_estimator()
    mse, mae, r2 = eval_metrics(y_test, y_pred=estimator.predict(x_test))
    report(estimator, mse, mae, r2)


#
# Debe coincidir con el mejor modelo encontrado en la celdas anteriores
#
check_estimator()
ElasticNet(alpha=0.0001, l1_ratio=0.0001, random_state=12345):
  MSE: 0.4555137059864613
  MAE: 0.5292599144523824
  R2: 0.3464418293533321

Problemas de esta aproximación#

  • El usuario tiene que decidir en cada iteración que valores tantear.

  • No se almacenan los resultados de cada corrida.

  • La complejidad aumenta exponencialmente para el usuario con el aumento de parámetros elegibles.

  • No tiene en cuenta aspectos como la validación cruzada.

Búsqueda por código#

[15]:
def make_hyperparameters_search(alphas, l1_ratios):

    for alpha in alphas:
        for l1_ratio in l1_ratios:
            train_estimator(alpha=alpha, l1_ratio=l1_ratio, verbose=0)
[16]:
import numpy as np

alphas = np.linspace(0.0001, 0.5, 10)
l1_ratios = np.linspace(0.0001, 0.5, 10)
make_hyperparameters_search(alphas, l1_ratios)
check_estimator()
ElasticNet(alpha=0.0001, l1_ratio=0.0001, random_state=12345):
  MSE: 0.4555137059864613
  MAE: 0.5292599144523824
  R2: 0.3464418293533321
  • Esta aproximación es util solo cuando hay pocos hiperparámetros.

  • Tampoco se almacenan parámetros de las corridas, solo el mejor modelo.

[17]:
%%bash
rm -rf outputs mlruns models