Registrazione di modelli MLflow

Questo articolo descrive come registrare i modelli sottoposti a training (o artefatti) come modelli MLflow. Esplora i diversi modi per personalizzare la modalità con cui MLflow crea pacchetti dei modelli e la modalità con cui esegue tali modelli.

Perché registrare modelli anziché artefatti?

Da artefatti a modelli in MLflow descrive la differenza tra artefatti o file di registrazione e la registrazione di modelli MLflow.

Anche un modello MLflow è un artefatto. Tale modello, tuttavia, ha una struttura specifica che funge da contratto tra la persona che ha creato il modello e la persona che intende usarlo. Questo contratto consente di creare un ponte tra gli artefatti stessi e i loro significati.

La registrazione di modelli presenta questi vantaggi:

  • È possibile caricare direttamente i modelli, per l'inferenza, con mlflow.<flavor>.load_model, ed è possibile usare la funzione predict
  • Gli input della pipeline possono usare direttamente i modelli
  • È possibile distribuire modelli senza l’indicazione di uno script di assegnazione dei punteggi o di un ambiente
  • Swagger viene abilitato automaticamente negli endpoint distribuiti e Azure Machine Learning Studio può usare la funzionalità Test
  • È possibile usare il dashboard di intelligenza artificiale responsabile

Questa sezione descrive come usare il concetto del modello in Azure Machine Learning con MLflow:

Registrazione di modelli con il log automatico

È possibile usare la funzionalità di log automatico di MLflow. Il log automatico consente a MLflow di indicare al framework in uso di registrare tutte le metriche, i parametri, gli artefatti e i modelli che il framework considera pertinenti. Per impostazione predefinita, se è abilitato il log automatico viene registrata la maggior parte dei modelli. In alcune situazioni, alcune versioni potrebbero non registrare un modello. Ad esempio, la versione PySpark non registra modelli che superano una determinata dimensione.

Usare mlflow.autolog() o mlflow.<flavor>.autolog() per attivare la registrazione automatica. Questo esempio usa autolog() per registrare un modello di classificatore sottoposto a training con XGBoost:

import mlflow
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score

mlflow.autolog()

model = XGBClassifier(use_label_encoder=False, eval_metric="logloss")
model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)

y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)

Suggerimento

Se si usano pipeline di Machine Learning, ad esempio pipeline Scikit-Learn, usare la funzionalità autolog di tale versione della pipeline per registrare i modelli. La registrazione del modello avviene automaticamente quando viene richiamato il metodo fit() sull'oggetto pipeline. Training e rilevamento di un classificatore XGBoost con il notebook MLflow illustra come registrare un modello con la pre-elaborazione, usando le pipeline.

Registrazione di modelli con firma, ambiente o esempi personalizzati

Il metodo MLflow mlflow.<flavor>.log_model può registrare manualmente i modelli. Questo flusso di lavoro può controllare diversi aspetti della registrazione del modello.

Usare questo metodo nei casi seguenti:

  • Si desidera indicare pacchetti pip o un ambiente conda che differisce da quelli rilevati automaticamente
  • Si desidera includere esempi di input
  • Si desidera includere artefatti specifici nel pacchetto necessario
  • autolog non inferisce correttamente la firma. Questo aspetto è importante quando si gestiscono input tensor in cui la firma richiede forme specifiche
  • Il comportamento della registrazione automatica non copre lo scopo per qualche motivo

Questo esempio di codice registra un modello per un classificatore XGBoost:

import mlflow
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score
from mlflow.models import infer_signature
from mlflow.utils.environment import _mlflow_conda_env

mlflow.autolog(log_models=False)

model = XGBClassifier(use_label_encoder=False, eval_metric="logloss")
model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)
y_pred = model.predict(X_test)

accuracy = accuracy_score(y_test, y_pred)

# Signature
signature = infer_signature(X_test, y_test)

# Conda environment
custom_env =_mlflow_conda_env(
    additional_conda_deps=None,
    additional_pip_deps=["xgboost==1.5.2"],
    additional_conda_channels=None,
)

# Sample
input_example = X_train.sample(n=1)

# Log the model manually
mlflow.xgboost.log_model(model, 
                         artifact_path="classifier", 
                         conda_env=custom_env,
                         signature=signature,
                         input_example=input_example)

Nota

  • autolog ha la configurazione log_models=False. Ciò impedisce la registrazione automatica del modello MLflow. La registrazione automatica del modello MLflow avviene in un secondo momento, come processo manuale
  • Usare il metodo infer_signature per provare a inferire la firma direttamente da input e output
  • Il metodo mlflow.utils.environment._mlflow_conda_env è un metodo privato nell’SDK MLflow. In questo esempio il codice risulta più semplice, ma è preferibile usarlo con cautela. In futuro potrebbe cambiare. In alternativa, è possibile generare manualmente la definizione YAML come dizionario Python.

Registrazione di modelli con un comportamento diverso nel metodo di stima

Quando si registra un modello con mlflow.autolog o mlflow.<flavor>.log_model, la versione del modello determina come eseguire l'inferenza e il risultato restituito dal modello. MLflow non applica alcun comportamento specifico sulla generazione di risultati predict. In alcuni scenari è possibile eseguire alcune operazioni di pre-elaborazione o post-elaborazione prima e dopo l'esecuzione del modello.

In questo caso, implementare pipeline di Machine Learning che passano direttamente dagli input agli output. Anche se questa implementazione è possibile e talvolta è preferibile per migliorare le prestazioni, potrebbe diventare difficile da ottenere. In questi casi può essere utile personalizzare il modo in cui il modello gestisce l'inferenza, come illustrato nella sezione successiva.

Registrazione di modelli personalizzati

MLflow supporta numerosi framework di Machine Learning, tra cui

  • CatBoost
  • FastAI
  • h2o
  • Keras
  • LightGBM
  • MLeap
  • MXNet Gluon
  • ONNX
  • Prophet
  • PyTorch
  • Scikit-Learn
  • spaCy
  • Spark MLLib
  • statsmodels
  • TensorFlow
  • XGBoost

Tuttavia, potrebbe essere necessario modificare il funzionamento di una versione, registrare un modello non supportato in modo nativo da MLflow o anche registrare un modello che usa più elementi di framework diversi. In questi casi potrebbe essere necessario creare una versione del modello personalizzato.

Per risolvere il problema, MLflow introduce la versione pyfunc (a partire da una funzione Python). Questa versione può registrare qualunque oggetto come modello, purché tale oggetto soddisfi due condizioni:

  • Si implementa almeno il metodo predict
  • L'oggetto Python eredita da mlflow.pyfunc.PythonModel

Suggerimento

I modelli serializzabili che implementano l'API Scikit-learn possono usare la versione Scikit-learn per registrare il modello, indipendentemente dal fatto che il modello sia stato generato con Scikit-learn. Se è possibile rendere persistente il modello in formato Pickle e l'oggetto ha almeno i metodi predict() e predict_proba(), è possibile usare mlflow.sklearn.log_model() per registrare il modello all'interno di un'esecuzione MLflow.

Se si crea un wrapper per l'oggetto modello esistente, diventa il più semplice creare una versione per il modello personalizzato. MLflow lo serializza e ne crea automaticamente un pacchetto. Gli oggetti Python sono serializzabili quando l'oggetto può essere archiviato nel file system come file, generalmente in formato Pickle. Nel runtime, l'oggetto può materializzarsi da tale file. In questo modo vengono ripristinati tutti i valori, le proprietà e i metodi che erano disponibili quando è stato salvato.

Usare questo metodo nei casi seguenti:

  • È possibile serializzare il modello in formato Pickle
  • Si desidera mantenere lo stato del modello inalterato così com’era dopo il training
  • Si desidera personalizzare il funzionamento della funzione predict.

Questo esempio di codice esegue il wrapping di un modello creato con XGBoost affinché si comporti diversamente dall'implementazione predefinita di XGBoost flavor. Restituisce, invece, le probabilità anziché le classi:

from mlflow.pyfunc import PythonModel, PythonModelContext

class ModelWrapper(PythonModel):
    def __init__(self, model):
        self._model = model

    def predict(self, context: PythonModelContext, data):
        # You don't have to keep the semantic meaning of `predict`. You can use here model.recommend(), model.forecast(), etc
        return self._model.predict_proba(data)

    # You can even add extra functions if you need to. Since the model is serialized,
    # all of them will be available when you load your model back.
    def predict_batch(self, data):
        pass

Registrare un modello personalizzato nell'esecuzione:

import mlflow
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score
from mlflow.models import infer_signature

mlflow.xgboost.autolog(log_models=False)

model = XGBClassifier(use_label_encoder=False, eval_metric="logloss")
model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)
y_probs = model.predict_proba(X_test)

accuracy = accuracy_score(y_test, y_probs.argmax(axis=1))
mlflow.log_metric("accuracy", accuracy)

signature = infer_signature(X_test, y_probs)
mlflow.pyfunc.log_model("classifier", 
                        python_model=ModelWrapper(model),
                        signature=signature)

Suggerimento

In questo caso, il metodo infer_signature usa y_probs per inferire la firma. La colonna di destinazione ha la classe di destinazione, ma il modello ora restituisce le due probabilità per ogni classe.

Passaggi successivi