Condividi tramite


Parte 3 dell'esercitazione: eseguire il training e la registrazione di modelli di Machine Learning

In questa esercitazione si apprenderà come eseguire il training di più modelli di Machine Learning per selezionare quello migliore per stimare quali clienti bancari potrebbero lasciare.

In questa esercitazione si apprenderà come:

  • Eseguire il training di modelli Random Forest e LightGBM.
  • Usare l'integrazione nativa di Microsoft Fabric con il framework MLflow per registrare i modelli di Machine Learning sottoposti a training, gli iperparametri usati e le metriche di valutazione.
  • Registrare il modello di Machine Learning sottoposto a training.
  • Valutare le prestazioni dei modelli di Machine Learning sottoposti a training nel set di dati di convalida.

MLflow è una piattaforma open source per la gestione del ciclo di vita di Machine Learning con funzionalità come Rilevamento, Modelli e Registro modelli. MLflow è integrato in modo nativo con l'esperienza di data science di Fabric.

Prerequisiti

Questa è la parte 3 di 5 di questa serie di esercitazioni. Per procedere con questa esercitazione, è necessario completare:

Seguire la procedura nel notebook

3-train-evaluate.ipynb è il notebook che accompagna questa esercitazione.

Importante

Collegare lo stesso lakehouse usato nella parte 1 e nella parte 2.

Installare librerie personalizzate

Per questo notebook si installerà imbalanced-learn (importato come imblearn) usando %pip install. Imbalanced-learn è una libreria per la tecnica di Sovracampionamento delle minoranze sintetiche (SMOTE) usata per gestire set di dati sbilanciati. Il kernel PySpark verrà riavviato dopo %pip install, quindi sarà necessario installare la libreria prima di eseguire qualsiasi altra cella.

Si accederà a SMOTE usando la libreria imblearn. Installarlo ora usando le funzionalità di installazione in linea (ad esempio %pip, %conda).

# Install imblearn for SMOTE using pip
%pip install imblearn

Importante

Eseguire questa installazione ogni volta che si riavvia il notebook.

Quando si installa una libreria in un notebook, è disponibile solo per la durata della sessione del notebook e non nell'area di lavoro. Se si riavvia il notebook, sarà necessario installare nuovamente la libreria.

Se si ha spesso una libreria usata e si vuole renderla disponibile per tutti i notebook nell'area di lavoro, è possibile usare un ambiente Fabric a tale scopo. È possibile creare un ambiente, installare la libreria e quindi l'amministratore dell'area di lavoro può collegare l'ambiente all'area di lavoro come ambiente predefinito. Per altre informazioni sull'impostazione predefinita di un ambiente, vedere Impostazione predefinita dell'area di lavoro da parte dell'amministratore.

Per eseguire la migrazione delle librerie dell’area di lavoro e delle proprietà di Spark a un ambiente predefinito, vedere Eseguire la migrazione delle librerie dell'area di lavoro e delle proprietà di Spark.

Caricare i dati

Prima di eseguire il training di qualsiasi modello di Machine Learning, è necessario caricare la tabella delta dal lakehouse per leggere i dati puliti creati nel notebook precedente.

import pandas as pd
SEED = 12345
df_clean = spark.read.format("delta").load("Tables/df_clean").toPandas()

Generare un esperimento per tenere traccia e registrare il modello usando MLflow

Questa sezione illustra come generare un esperimento, specificare il modello di Machine Learning e i parametri di training, nonché le metriche di assegnazione dei punteggi, eseguire il training dei modelli di Machine Learning, registrarli e salvare i modelli sottoposti a training per usarli in un secondo momento.

import mlflow
# Setup experiment name
EXPERIMENT_NAME = "bank-churn-experiment"  # MLflow experiment name

Estendendo le funzionalità di registrazione automatica di MLflow, la registrazione automatica funziona catturando automaticamente i valori dei parametri di input e delle metriche di output di un modello di machine learning durante il training. Queste informazioni vengono quindi registrate nell'area di lavoro, da cui è possibile accedervi e visualizzarle usando le API MLflow o l'esperimento corrispondente nell'area di lavoro.

Tutti gli esperimenti con i rispettivi nomi vengono registrati e sarà possibile tenere traccia dei parametri e delle metriche delle prestazioni. Per altre informazioni sulla registrazione automatica, vedere Registrazione automatica in Microsoft Fabric.

Impostare le specifiche dell'esperimento e della registrazione automatica

mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(exclusive=False)

Importare scikit-learn e LightGBM

Con i dati sul posto, è ora possibile definire i modelli di Machine Learning. In questo notebook verranno applicati modelli Random Forest e LightGBM. Usare scikit-learn e lightgbm per implementare i modelli in poche righe di codice.

# Import the required libraries for model training
from sklearn.model_selection import train_test_split
from lightgbm import LGBMClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score, precision_score, confusion_matrix, recall_score, roc_auc_score, classification_report

Preparare i dati di training e convalida

Usare la funzione train_test_split da scikit-learn per suddividere i dati in set di training, convalida e test.

y = df_clean["Exited"]
X = df_clean.drop("Exited",axis=1)
# Split the dataset to 60%, 20%, 20% for training, validation, and test datasets
# Train-Test Separation
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=SEED)
# Train-Validation Separation
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=SEED)

Salvare i dati di test in una tabella delta

Salvare i dati di test nella tabella delta da usare nel notebook successivo.

table_name = "df_test"
# Create PySpark DataFrame from Pandas
df_test=spark.createDataFrame(X_test)
df_test.write.mode("overwrite").format("delta").save(f"Tables/{table_name}")
print(f"Spark test DataFrame saved to delta table: {table_name}")

Applicare SMOTE ai dati di training per sintetizzare nuovi esempi per la classe di minoranza

L'esplorazione dei dati nella parte 2 ha mostrato che dei 10.000 punti dati corrispondenti a 10.000 clienti, solo 2.037 clienti (circa il 20%) hanno lasciato la banca. Ciò indica che il set di dati è altamente sbilanciato. Il problema della classificazione sbilanciata è che ci sono troppi esempi della classe di minoranza per un modello per apprendere efficacemente il limite decisionale. SMOTE è l'approccio più diffuso per sintetizzare nuovi esempi per la classe di minoranza. Altre informazioni su SMOTE sono disponibili qui e qui.

Suggerimento

Si noti che SMOTE deve essere applicato solo al set di dati di training. È necessario lasciare il set di dati di test nella distribuzione originale sbilanciata per ottenere un'approssimazione valida del modo in cui il modello di Machine Learning eseguirà sui dati originali, che rappresenta la situazione nell'ambiente di produzione.

from collections import Counter
from imblearn.over_sampling import SMOTE

sm = SMOTE(random_state=SEED)
X_res, y_res = sm.fit_resample(X_train, y_train)
new_train = pd.concat([X_res, y_res], axis=1)

Suggerimento

È possibile ignorare in modo sicuro il messaggio di avviso MLflow visualizzato quando si esegue questa cella. Se viene visualizzato un messaggio ModuleNotFoundError, non è stata eseguita la prima cella in questo notebook, che installa la libreria imblearn. È necessario installare questa libreria ogni volta che si riavvia il notebook. Tornare indietro ed eseguire di nuovo tutte le celle a partire dalla prima cella di questo notebook.

Training del modello

  • Eseguire il training del modello usando Random Forest con una profondità massima di 4 e 4 funzionalità
mlflow.sklearn.autolog(registered_model_name='rfc1_sm') # Register the trained model with autologging
rfc1_sm = RandomForestClassifier(max_depth=4, max_features=4, min_samples_split=3, random_state=1) # Pass hyperparameters
with mlflow.start_run(run_name="rfc1_sm") as run:
    rfc1_sm_run_id = run.info.run_id # Capture run_id for model prediction later
    print("run_id: {}; status: {}".format(rfc1_sm_run_id, run.info.status))
    # rfc1.fit(X_train,y_train) # Imbalanaced training data
    rfc1_sm.fit(X_res, y_res.ravel()) # Balanced training data
    rfc1_sm.score(X_val, y_val)
    y_pred = rfc1_sm.predict(X_val)
    cr_rfc1_sm = classification_report(y_val, y_pred)
    cm_rfc1_sm = confusion_matrix(y_val, y_pred)
    roc_auc_rfc1_sm = roc_auc_score(y_res, rfc1_sm.predict_proba(X_res)[:, 1])
  • Eseguire il training del modello usando Random Forest con una profondità massima di 8 e 6 funzionalità
mlflow.sklearn.autolog(registered_model_name='rfc2_sm') # Register the trained model with autologging
rfc2_sm = RandomForestClassifier(max_depth=8, max_features=6, min_samples_split=3, random_state=1) # Pass hyperparameters
with mlflow.start_run(run_name="rfc2_sm") as run:
    rfc2_sm_run_id = run.info.run_id # Capture run_id for model prediction later
    print("run_id: {}; status: {}".format(rfc2_sm_run_id, run.info.status))
    # rfc2.fit(X_train,y_train) # Imbalanced training data
    rfc2_sm.fit(X_res, y_res.ravel()) # Balanced training data
    rfc2_sm.score(X_val, y_val)
    y_pred = rfc2_sm.predict(X_val)
    cr_rfc2_sm = classification_report(y_val, y_pred)
    cm_rfc2_sm = confusion_matrix(y_val, y_pred)
    roc_auc_rfc2_sm = roc_auc_score(y_res, rfc2_sm.predict_proba(X_res)[:, 1])
  • Eseguire il training del modello usando LightGBM
# lgbm_model
mlflow.lightgbm.autolog(registered_model_name='lgbm_sm') # Register the trained model with autologging
lgbm_sm_model = LGBMClassifier(learning_rate = 0.07, 
                        max_delta_step = 2, 
                        n_estimators = 100,
                        max_depth = 10, 
                        eval_metric = "logloss", 
                        objective='binary', 
                        random_state=42)

with mlflow.start_run(run_name="lgbm_sm") as run:
    lgbm1_sm_run_id = run.info.run_id # Capture run_id for model prediction later
    # lgbm_sm_model.fit(X_train,y_train) # Imbalanced training data
    lgbm_sm_model.fit(X_res, y_res.ravel()) # Balanced training data
    y_pred = lgbm_sm_model.predict(X_val)
    accuracy = accuracy_score(y_val, y_pred)
    cr_lgbm_sm = classification_report(y_val, y_pred)
    cm_lgbm_sm = confusion_matrix(y_val, y_pred)
    roc_auc_lgbm_sm = roc_auc_score(y_res, lgbm_sm_model.predict_proba(X_res)[:, 1])

Artefatto degli esperimenti per tenere traccia delle prestazioni del modello

Le esecuzioni dell'esperimento vengono salvate automaticamente nell'artefatto dell'esperimento che è possibile trovare dall'area di lavoro. Vengono denominati in base al nome usato per impostare l'esperimento. Vengono registrati tutti i modelli di Machine Learning sottoposti a training, le relative esecuzioni, le metriche delle prestazioni e i parametri del modello.

Per visualizzare gli esperimenti:

  1. Nel pannello a sinistra, selezionare l'area di lavoro.

  2. In alto a destra filtrare in modo da visualizzare solo gli esperimenti, per semplificare l'individuazione dell'esperimento che si sta cercando.

    Screenshot che mostra l'area di lavoro con il filtro esperimenti selezionato.

  3. Trovare e selezionare il nome dell'esperimento, in questo caso bank-churn-experiment. Se l'esperimento non viene visualizzato nell'area di lavoro, aggiornare il browser.

    Screenshot che mostra la pagina dell'esperimento per bank-churn-experiment.

Valutare le prestazioni dei modelli sottoposti a training nel set di dati di convalida

Al termine del training dei modelli di Machine Learning, è possibile valutare le prestazioni dei modelli sottoposti a training in due modi.

  • Aprire l'esperimento salvato dall'area di lavoro, caricare i modelli di Machine Learning e quindi valutare le prestazioni dei modelli caricati nel set di dati di convalida.

    # Define run_uri to fetch the model
    # mlflow client: mlflow.model.url, list model
    load_model_rfc1_sm = mlflow.sklearn.load_model(f"runs:/{rfc1_sm_run_id}/model")
    load_model_rfc2_sm = mlflow.sklearn.load_model(f"runs:/{rfc2_sm_run_id}/model")
    load_model_lgbm1_sm = mlflow.lightgbm.load_model(f"runs:/{lgbm1_sm_run_id}/model")
    # Assess the performance of the loaded model on validation dataset
    ypred_rfc1_sm_v1 = load_model_rfc1_sm.predict(X_val) # Random Forest with max depth of 4 and 4 features
    ypred_rfc2_sm_v1 = load_model_rfc2_sm.predict(X_val) # Random Forest with max depth of 8 and 6 features
    ypred_lgbm1_sm_v1 = load_model_lgbm1_sm.predict(X_val) # LightGBM
    
  • Valutare direttamente le prestazioni dei modelli di Machine Learning sottoposti a training nel set di dati di convalida.

    ypred_rfc1_sm_v2 = rfc1_sm.predict(X_val) # Random Forest with max depth of 4 and 4 features
    ypred_rfc2_sm_v2 = rfc2_sm.predict(X_val) # Random Forest with max depth of 8 and 6 features
    ypred_lgbm1_sm_v2 = lgbm_sm_model.predict(X_val) # LightGBM
    

A seconda della preferenza, entrambi gli approcci sono ottimi e dovrebbero offrire prestazioni identiche. In questo notebook si sceglierà il primo approccio per illustrare meglio le funzionalità di registrazione automatica di MLflow in Microsoft Fabric.

Mostra veri/falsi positivi/negativi usando la matrice di confusione

Successivamente, si svilupperà uno script per tracciare la matrice di confusione per valutare l'accuratezza della classificazione usando il set di dati di convalida. La matrice di confusione può essere tracciata anche usando gli strumenti SynapseML, come illustrato nell'esempio di rilevamento delle frodi disponibile qui.

import seaborn as sns
sns.set_theme(style="whitegrid", palette="tab10", rc = {'figure.figsize':(9,6)})
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from matplotlib import rc, rcParams
import numpy as np
import itertools

def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    print(cm)
    plt.figure(figsize=(4,4))
    plt.rcParams.update({'font.size': 10})
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45, color="blue")
    plt.yticks(tick_marks, classes, color="blue")

    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, format(cm[i, j], fmt),
                 horizontalalignment="center",
                 color="red" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
  • Matrice di confusione per il classificatore di Random Forest con profondità massima di 4 e 4 funzionalità
cfm = confusion_matrix(y_val, y_pred=ypred_rfc1_sm_v1)
plot_confusion_matrix(cfm, classes=['Non Churn','Churn'],
                      title='Random Forest with max depth of 4')
tn, fp, fn, tp = cfm.ravel()

Il grafico mostra la matrice di confusione per Random Forest con profondità massima pari a 4.

  • Matrice di confusione per il classificatore di Random Forest con profondità massima di 8 e 6 funzionalità
cfm = confusion_matrix(y_val, y_pred=ypred_rfc2_sm_v1)
plot_confusion_matrix(cfm, classes=['Non Churn','Churn'],
                      title='Random Forest with max depth of 8')
tn, fp, fn, tp = cfm.ravel()

Il grafico mostra la matrice di confusione per Random Forest con profondità massima pari a 8.

  • Matrice di confusione per LightGBM
cfm = confusion_matrix(y_val, y_pred=ypred_lgbm1_sm_v1)
plot_confusion_matrix(cfm, classes=['Non Churn','Churn'],
                      title='LightGBM')
tn, fp, fn, tp = cfm.ravel()

Il grafico mostra la matrice di confusione per LightGBM.

Passaggio successivo