Condividi tramite


Esercitazione: Creare una pipeline di Azure Machine Learning per la classificazione delle immagini

SI APPLICA A:Python SDK azureml v1

Nota

Per un'esercitazione che utilizza SDK v2 per creare una pipeline, vedere Esercitazione: Utilizzare pipeline ML per flussi di lavoro ML di produzione con Python SDK v2 in un Jupyter Notebook.

In questa esercitazione, verrà illustrato come compilare una pipeline di Azure Machine Learning per preparare i dati ed eseguire il training di un modello di Machine Learning. Le pipeline di Machine Learning ottimizzano il flusso di lavoro offrendo velocità, portabilità e possibilità di riutilizzo per consentire così di concentrarsi su Machine Learning anziché sull'infrastruttura e l'automazione.

Nell'esempio viene addestrata una piccola rete neurale convoluzionale Keras per classificare le immagini nel set di dati Fashion MNIST.

In questa esercitazione si completano le attività seguenti:

  • Configurare l'area di lavoro
  • Creare un esperimento per sostenere il lavoro
  • Fornire un ComputeTarget per svolgere il lavoro
  • Creare un set di dati in cui memorizzare i dati compressi
  • Creare una fase della pipeline per preparare i dati per il training
  • Definire un ambiente runtime in cui eseguire il training
  • Creare un passaggio della pipeline per definire la rete neurale ed eseguire il training
  • Comporre una pipeline dalle relative fasi
  • Eseguire la pipeline nell'esperimento
  • Rivedere l'output dei passaggi e la rete neurale addestrata
  • Registrare il modello per un ulteriore utilizzo

Se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare. Provare la versione gratuita o a pagamento di Azure Machine Learning.

Prerequisiti

  • Completare Creare risorse per iniziare se non si dispone già di un'area di lavoro Azure Machine Learning.
  • Un ambiente Python in cui sono stati installati entrambi i pacchetti azureml-core e azureml-pipeline. Questo ambiente serve per definire e controllare le risorse di Azure Machine Learning ed è separato dall'ambiente utilizzato in fase di esecuzione per il training.

Importante

Attualmente, la versione più recente di Python compatibile con azureml-pipeline è Python 3.8. Se si ha difficoltà a installare il pacchetto azureml-pipeline, assicurarsi che python --version sia una versione compatibile. Consultare la documentazione del gestore dell'ambiente virtuale Python (venv, conda, e così via) per le istruzioni.

Avviare una sessione Python interattiva

Questa esercitazione utilizza Python SDK per Azure Machine Learning per creare e controllare una pipeline di Azure Machine Learning. L'esercitazione presuppone che i frammenti di codice vengano eseguiti in modo interattivo in un ambiente Python REPL o in un notebook Jupyter.

  • Questa esercitazione si basa sul notebook image-classification.ipynb disponibile nella directory python-sdk/tutorial/using-pipelines del repository Esempi di Azure Machine Learning. Il codice sorgente per le varie fasi si trova nella sottodirectory keras-mnist-fashion.

Tipi di importazione

Importare tutti i tipi di Azure Machine Learning necessari per questa esercitazione:

import os
import azureml.core
from azureml.core import (
    Workspace,
    Experiment,
    Dataset,
    Datastore,
    ComputeTarget,
    Environment,
    ScriptRunConfig
)
from azureml.data import OutputFileDatasetConfig
from azureml.core.compute import AmlCompute
from azureml.core.compute_target import ComputeTargetException
from azureml.pipeline.steps import PythonScriptStep
from azureml.pipeline.core import Pipeline

# check core SDK version number
print("Azure Machine Learning SDK Version: ", azureml.core.VERSION)

La versione di Azure Machine Learning SDK deve essere 1.37 o successiva. In caso contrario, eseguire l'upgrade con pip install --upgrade azureml-core.

Configurare l'area di lavoro

Creare un oggetto area di lavoro dall'area di lavoro di Azure Machine Learning esistente.

workspace = Workspace.from_config()

Importante

Questo frammento di codice prevede che la configurazione dell'area di lavoro sia salvata nella directory corrente o nella relativa directory padre. Per ulteriori informazioni sulla creazione di uno spazio di lavoro, vedere Creare risorse dell'area di lavoro . Per altre informazioni sul salvataggio della configurazione in un file, vedere Creare un file di configurazione dell'area di lavoro.

Creare l'infrastruttura per la pipeline

Creare un oggetto Experiment per contenere i risultati delle esecuzioni della pipeline:

exp = Experiment(workspace=workspace, name="keras-mnist-fashion")

Creare un oggetto ComputeTarget che rappresenti la risorsa macchina su cui verrà eseguita la pipeline. La semplice rete neurale utilizzata in questo tutorial viene addestrata in pochi minuti anche su una macchina basata su CPU. Se si desidera utilizzare una GPU per il training, impostare use_gpu su True. Il provisioning di una destinazione di calcolo richiede generalmente circa cinque minuti.

use_gpu = False

# choose a name for your cluster
cluster_name = "gpu-cluster" if use_gpu else "cpu-cluster"

found = False
# Check if this compute target already exists in the workspace.
cts = workspace.compute_targets
if cluster_name in cts and cts[cluster_name].type == "AmlCompute":
    found = True
    print("Found existing compute target.")
    compute_target = cts[cluster_name]
if not found:
    print("Creating a new compute target...")
    compute_config = AmlCompute.provisioning_configuration(
        vm_size= "STANDARD_NC6" if use_gpu else "STANDARD_D2_V2"
        # vm_priority = 'lowpriority', # optional
        max_nodes=4,
    )

    # Create the cluster.
    compute_target = ComputeTarget.create(workspace, cluster_name, compute_config)

    # Can poll for a minimum number of nodes and for a specific timeout.
    # If no min_node_count is provided, it will use the scale settings for the cluster.
    compute_target.wait_for_completion(
        show_output=True, min_node_count=None, timeout_in_minutes=10
    )
# For a more detailed view of current AmlCompute status, use get_status().print(compute_target.get_status().serialize())

Nota

La disponibilità della GPU dipende dalla quota della sottoscrizione di Azure e dalla capacità di Azure. Vedere Gestire e aumentare le quote per le risorse con Azure Machine Learning.

Creare un set di dati per i dati archiviati in Azure

Fashion-MNIST è un set di dati di immagini di moda suddiviso in 10 classi. Ogni immagine è un'immagine in scala di grigi 28x28 ed esistono 60.000 immagini per il training e 10.000 immagini per i test. Come problema di classificazione delle immagini, Fashion-MNIST è più difficile del classico database di cifre scritte a mano MNIST. È distribuito nella stessa forma binaria compressa del database di cifre scritto a mano originale.

Per creare un oggetto Dataset che faccia riferimento ai dati basati sul Web, eseguire:

data_urls = ["https://data4mldemo6150520719.blob.core.windows.net/demo/mnist-fashion"]
fashion_ds = Dataset.File.from_files(data_urls)

# list the files referenced by fashion_ds
print(fashion_ds.to_path())

Questo codice viene completato rapidamente. I dati sottostanti rimangono nella risorsa di archiviazione di Azure specificata nella matrice data_urls.

Creare la fase della pipeline di preparazione dei dati

Nella prima fase di questa pipeline i file di dati compressi di fashion_ds verranno convertiti in un set di dati nell'area di lavoro costituita da file CSV pronti per l'uso nel training. Una volta registrati nell'area di lavoro, i propri collaboratori possono accedere a questi dati per l'analisi, il training e così via

datastore = workspace.get_default_datastore()
prepared_fashion_ds = OutputFileDatasetConfig(
    destination=(datastore, "outputdataset/{run-id}")
).register_on_complete(name="prepared_fashion_ds")

Il codice specificato sopra indica un set di dati basato sull'output di una fase della pipeline. I file elaborati sottostanti verranno inseriti nell'archivio BLOB predefinito dell'area di lavoro nel percorso specificato in destination. Il set di dati verrà registrato nell'area di lavoro con il nome prepared_fashion_ds.

Creare l'origine della fase della pipeline

Il codice eseguito finora ha creato e controllato risorse di Azure. Ora è il momento di scrivere il codice che esegue la prima fase nel dominio.

Se si sta seguendo l'esempio nel repository Esempi di Azure Machine Learning, il file di origine è già disponibile come keras-mnist-fashion/prepare.py.

Se si sta lavorando da zero, creare una sottodirectory chiamata keras-mnist-fashion/. Creare un nuovo file, aggiungere il seguente codice e assegnare un nome al file prepare.py.

# prepare.py
# Converts MNIST-formatted files at the passed-in input path to a passed-in output path
import os
import sys

# Conversion routine for MNIST binary format
def convert(imgf, labelf, outf, n):
    f = open(imgf, "rb")
    l = open(labelf, "rb")
    o = open(outf, "w")

    f.read(16)
    l.read(8)
    images = []

    for i in range(n):
        image = [ord(l.read(1))]
        for j in range(28 * 28):
            image.append(ord(f.read(1)))
        images.append(image)

    for image in images:
        o.write(",".join(str(pix) for pix in image) + "\n")
    f.close()
    o.close()
    l.close()

# The MNIST-formatted source
mounted_input_path = sys.argv[1]
# The output directory at which the outputs will be written
mounted_output_path = sys.argv[2]

# Create the output directory
os.makedirs(mounted_output_path, exist_ok=True)

# Convert the training data
convert(
    os.path.join(mounted_input_path, "mnist-fashion/train-images-idx3-ubyte"),
    os.path.join(mounted_input_path, "mnist-fashion/train-labels-idx1-ubyte"),
    os.path.join(mounted_output_path, "mnist_train.csv"),
    60000,
)

# Convert the test data
convert(
    os.path.join(mounted_input_path, "mnist-fashion/t10k-images-idx3-ubyte"),
    os.path.join(mounted_input_path, "mnist-fashion/t10k-labels-idx1-ubyte"),
    os.path.join(mounted_output_path, "mnist_test.csv"),
    10000,
)

Il codice in prepare.py accetta due argomenti della riga di comando: il primo è assegnato a mounted_input_path e il secondo a mounted_output_path. Se quella sottodirectory non esiste, viene creata dalla chiamata a os.makedirs. Il programma converte quindi i dati di training e di test e invia i file separati da una virgola a mounted_output_path.

Specificare la fase della pipeline

Tornando all'ambiente Python che si sta utilizzando per specificare la pipeline, eseguire questo codice per creare un oggetto PythonScriptStep per il codice di preparazione:

script_folder = "./keras-mnist-fashion"

prep_step = PythonScriptStep(
    name="prepare step",
    script_name="prepare.py",
    # On the compute target, mount fashion_ds dataset as input, prepared_fashion_ds as output
    arguments=[fashion_ds.as_named_input("fashion_ds").as_mount(), prepared_fashion_ds],
    source_directory=script_folder,
    compute_target=compute_target,
    allow_reuse=True,
)

La chiamata a PythonScriptStep specifica che, quando viene eseguita la fase della pipeline:

  • Tutti i file nella directory script_folder vengono caricati nella directory compute_target
  • Tra i file di origine caricati, verrà eseguito il file prepare.py
  • I set di dati fashion_ds e prepared_fashion_ds verranno montati su compute_target e visualizzati come directory
  • Il percorso dei file fashion_ds sarà il primo argomento di prepare.py. In prepare.py, questo argomento è assegnato a mounted_input_path
  • Il percorso per prepared_fashion_ds sarà il secondo argomento per prepare.py. In prepare.py, questo argomento è assegnato a mounted_output_path
  • Poiché allow_reuse è True, non verrà rieseguito fino a quando i file di origine o gli input non cambieranno
  • PythonScriptStep verrà ridenominato prepare step

La modularità e il riutilizzo sono i principali vantaggi delle pipeline. Azure Machine Learning può determinare automaticamente il codice sorgente o le modifiche al set di dati. L'output di una fase che non è interessata verrà riutilizzato senza rieseguire nuovamente le fasi se allow_reuse è True. Se una fase si basa su un'origine dati esterna ad Azure Machine Learning che potrebbe cambiare (ad esempio, un URL che contiene dati di vendita), impostare allow_reuse su False e la fase della pipeline verrà eseguita a ogni esecuzione della pipeline.

Creare la fase di training

Una volta che i dati sono stati convertiti dal formato compresso in file CSV, possono essere utilizzati per fare training a una rete neurale convoluzionale.

Creare l'origine della fase di training

Con pipeline più grandi, è consigliabile inserire il codice sorgente di ogni fase in una directory separata (src/prepare/, src/train/, e così via), ma per questa esercitazione basta usare o creare il file train.py nella stessa directory di origine keras-mnist-fashion/.

import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.layers.normalization import BatchNormalization
from keras.utils import to_categorical
from keras.callbacks import Callback

import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from azureml.core import Run

# dataset object from the run
run = Run.get_context()
dataset = run.input_datasets["prepared_fashion_ds"]

# split dataset into train and test set
(train_dataset, test_dataset) = dataset.random_split(percentage=0.8, seed=111)

# load dataset into pandas dataframe
data_train = train_dataset.to_pandas_dataframe()
data_test = test_dataset.to_pandas_dataframe()

img_rows, img_cols = 28, 28
input_shape = (img_rows, img_cols, 1)

X = np.array(data_train.iloc[:, 1:])
y = to_categorical(np.array(data_train.iloc[:, 0]))

# here we split validation data to optimiza classifier during training
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=13)

# test data
X_test = np.array(data_test.iloc[:, 1:])
y_test = to_categorical(np.array(data_test.iloc[:, 0]))


X_train = (
    X_train.reshape(X_train.shape[0], img_rows, img_cols, 1).astype("float32") / 255
)
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1).astype("float32") / 255
X_val = X_val.reshape(X_val.shape[0], img_rows, img_cols, 1).astype("float32") / 255

batch_size = 256
num_classes = 10
epochs = 10

# construct neuron network
model = Sequential()
model.add(
    Conv2D(
        32,
        kernel_size=(3, 3),
        activation="relu",
        kernel_initializer="he_normal",
        input_shape=input_shape,
    )
)
model.add(MaxPooling2D((2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(64, (3, 3), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(128, (3, 3), activation="relu"))
model.add(Dropout(0.4))
model.add(Flatten())
model.add(Dense(128, activation="relu"))
model.add(Dropout(0.3))
model.add(Dense(num_classes, activation="softmax"))

model.compile(
    loss=keras.losses.categorical_crossentropy,
    optimizer=keras.optimizers.Adam(),
    metrics=["accuracy"],
)

# start an Azure ML run
run = Run.get_context()


class LogRunMetrics(Callback):
    # callback at the end of every epoch
    def on_epoch_end(self, epoch, log):
        # log a value repeated which creates a list
        run.log("Loss", log["loss"])
        run.log("Accuracy", log["accuracy"])


history = model.fit(
    X_train,
    y_train,
    batch_size=batch_size,
    epochs=epochs,
    verbose=1,
    validation_data=(X_val, y_val),
    callbacks=[LogRunMetrics()],
)

score = model.evaluate(X_test, y_test, verbose=0)

# log a single value
run.log("Final test loss", score[0])
print("Test loss:", score[0])

run.log("Final test accuracy", score[1])
print("Test accuracy:", score[1])

plt.figure(figsize=(6, 3))
plt.title("Fashion MNIST with Keras ({} epochs)".format(epochs), fontsize=14)
plt.plot(history.history["accuracy"], "b-", label="Accuracy", lw=4, alpha=0.5)
plt.plot(history.history["loss"], "r--", label="Loss", lw=4, alpha=0.5)
plt.legend(fontsize=12)
plt.grid(True)

# log an image
run.log_image("Loss v.s. Accuracy", plot=plt)

# create a ./outputs/model folder in the compute target
# files saved in the "./outputs" folder are automatically uploaded into run history
os.makedirs("./outputs/model", exist_ok=True)

# serialize NN architecture to JSON
model_json = model.to_json()
# save model JSON
with open("./outputs/model/model.json", "w") as f:
    f.write(model_json)
# save model weights
model.save_weights("./outputs/model/model.h5")
print("model saved in ./outputs/model folder")

La maggior parte di questo codice dovrebbe essere familiare agli sviluppatori ML:

  • I dati sono suddivisi in set di addestramento e convalida per il training e un sottoinsieme di test separato per il punteggio finale
  • La forma dell'input è 28x28x1 (solo 1 perché l'input è in scala di grigi), ci saranno 256 input in un batch e ci saranno 10 classi
  • Il numero di epoche di training sarà 10
  • Il modello ha tre strati convoluzionali, con pooling e dropout massimi, seguiti da uno strato denso e da una testa softmax
  • Il modello viene montato per 10 epoche e poi valutato
  • L'architettura del modello è scritta in outputs/model/model.json e i pesi in outputs/model/model.h5

Parte del codice, tuttavia, è specifico per Azure Machine Learning. run = Run.get_context() recupera un oggetto Run, che contiene il contesto di servizio corrente. L'origine train.py utilizza questo oggetto run per recuperare il set di dati di input tramite il relativo nome (un'alternativa al codice in prepare.py che ha recuperato il set di dati tramite la matrice argv di argomenti dello script).

L'oggetto run viene utilizzato anche per registrare l'avanzamento della formazione alla fine di ogni epoca e, al termine del training, per registrare il grafico di perdita e accuratezza nel tempo.

Creare la fase di training della pipeline

La fase di training ha una configurazione leggermente più complessa rispetto alla fase di preparazione. La fase di preparazione ha utilizzato solo librerie Python standard. Più comunemente, è necessario modificare l'ambiente di runtime in cui viene eseguito il codice sorgente.

Creare un file conda_dependencies.yml con i seguenti contenuti:

dependencies:
- python=3.7
- pip:
  - azureml-core
  - azureml-dataset-runtime
  - keras==2.4.3
  - tensorflow==2.4.3
  - numpy
  - scikit-learn
  - pandas
  - matplotlib

La classe Environment rappresenta l'ambiente di runtime in cui viene eseguita un'attività di apprendimento automatico. Associare la specifica di cui sopra al codice di training con:

keras_env = Environment.from_conda_specification(
    name="keras-env", file_path="./conda_dependencies.yml"
)

train_cfg = ScriptRunConfig(
    source_directory=script_folder,
    script="train.py",
    compute_target=compute_target,
    environment=keras_env,
)

La creazione della fase di training stessa utilizza un codice simile al codice utilizzato per creare la fase di preparazione:

train_step = PythonScriptStep(
    name="train step",
    arguments=[
        prepared_fashion_ds.read_delimited_files().as_input(name="prepared_fashion_ds")
    ],
    source_directory=train_cfg.source_directory,
    script_name=train_cfg.script,
    runconfig=train_cfg.run_config,
)

Creare ed eseguire la pipeline

Ora che sono stati specificati gli input e gli output dei dati e sono state create le fasi della pipeline, è possibile comporle in una pipeline ed eseguirla:

pipeline = Pipeline(workspace, steps=[prep_step, train_step])
run = exp.submit(pipeline)

L'oggetto Pipeline creato viene eseguito in workspace ed è composto dalle fasi di preparazione e training specificate.

Nota

Questa pipeline ha un semplice grafico di dipendenza: la fase di training si basa sulla fase di preparazione e la fase di preparazione si basa sul set di dati fashion_ds. Le pipeline di produzione avranno spesso dipendenze molto più complesse. Le fasi possono basarsi su più fasi a monte, una modifica del codice sorgente in una fase iniziale può avere conseguenze di vasta portata e così via. Azure Machine Learning tiene traccia di questi problemi. È sufficiente inserire la matrice di steps e Azure Machine Learning si occuperà di calcolare il grafico di esecuzione.

La chiamata per submit l'Experiment si completa rapidamente e produce un output simile a:

Submitted PipelineRun 5968530a-abcd-1234-9cc1-46168951b5eb
Link to Azure Machine Learning Portal: https://ml.azure.com/runs/abc-xyz...

È possibile monitorare l'esecuzione della pipeline aprendo il collegamento oppure è possibile bloccarla fino al suo completamento eseguendo:

run.wait_for_completion(show_output=True)

Importante

La prima esecuzione della pipeline richiede circa 15 minuti. Devono essere scaricate tutte le dipendenze, quindi viene creata un'immagine Docker e viene effettuato il provisioning o la creazione dell'ambiente Python. Una seconda esecuzione della pipeline richiede molto meno tempo, perché queste risorse vengono riutilizzate e non create. Tuttavia, il tempo di esecuzione totale dipende dal carico di lavoro degli script e dai processi in esecuzione in ogni passaggio della pipeline.

Una volta completata la pipeline, è possibile recuperare le metriche registrate nella fase di training:

run.find_step_run("train step")[0].get_metrics()

Se si è soddisfatti delle metriche, è possibile registrare il modello nell'area di lavoro:

run.find_step_run("train step")[0].register_model(
    model_name="keras-model",
    model_path="outputs/model/",
    datasets=[("train test data", fashion_ds)],
)

Pulire le risorse

Se si intende eseguire altre esercitazioni su Azure Machine Learning, non completare questa sezione.

Arrestare l'istanza di calcolo

Se è stata utilizzata un'istanza di calcolo, arrestare la VM quando non viene utilizzata per ridurre i costi.

  1. Nell'area di lavoro selezionare Compute.

  2. Dall'elenco, selezionare il nome dell'istanza di calcolo.

  3. Selezionare Interrompi.

  4. Quando si è pronti a usare di nuovo il server, selezionare Avvia.

Eliminare tutto

Se non si prevede di usare le risorse create, eliminarle per non incorrere in alcun addebito:

  1. Nel menu sinistro del portale di Azure selezionare Gruppi di risorse.
  2. Nell'elenco di gruppi di risorse selezionare quello creato.
  3. Selezionare Elimina gruppo di risorse.
  4. Immettere il nome del gruppo di risorse. Quindi, selezionare Elimina.

È anche possibile mantenere il gruppo di risorse ma eliminare una singola area di lavoro. Visualizzare le proprietà dell'area di lavoro e selezionare Elimina.

Passaggi successivi

In questa esercitazione, sono stati utilizzati i seguenti tipi:

  • Workspace rappresenta l'area di lavoro di Azure Machine Learning. Conteneva:
    • Experiment che contiene i risultati delle sessioni di training della pipeline
    • Dataset che ha caricato lentamente i dati contenuti nel datastore Fashion-MNIST
    • ComputeTarget che rappresenta la macchina o le macchine su cui vengono eseguite le fasi della pipeline
    • Environment che è l'ambiente di runtime in cui vengono eseguite le fasi della pipeline
    • Pipeline che compone le fasi di PythonScriptStep in un insieme
    • Model che è stato registrato dopo aver completato correttamente il processo di training

L'oggetto Workspace contiene riferimenti ad altre risorse (notebook, endpoint e così via) che non sono state utilizzate in questa esercitazione. Per ulteriori informazioni, vedere Che cos'è un'area di lavoro di Azure Machine Learning?.

OutputFileDatasetConfig promuove l'output di un'esecuzione in un set di dati basato su file. Per ulteriori informazioni sui set di dati e sull'utilizzo dei dati, vedere Come accedere ai dati.

Per ulteriori informazioni sulle destinazioni e gli ambienti di calcolo, vedere Che cosa sono le destinazioni di calcolo in Azure Machine Learning? e Cosa sono gli ambienti di Azure Machine Learning?

ScriptRunConfig associa ComputeTarget e Environment ai file di origine Python. PythonScriptStep acquisisce ScriptRunConfig e definisce i relativi input e output, che in questa pipeline corrispondono al set di dati del file creato da OutputFileDatasetConfig.

Per ulteriori esempi su come creare pipeline utilizzando l'SDK di apprendimento automatico, vedere il repository di esempio.