<jupyter_start><jupyter_text>Demo Wine avec MLflow  Setup MLflowPar defaut suppose que le repository est le répertoire local mlrunsPour travailler en coopération, on va désigner le serveur soit en ligne de commande avec```export MLFLOW_TRACKING_URI=http://localhost:5000```soit par programme<jupyter_code>import mlflow
server_uri = "http://localhost:5000"
mlflow.set_tracking_uri(server_uri)<jupyter_output><empty_output><jupyter_text>Création d'une expérimentationL'expérimentation peut être crée puis sélectionnée en ligne de commande par```mlflow experiments create --experiment-name ac2  --artifact-location /opt/mlflow/mlruns/export MLFLOW_EXPERIMENT_ID=1```ou par programme (voir ci-après)<jupyter_code>mlflow.set_experiment("wine7")<jupyter_output><empty_output><jupyter_text>Entraînement<jupyter_code>import warnings
import logging
logging.basicConfig(level=logging.WARN)
logger = logging.getLogger(__name__)

import numpy as np
warnings.filterwarnings("ignore")
np.random.seed(40)

import mlflow.sklearn
import pandas as pd 

# read data from file
df = pd.read_csv("wine-quality.csv")
from sklearn.model_selection import train_test_split
# Split the data into training and test sets. (0.75, 0.25) split.
train, test = train_test_split(df)

# The predicted column is "quality" which is a scalar from [3, 9]
train_x = train.drop(["quality"], axis=1)
test_x = test.drop(["quality"], axis=1)
train_y = train[["quality"]]
test_y = test[["quality"]]

# make it easy to pass datasets
datasets = { 'train_x': train_x, 'train_y': train_y, 'test_x': test_x, 'test_y': test_y }
shapes = [ "%s : %s" % (name, dataset.shape) for (name,dataset) in datasets.items() ]
print(shapes)
def eval_parameters(in_alpha, in_l1_ratio):
    # Set default values if no alpha is provided
    alpha = float(in_alpha) if not in_alpha is None else 0.5
    # Set default values if no l1_ratio is provided
    l1_ratio = float(in_l1_ratio) if not in_l1_ratio is None else 0.5
    return alpha, l1_ratio
def eval_metrics(actual, predicted):
    from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
    rmse = np.sqrt(mean_squared_error(actual, predicted))
    mae = mean_absolute_error(actual, predicted)
    r2 = r2_score(actual, predicted)
    return rmse, mae, r2

from sklearn.linear_model import lasso_path, enet_path
import matplotlib.pyplot as plt
from itertools import cycle
def plot_enet_descent_path(tmpdir, X, y, l1_ratio):
    # Compute paths
    eps = 5e-3  # the smaller it is the longer is the path

    # Reference the global image variable
    global image
    
    print("Computing regularization path using ElasticNet.")
    alphas_enet, coefs_enet, _ = enet_path(X, y, eps=eps, l1_ratio=l1_ratio, fit_intercept=False)

    # Display results
    fig = plt.figure(1)
    ax = plt.gca()

    colors = cycle(['b', 'r', 'g', 'c', 'k'])
    neg_log_alphas_enet = -np.log10(alphas_enet)
    for coef_e, c in zip(coefs_enet, colors):
        l1 = plt.plot(neg_log_alphas_enet, coef_e, linestyle='--', c=c)

    plt.xlabel('-Log(alpha)')
    plt.ylabel('coefficients')
    title = 'ElasticNet Path by alpha for l1_ratio = ' + str(l1_ratio)
    plt.title(title)
    plt.axis('tight')

    # Display images
    image = fig
    
    # Save figure
    fig.savefig(os.path.join(tempdir, "ElasticNet-paths.png"))

    # Close plot
    plt.close(fig)

    # Return images
    return image    

import os
def output_enet_coefs(tempdir, columns, lr):
    coef_file_name = os.path.join(tempdir, "coefs.txt")
    with open(coef_file_name, "w") as f: 
        f.write("Coefs:\n")         
        [ f.write("\t %s: %s\n" % (name, coef)) for (name, coef) in zip(columns, lr.coef_) ]
        f.write("\t intercept: %s\n" % lr.intercept_) 
def plot_enet_feature_importance(tempdir, columns, coefs):
    # Reference the global image variable
    global image
    
    # Display results
    fig = plt.figure(1)
    ax = plt.gca()
    
    feature_importance = pd.Series(index = columns, data = np.abs(coefs))
    n_selected_features = (feature_importance>0).sum()
    print('{0:d} features, reduction of {1:2.2f}%'.format(
        n_selected_features,(1-n_selected_features/len(feature_importance))*100))
    feature_importance.sort_values().tail(30).plot(kind = 'bar', figsize = (20,12));
    
    # Display images
    image = fig
    
    # Save figure
    fig.savefig(os.path.join(tempdir, "feature-importance.png"))

    # Close plot
    plt.close(fig)

    # Return images
    return image    
import tempfile
def train_elasticnet(in_alpha, in_l1_ratio, trial=None):
    from sklearn.linear_model import ElasticNet

    alpha, l1_ratio = eval_parameters(in_alpha, in_l1_ratio)
    print("Parameters (alpha=%f, l1_ratio=%f):" % (alpha, l1_ratio))
    
    run_name = "en_%f_%f" % (alpha,l1_ratio)
    with mlflow.start_run() as run:
        # train with ElasticNet
        lr = ElasticNet(alpha=alpha, l1_ratio=l1_ratio, random_state=42)
        lr.fit(train_x, train_y)

        # Evaluate Metrics
        predicted_qualities = lr.predict(test_x)
        (rmse, mae, r2) = eval_metrics(test_y, predicted_qualities)

        # Print out metrics
        print("Elasticnet model (alpha=%f, l1_ratio=%f):" % (alpha, l1_ratio))
        print("  RMSE: %s" % rmse)
        print("  MAE: %s" % mae)
        print("  R2: %s" % r2)

        # Log parameter, metrics, and model to MLflow
        mlflow.log_param("alpha", alpha)
        mlflow.log_param("l1_ratio", l1_ratio)
        mlflow.log_metric("rmse", rmse)
        mlflow.log_metric("mae", mae)
        mlflow.log_metric("r2", r2)
        mlflow.set_tag("algo", "ElastiNet")
        if trial != None:
             mlflow.set_tag("trial", trial)
        
        #run_id = run.info.run_id
        # store info       
        with tempfile.TemporaryDirectory() as tmpdirname:  
            output_enet_coefs(tmpdirname, train_x.columns, lr) 

            # plots
            plot_enet_feature_importance(tmpdirname, train_x.columns, lr.coef_)
            # Call plot_enet_descent_path
            #image = plot_enet_descent_path(tmpdirname, train_x, train_y, l1_ratio)

            # Log artifacts (output files)
            mlflow.log_artifacts(tmpdirname, artifact_path="artifacts")


        # store model
        mlflow.sklearn.log_model(lr, "model")
        
        return rmse
train_elasticnet(0.5, 0.5) # alpha 0.5, L1 0.5
train_elasticnet(0.5, 0.4)<jupyter_output>Parameters (alpha=0.500000, l1_ratio=0.400000):
Elasticnet model (alpha=0.500000, l1_ratio=0.400000):
  RMSE: 0.8134651568415164
  MAE: 0.6249674191990106
  R2: 0.1453313314484228
3 features, reduction of 72.73%<jupyter_text>Auto tuning<jupyter_code>!pip install optuna
import optuna
from datetime import datetime
optuna.logging.set_verbosity(optuna.logging.INFO)
ts = datetime.now().strftime('%Y%m%dT%H%M%S')
# Define an objective function to be minimized.
def objective(trial):

    suggested_alpha = trial.suggest_uniform('alpha', 0.1, 0.8)
    suggested_l1_ratio = trial.suggest_uniform('l1_ratio', 0.1, 0.8)
        
    error = train_elasticnet(suggested_alpha, suggested_l1_ratio, trial="%s_%s" % (ts,trial.trial_id))
    
    return error  # A objective value linked with the Trial object.

study = optuna.create_study()  # Create a new study.
study.optimize(objective, n_trials=40)  #100   # Invoke optimization of the objective function.
study.best_params
study.best_trial<jupyter_output><empty_output><jupyter_text>Identification par tag du best model<jupyter_code>trial_id = study.best_trial.number
print("trial_id: %s" % trial_id)
tag = "%s_%s" % (ts, trial_id)
print("tag: %s" % tag)
from mlflow.entities import ViewType
query = "tags.trial = '%s'" % tag
runs = mlflow.search_runs(filter_string=query, run_view_type=ViewType.ACTIVE_ONLY)
runs.head(10)
best_model_id = runs['run_id'][0]
best_model_uri = runs['artifact_uri'][0]
print("best model - id: %s - uri: %s" % (best_model_id, best_model_uri) )
from  mlflow.tracking import MlflowClient
mlflow_client = MlflowClient()
mlflow_client.set_tag(best_model_id, "best_model", "true")
runs = mlflow.search_runs(filter_string=query, run_view_type=ViewType.ACTIVE_ONLY)
runs.head(10)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11646929556830668, 'fraction_numerical': 0.025149554388963498, 'mean_word_length': 3.92012012012012, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '47146', 'license': 'MIT', 'n_tokens_mistral': 3068, 'n_tokens_neox': 2907, 'n_words': 654, 'path': 'wine-notebooks/build-model-mlflow.ipynb', 'repo_name': 'cfalguiere/aidemos-mlflow-wine', 'size': '8191'}