Eseguire il training di modelli scikit-learn su larga scala con Azure Machine Learning

SI APPLICA A: Python SDK azure-ai-ml v2 (corrente)

Questo articolo illustra come eseguire gli script di training scikit-learn con Azure Machine Learning Python SDK v2.

Gli script di esempio in questo articolo vengono usati per classificare le immagini dei fiori iris per creare un modello di Machine Learning basato sul set di dati iris di scikit-learn.

Sia che si stia eseguendo il training di un modello scikit-learn di Machine Learning da zero o si stia portando un modello esistente nel cloud, è possibile usare Azure Machine Learning per aumentare il numero di processi di training open source usando risorse di calcolo cloud elastiche. È possibile compilare, distribuire, versione e monitorare i modelli di livello di produzione con Azure Machine Learning.

Prerequisiti

È possibile eseguire il codice per questo articolo in un'istanza di calcolo di Azure Machine Learning o nel proprio Jupyter Notebook.

  • Istanza di calcolo di Azure Machine Learning

    • Completare l'avvio rapido: Introduzione ad Azure Machine Learning per creare un'istanza di calcolo. Ogni istanza di calcolo include un server notebook dedicato precaricato con l'SDK e il repository di esempio dei notebook.
    • Selezionare la scheda notebook nel studio di Azure Machine Learning. Nella cartella di training degli esempi trovare un notebook completato ed espanso passando a questa directory: v2 > sdk > jobs > single-step > scikit-learn > train-hyperparameter-tune-deploy-with-sklearn.
    • Per completare questa esercitazione, è possibile usare il codice prepopolato nella cartella di training di esempio.
  • Server Jupyter Notebook.

Configurare il processo

Questa sezione configura il processo per il training caricando i pacchetti Python necessari, connettendosi a un'area di lavoro, creando una risorsa di calcolo per eseguire un processo di comando e creando un ambiente per eseguire il processo.

Connettersi all'area di lavoro

Prima di tutto, è necessario connettersi all'area di lavoro di AzureML. L'area di lavoro di AzureML è la risorsa di primo livello per il servizio. Offre una posizione centralizzata per lavorare con tutti gli artefatti creati quando si usa Azure Machine Learning.

Viene usato DefaultAzureCredential per ottenere l'accesso all'area di lavoro. Questa credenziale deve essere in grado di gestire la maggior parte degli scenari di autenticazione di Azure SDK.

Se DefaultAzureCredential non funziona, vedere azure-identity reference documentation o Set up authentication per altre credenziali disponibili.

# Handle to the workspace
from azure.ai.ml import MLClient

# Authentication package
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()

Se si preferisce usare un browser per accedere ed eseguire l'autenticazione, è necessario rimuovere i commenti nel codice seguente e usarlo.

# Handle to the workspace
# from azure.ai.ml import MLClient

# Authentication package
# from azure.identity import InteractiveBrowserCredential
# credential = InteractiveBrowserCredential()

Ottenere quindi un handle nell'area di lavoro specificando l'ID sottoscrizione, il nome del gruppo di risorse e il nome dell'area di lavoro. Per trovare questi parametri:

  1. Cercare nell'angolo in alto a destra della barra degli strumenti studio di Azure Machine Learning il nome dell'area di lavoro.
  2. Selezionare il nome dell'area di lavoro per visualizzare il gruppo di risorse e l'ID sottoscrizione.
  3. Copiare i valori per Gruppo di risorse e ID sottoscrizione nel codice.
# Get a handle to the workspace
ml_client = MLClient(
    credential=credential,
    subscription_id="<SUBSCRIPTION_ID>",
    resource_group_name="<RESOURCE_GROUP>",
    workspace_name="<AML_WORKSPACE_NAME>",
)

Il risultato dell'esecuzione di questo script è un handle dell'area di lavoro che verrà usato per gestire altre risorse e processi.

Nota

La creazione MLClient non connetterà il client all'area di lavoro. L'inizializzazione del client è differita e attenderà la prima volta che deve effettuare una chiamata. In questo articolo questo problema verrà eseguito durante la creazione del calcolo.

Creare una risorsa di calcolo per eseguire il processo

AzureML richiede una risorsa di calcolo per eseguire un processo. Questa risorsa può essere un computer a nodo singolo o multinodo con sistema operativo Linux o Windows o un'infrastruttura di calcolo specifica, ad esempio Spark.

Nello script di esempio seguente viene effettuato il provisioning di un linux compute cluster. È possibile visualizzare la Azure Machine Learning pricing pagina per l'elenco completo delle dimensioni e dei prezzi delle macchine virtuali. Per questo esempio è necessario solo un cluster di base. verrà quindi scelto un modello di Standard_DS3_v2 con 2 core vCPU e 7 GB di RAM per creare un ambiente di calcolo AzureML.

from azure.ai.ml.entities import AmlCompute

# Name assigned to the compute cluster
cpu_compute_target = "cpu-cluster"

try:
    # let's see if the compute target already exists
    cpu_cluster = ml_client.compute.get(cpu_compute_target)
    print(
        f"You already have a cluster named {cpu_compute_target}, we'll reuse it as is."
    )

except Exception:
    print("Creating a new cpu compute target...")

    # Let's create the Azure ML compute object with the intended parameters
    cpu_cluster = AmlCompute(
        name=cpu_compute_target,
        # Azure ML Compute is the on-demand VM service
        type="amlcompute",
        # VM Family
        size="STANDARD_DS3_V2",
        # Minimum running nodes when there is no job running
        min_instances=0,
        # Nodes in cluster
        max_instances=4,
        # How many seconds will the node running after the job termination
        idle_time_before_scale_down=180,
        # Dedicated or LowPriority. The latter is cheaper but there is a chance of job termination
        tier="Dedicated",
    )

    # Now, we pass the object to MLClient's create_or_update method
    cpu_cluster = ml_client.compute.begin_create_or_update(cpu_cluster).result()

print(
    f"AMLCompute with name {cpu_cluster.name} is created, the compute size is {cpu_cluster.size}"
)

Creare un ambiente di processo

Per eseguire un processo AzureML, è necessario un ambiente. Un ambiente AzureML incapsula le dipendenze( ad esempio il runtime software e le librerie) necessarie per eseguire lo script di training di Machine Learning nella risorsa di calcolo. Questo ambiente è simile a un ambiente Python nel computer locale.

AzureML consente di usare un ambiente curato (o pronto) o di creare un ambiente personalizzato usando un'immagine Docker o una configurazione Conda. In questo articolo si creerà un ambiente personalizzato per i processi usando un file YAML Conda.

Creare un ambiente personalizzato

Per creare l'ambiente personalizzato, si definiranno le dipendenze Conda in un file YAML. Creare prima di tutto una directory per l'archiviazione del file. In questo esempio è stata denominata la directory env.

import os

dependencies_dir = "./env"
os.makedirs(dependencies_dir, exist_ok=True)

Creare quindi il file nella directory dependencies. In questo esempio è stato denominato il file conda.yml.

%%writefile {dependencies_dir}/conda.yml
name: sklearn-env
channels:
  - conda-forge
dependencies:
  - python=3.8
  - pip=21.2.4
  - scikit-learn=0.24.2
  - scipy=1.7.1
  - pip:  
    - mlflow== 1.26.1
    - azureml-mlflow==1.42.0

La specifica contiene alcuni pacchetti consueti (ad esempio numpy e pip) che verranno usati nel processo.

Usare quindi il file YAML per creare e registrare questo ambiente personalizzato nell'area di lavoro. L'ambiente verrà inserito in un contenitore Docker in fase di esecuzione.

from azure.ai.ml.entities import Environment

custom_env_name = "sklearn-env"

job_env = Environment(
    name=custom_env_name,
    description="Custom environment for sklearn image classification",
    conda_file=os.path.join(dependencies_dir, "conda.yml"),
    image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest",
)
job_env = ml_client.environments.create_or_update(job_env)

print(
    f"Environment with name {job_env.name} is registered to workspace, the environment version is {job_env.version}"
)

Per altre informazioni sulla creazione e l'uso di ambienti, vedere Creare e usare ambienti software in Azure Machine Learning.

Configurare e inviare il processo di training

In questa sezione verrà illustrato come eseguire un processo di training usando uno script di training fornito. Per iniziare, si compilerà il processo di training configurando il comando per l'esecuzione dello script di training. Si invierà quindi il processo di training da eseguire in AzureML.

Preparare lo script di training

In questo articolo è stato fornito lo script di training train_iris.py. In pratica, dovrebbe essere possibile eseguire qualsiasi script di training personalizzato così come è ed eseguirlo con AzureML senza dover modificare il codice.

Nota

Lo script di training fornito esegue le operazioni seguenti:

  • illustra come registrare alcune metriche nell'esecuzione di AzureML;
  • scarica ed estrae i dati di training usando iris = datasets.load_iris(); e
  • esegue il training di un modello, quindi lo salva e lo registra.

Per usare e accedere ai propri dati, vedere come leggere e scrivere dati in un processo per rendere disponibili i dati durante il training.

Per usare lo script di training, creare prima di tutto una directory in cui archiviare il file.

import os

src_dir = "./src"
os.makedirs(src_dir, exist_ok=True)

Creare quindi il file di script nella directory di origine.

%%writefile {src_dir}/train_iris.py
# Modified from https://www.geeksforgeeks.org/multiclass-classification-using-scikit-learn/

import argparse
import os

# importing necessary libraries
import numpy as np

from sklearn import datasets
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split

import joblib

import mlflow
import mlflow.sklearn

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('--kernel', type=str, default='linear',
                        help='Kernel type to be used in the algorithm')
    parser.add_argument('--penalty', type=float, default=1.0,
                        help='Penalty parameter of the error term')

    # Start Logging
    mlflow.start_run()

    # enable autologging
    mlflow.sklearn.autolog()

    args = parser.parse_args()
    mlflow.log_param('Kernel type', str(args.kernel))
    mlflow.log_metric('Penalty', float(args.penalty))

    # loading the iris dataset
    iris = datasets.load_iris()

    # X -> features, y -> label
    X = iris.data
    y = iris.target

    # dividing X, y into train and test data
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

    # training a linear SVM classifier
    from sklearn.svm import SVC
    svm_model_linear = SVC(kernel=args.kernel, C=args.penalty)
    svm_model_linear = svm_model_linear.fit(X_train, y_train)
    svm_predictions = svm_model_linear.predict(X_test)

    # model accuracy for X_test
    accuracy = svm_model_linear.score(X_test, y_test)
    print('Accuracy of SVM classifier on test set: {:.2f}'.format(accuracy))
    mlflow.log_metric('Accuracy', float(accuracy))
    # creating a confusion matrix
    cm = confusion_matrix(y_test, svm_predictions)
    print(cm)

    registered_model_name="sklearn-iris-flower-classify-model"

    ##########################
    #<save and register model>
    ##########################
    # Registering the model to the workspace
    print("Registering the model via MLFlow")
    mlflow.sklearn.log_model(
        sk_model=svm_model_linear,
        registered_model_name=registered_model_name,
        artifact_path=registered_model_name
    )

    # # Saving the model to a file
    print("Saving the model via MLFlow")
    mlflow.sklearn.save_model(
        sk_model=svm_model_linear,
        path=os.path.join(registered_model_name, "trained_model"),
    )
    ###########################
    #</save and register model>
    ###########################
    mlflow.end_run()

if __name__ == '__main__':
    main()

Compilare il processo di training

Ora che sono disponibili tutti gli asset necessari per eseguire il processo, è possibile compilarlo usando AzureML Python SDK v2. A questo scopo, verrà creato un oggetto command.

AzureML command è una risorsa che specifica tutti i dettagli necessari per eseguire il codice di training nel cloud. Questi dettagli includono gli input e gli output, il tipo di hardware da usare, il software da installare e come eseguire il codice. Contiene command informazioni per eseguire un singolo comando.

Configurare il comando

Si userà lo scopo command generico per eseguire lo script di training ed eseguire le attività desiderate. Creare un Command oggetto per specificare i dettagli di configurazione del processo di training.

  • Gli input per questo comando includono il numero di periodi, frequenza di apprendimento, slancio e directory di output.
  • Per i valori dei parametri:
    • specificare il cluster cpu_compute_target = "cpu-cluster" di calcolo creato per l'esecuzione di questo comando;
    • fornire l'ambiente sklearn-env personalizzato creato per l'esecuzione del processo AzureML;
    • configurare l'azione della riga di comando stessa, in questo caso il comando è python train_iris.py. È possibile accedere agli input e agli output nel comando tramite la ${{ ... }} notazione; e
    • configurare i metadati, ad esempio il nome visualizzato e il nome dell'esperimento; dove un esperimento è un contenitore per tutte le iterazioni eseguite in un determinato progetto. Si noti che tutti i processi inviati con lo stesso nome dell'esperimento verranno elencati uno accanto all'altro in AzureML Studio.
from azure.ai.ml import command
from azure.ai.ml import Input

job = command(
    inputs=dict(kernel="linear", penalty=1.0),
    compute=cpu_compute_target,
    environment=f"{job_env.name}:{job_env.version}",
    code="./src/",
    command="python train_iris.py --kernel ${{inputs.kernel}} --penalty ${{inputs.penalty}}",
    experiment_name="sklearn-iris-flowers",
    display_name="sklearn-classify-iris-flower-images",
)

Inviare il processo

È ora possibile inviare il processo per l'esecuzione in AzureML. Questa volta si userà create_or_update in ml_client.jobs.

ml_client.jobs.create_or_update(job)

Al termine, il processo registrerà un modello nell'area di lavoro (in seguito al training) e restituirà un collegamento per visualizzare il processo in AzureML Studio.

Avviso

Azure Machine Learning esegue script di training copiando l'intera directory di origine. Se si dispone di dati sensibili che non si desidera caricare, usare un file con estensione ignore o non includerlo nella directory di origine.

Cosa accade durante l'esecuzione del processo

Durante l'esecuzione del processo, vengono eseguite le fasi seguenti:

  • Preparazione: viene creata un'immagine Docker in base all'ambiente definito. L'immagine viene caricata nel registro contenitori dell'area di lavoro e memorizzata nella cache per le esecuzioni successive. I log vengono trasmessi anche alla cronologia di esecuzione e possono essere visualizzati per monitorare lo stato di avanzamento. Se viene specificato un ambiente curato, verrà usato il backup dell'immagine memorizzata nella cache dell'ambiente curato.

  • Ridimensionamento: il cluster tenta di aumentare le prestazioni se il cluster richiede più nodi per eseguire l'esecuzione rispetto a quelli attualmente disponibili.

  • In esecuzione: tutti gli script nella cartella script src vengono caricati nella destinazione di calcolo, gli archivi dati vengono montati o copiati e lo script viene eseguito. Gli output da stdout e la cartella ./logs vengono trasmessi alla cronologia di esecuzione e possono essere usati per monitorare l'esecuzione.

Ottimizzare gli iperparametri del modello

Ora che si è visto come eseguire un semplice training Scikit-learn usando l'SDK, è possibile verificare se è possibile migliorare ulteriormente l'accuratezza del modello. È possibile ottimizzare e ottimizzare gli iperparametri del modello usando le funzionalità di sweep Azure Machine Learning.

Per ottimizzare gli iperparametri del modello, definire lo spazio dei parametri in cui eseguire la ricerca durante il training. A tale scopo, sostituire alcuni dei parametri (kernel e penalty) passati al processo di training con input speciali del azure.ml.sweep pacchetto.

from azure.ai.ml.sweep import Choice

# we will reuse the command_job created before. we call it as a function so that we can apply inputs
# we do not apply the 'iris_csv' input again -- we will just use what was already defined earlier
job_for_sweep = job(
    kernel=Choice(values=["linear", "rbf", "poly", "sigmoid"]),
    penalty=Choice(values=[0.5, 1, 1.5]),
)

Si configurerà quindi lo sweep nel processo di comando, usando alcuni parametri specifici dello sweep, ad esempio la metrica primaria da controllare e l'algoritmo di campionamento da usare.

Nel codice seguente viene usato il campionamento casuale per provare diversi set di configurazioni di iperparametri nel tentativo di ottimizzare la metrica primaria, Accuracy.

sweep_job = job_for_sweep.sweep(
    compute="cpu-cluster",
    sampling_algorithm="random",
    primary_metric="Accuracy",
    goal="Maximize",
    max_total_trials=12,
    max_concurrent_trials=4,
)

È ora possibile inviare questo processo come in precedenza. Questa volta si eseguirà un processo di sweep che scorre il processo di training.

returned_sweep_job = ml_client.create_or_update(sweep_job)

# stream the output and wait until the job is finished
ml_client.jobs.stream(returned_sweep_job.name)

# refresh the latest status of the job after streaming
returned_sweep_job = ml_client.jobs.get(name=returned_sweep_job.name)

È possibile monitorare il processo usando il collegamento dell'interfaccia utente di Studio presentato durante l'esecuzione del processo.

Trovare e registrare il modello migliore

Al termine di tutte le esecuzioni, è possibile trovare l'esecuzione che ha prodotto il modello con la massima accuratezza.

from azure.ai.ml.entities import Model

if returned_sweep_job.status == "Completed":

    # First let us get the run which gave us the best result
    best_run = returned_sweep_job.properties["best_child_run_id"]

    # lets get the model from this run
    model = Model(
        # the script stores the model as "sklearn-iris-flower-classify-model"
        path="azureml://jobs/{}/outputs/artifacts/paths/sklearn-iris-flower-classify-model/".format(
            best_run
        ),
        name="run-model-example",
        description="Model created from run.",
        type="custom_model",
    )

else:
    print(
        "Sweep job status: {}. Please wait until it completes".format(
            returned_sweep_job.status
        )
    )

È quindi possibile registrare questo modello.

registered_model = ml_client.models.create_or_update(model=model)

Distribuire il modello

Dopo aver registrato il modello, è possibile distribuirlo allo stesso modo di qualsiasi altro modello registrato in Azure ML. Per altre informazioni sulla distribuzione, vedere Distribuire e assegnare punteggi a un modello di Machine Learning con endpoint online gestito con Python SDK v2.

Passaggi successivi

In questo articolo è stato eseguito il training e la registrazione di un modello scikit-learn e sono state apprese le opzioni di distribuzione. Per altre informazioni su Azure Machine Learning, vedere questi altri articoli.