Självstudie: Skapa en Azure Machine Learning pipeline för bildklassificering

I den här självstudien får du lära dig hur du skapar en Azure Machine Learning pipeline för att förbereda data och träna en maskininlärningsmodell. Maskininlärningspipelines optimerar ditt arbetsflöde med hastighet, portabilitet och återanvändning, så att du kan fokusera på maskininlärning i stället för infrastruktur och automatisering.

Exemplet tränar ett litet Keras-convolutional neuralt nätverk för att klassificera bilder i Fashion MNIST-datauppsättningen.

I den här självstudien slutför du följande uppgifter:

  • Konfigurera arbetsyta
  • Skapa ett experiment för att lagra ditt arbete
  • Etablera en ComputeTarget för att utföra arbetet
  • Skapa en datauppsättning där komprimerade data ska lagras
  • Skapa ett pipelinesteg för att förbereda data för träning
  • Definiera en körningsmiljö där träning ska utföras
  • Skapa ett pipelinesteg för att definiera det neurala nätverket och utföra träningen
  • Skapa en pipeline från pipelinestegen
  • Köra pipelinen i experimentet
  • Granska utdata från stegen och det tränade neurala nätverket
  • Registrera modellen för vidare användning

Om du inte har någon Azure-prenumeration kan du skapa ett kostnadsfritt konto innan du börjar. Prova den kostnadsfria eller betalda versionen av Azure Machine Learning idag.

Förutsättningar

  • Slutför snabbstarten: Kom igång med Azure Machine Learning om du inte redan har en Azure Machine Learning arbetsyta.
  • En Python-miljö där du har installerat både paketen azureml-core och azureml-pipeline . Den här miljön används för att definiera och kontrollera dina Azure Machine Learning resurser och är separat från den miljö som används vid körning för träning.

Viktigt

För närvarande är den senaste Python-versionen som är kompatibel med azureml-pipeline Python 3.8. Om du har problem med att azureml-pipeline installera paketet kontrollerar du att det python --version är en kompatibel version. Anvisningar finns i dokumentationen för din virtuella Python-miljöhanterare (venv, condaoch så vidare).

Starta en interaktiv Python-session

I den här självstudien används Python SDK för Azure ML för att skapa och styra en Azure Machine Learning pipeline. Självstudien förutsätter att du kommer att köra kodfragmenten interaktivt i antingen en Python REPL-miljö eller en Jupyter Notebook.

  • Den här självstudien baseras på notebook-filen image-classification.ipynb som finns i python-sdk/tutorial/using-pipelines katalogen på azureML-exempellagringsplatsen . Källkoden för själva stegen finns i underkatalogen keras-mnist-fashion .

Importtyper

Importera alla Azure Machine Learning typer som du behöver för den här självstudien:

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 ML SDK Version: ", azureml.core.VERSION)

Azure ML SDK-versionen ska vara 1.37 eller senare. Om den inte är det uppgraderar du med pip install --upgrade azureml-core.

Konfigurera arbetsyta

Skapa ett arbetsyteobjekt från den befintliga Azure Machine Learning arbetsytan.

workspace = Workspace.from_config()

Viktigt

Det här kodfragmentet förväntar sig att arbetsytans konfiguration sparas i den aktuella katalogen eller dess överordnade. Mer information om hur du skapar en arbetsyta finns i Skapa och hantera Azure Machine Learning arbetsytor. Mer information om hur du sparar konfigurationen i filen finns i Skapa en konfigurationsfil för arbetsytan.

Skapa infrastrukturen för din pipeline

Skapa ett Experiment -objekt för att lagra resultatet av dina pipelinekörningar:

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

Skapa en ComputeTarget som representerar den datorresurs som pipelinen ska köras på. Det enkla neurala nätverk som används i den här självstudien tränas på bara några minuter även på en CPU-baserad dator. Om du vill använda en GPU för träning anger du use_gpu till True. Det tar vanligtvis cirka fem minuter att etablera ett beräkningsmål.

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())

Anteckning

GPU-tillgänglighet beror på kvoten för din Azure-prenumeration och på Azure-kapacitet. Se Hantera och öka kvoter för resurser med Azure Machine Learning.

Skapa en datauppsättning för Azure-lagrade data

Fashion-MNIST är en datamängd med modebilder indelade i 10 klasser. Varje bild är en gråskalebild på 28 x 28 och det finns 60 000 träningsbilder och 10 000 testbilder. Som ett problem med bildklassificering är Fashion-MNIST svårare än den klassiska handskrivna MNIST-sifferdatabasen. Den distribueras i samma komprimerade binära format som den ursprungliga handskrivna sifferdatabasen .

Om du vill skapa en Dataset som refererar till webbaserade data kör du:

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())

Den här koden slutförs snabbt. Underliggande data finns kvar i Azure Storage-resursen som anges i matrisen data_urls .

Skapa pipelinesteget för förberedelse av data

Det första steget i den här pipelinen konverterar komprimerade datafiler fashion_ds till en datauppsättning på din egen arbetsyta som består av CSV-filer som är redo att användas i träning. När de har registrerats med arbetsytan kan dina medarbetare komma åt dessa data för sin egen analys, utbildning och så vidare

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

Koden ovan anger en datauppsättning som baseras på utdata från ett pipelinesteg. De underliggande bearbetade filerna placeras i arbetsytans standarddatalagers bloblagring på den sökväg som anges i destination. Datauppsättningen registreras på arbetsytan med namnet prepared_fashion_ds.

Skapa pipelinestegets källa

Den kod som du har kört hittills har skapat och kontrollerat Azure-resurser. Nu är det dags att skriva kod som utför det första steget i domänen.

Om du följer med i exemplet på lagringsplatsen AzureML-exempel är källfilen redan tillgänglig som keras-mnist-fashion/prepare.py.

Om du arbetar från grunden skapar du en underkatalog med namnet kera-mnist-fashion/. Skapa en ny fil, lägg till följande kod i den och ge filen prepare.pynamnet .

# 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,
)

Koden i prepare.py tar två kommandoradsargument: den första tilldelas till mounted_input_path och den andra till mounted_output_path. Om den underkatalogen inte finns skapar anropet till os.makedirs den. Sedan konverterar programmet tränings- och testdata och matar ut kommaavgränsade filer till mounted_output_path.

Ange pipelinesteget

Tillbaka i Python-miljön som du använder för att ange pipelinen kör du den här koden för att skapa en PythonScriptStep för din förberedelsekod:

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,
)

Anropet till PythonScriptStep anger att när pipelinesteget körs:

  • Alla filer i script_folder katalogen laddas upp till compute_target
  • Bland de uppladdade källfilerna körs filen prepare.py
  • Datauppsättningarna fashion_ds och prepared_fashion_ds monteras på compute_target och visas som kataloger
  • Sökvägen till fashion_ds filerna blir det första argumentet för prepare.py. I prepare.pytilldelas det här argumentet till mounted_input_path
  • Sökvägen till prepared_fashion_ds blir det andra argumentet till prepare.py. I prepare.pytilldelas det här argumentet till mounted_output_path
  • Eftersom allow_reuse är Truekörs den inte igen förrän dess källfiler eller indata ändras
  • Detta PythonScriptStep kommer att namnges prepare step

Modularitet och återanvändning är viktiga fördelar med pipelines. Azure Machine Learning kan automatiskt fastställa ändringar i källkoden eller datauppsättningen. Utdata från ett steg som inte påverkas återanvänds utan att du kör stegen igen om allow_reuse är True. Om ett steg förlitar sig på en extern datakälla till Azure Machine Learning som kan ändras (till exempel en URL som innehåller försäljningsdata) anger du allow_reuse till False och pipelinesteget körs varje gång pipelinen körs.

Skapa träningssteget

När data har konverterats från det komprimerade formatet till CSV-filer kan de användas för att träna ett neuralt convolutional-nätverk.

Skapa träningsstegets källa

Med större pipelines är det en bra idé att placera varje stegs källkod i en separat katalog (src/prepare/och src/train/så vidare), men i den här självstudien använder du eller skapar filen train.py i samma keras-mnist-fashion/ källkatalog.

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")

Merparten av den här koden bör vara bekant för ML utvecklare:

  • Data partitioneras i tränings- och valideringsuppsättningar för träning och en separat testunderuppsättning för slutlig bedömning
  • Indataformen är 28x28x1 (endast 1 eftersom indata är gråskala), det kommer att finnas 256 indata i en batch och det finns 10 klasser
  • Antalet träningsepoker blir 10
  • Modellen har tre faltningslager, med maximal poolning och avhopp, följt av ett tätt lager och softmax-huvud
  • Modellen är monterad för 10 epoker och utvärderas sedan
  • Modellarkitekturen skrivs till outputs/model/model.json och vikterna till outputs/model/model.h5

En del av koden är dock specifik för Azure Machine Learning. run = Run.get_context() hämtar ett Run -objekt som innehåller den aktuella tjänstkontexten. Källan train.py använder det här run objektet för att hämta indatauppsättningen via dess namn (ett alternativ till koden i prepare.py som hämtade datauppsättningen via matrisen argv med skriptargument).

Objektet run används också för att logga träningsförloppet i slutet av varje epok och, i slutet av träningen, för att logga grafen över förlust och noggrannhet över tid.

Skapa steget för träningspipeline

Träningssteget har en något mer komplex konfiguration än förberedelsesteget. Förberedelsesteget använde endast Python-standardbibliotek. Vanligare är att du behöver ändra körningsmiljön där källkoden körs.

Skapa en fil conda_dependencies.yml med följande innehåll:

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

Klassen Environment representerar körningsmiljön där en maskininlärningsuppgift körs. Associera ovanstående specifikation med träningskoden med:

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,
)

När du skapar själva träningssteget används kod som liknar den som används för att skapa förberedelsesteget:

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,
)

Skapa och köra pipelinen

Nu när du har angett indata och utdata och skapat pipelinens steg kan du skapa dem i en pipeline och köra den:

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

Objektet Pipeline som du skapar körs i och workspace består av de förberedelse- och träningssteg som du har angett.

Anteckning

Den här pipelinen har ett enkelt beroendediagram: träningssteget förlitar sig på förberedelsesteget och förberedelsesteget förlitar sig på datauppsättningen fashion_ds . Produktionspipelines har ofta mycket mer komplexa beroenden. Steg kan vara beroende av flera uppströmssteg, en källkodsändring i ett tidigt steg kan få långtgående konsekvenser och så vidare. Azure Machine Learning spårar dessa problem åt dig. Du behöver bara skicka in matrisen steps med och Azure Machine Learning tar hand om beräkning av körningsdiagrammet.

Anropet Experiment till submit slutförs snabbt och genererar utdata som liknar:

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

Du kan övervaka pipelinekörningen genom att öppna länken eller blockera tills den har slutförts genom att köra:

run.wait_for_completion(show_output=True)

Viktigt

Den första pipelinekörningen tar ungefär 15 minuter. Alla beroenden måste laddas ned, en Docker-avbildning skapas och Python-miljön etableras och skapas. Det tar betydligt kortare tid att köra pipelinen igen eftersom resurserna återanvänds i stället för att skapas. Den totala körningstiden för pipelinen beror dock på arbetsbelastningen för dina skript och de processer som körs i varje pipelinesteg.

När pipelinen är klar kan du hämta måtten som du loggade i träningssteget:

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

Om du är nöjd med måtten kan du registrera modellen på din arbetsyta:

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

Rensa resurser

Slutför inte det här avsnittet om du planerar att köra andra Azure Machine Learning självstudier.

Stoppa beräkningsinstansen

Om du använde en beräkningsinstans stoppar du den virtuella datorn när du inte använder den för att minska kostnaderna.

  1. Välj Beräkning på arbetsytan.

  2. I listan väljer du namnet på beräkningsinstansen.

  3. Välj Stoppa.

  4. När du är redo att använda servern igen väljer du Starta.

Ta bort allt

Om du inte planerar att använda de resurser som du skapade, tar du bort dem så att du inte debiteras:

  1. I Azure Portal går du till menyn till vänster och väljer Resursgrupper.
  2. I listan över resursgrupper väljer du den resursgrupp som du skapade.
  3. Välj Ta bort resursgrupp.
  4. Ange resursgruppsnamnet. Välj sedan Ta bort.

Du kan också behålla resursgruppen men ta bort en enstaka arbetsyta. Visa egenskaperna för arbetsytan och välj sedan Ta bort.

Nästa steg

I den här självstudien använde du följande typer:

  • Workspace representerar din Azure Machine Learning arbetsyta. Den innehöll:
    • Experiment Som innehåller resultatet av träningskörningar för din pipeline
    • Som Dataset lazily läste in data som lagras i Fashion-MNIST-datalagringen
    • ComputeTarget Som representerar de datorer som pipelinestegen körs på
    • Det Environment är den körningsmiljö där pipelinestegen körs
    • Som Pipeline utgör PythonScriptStep stegen i en helhet
    • Det Model som du registrerade efter att ha varit nöjd med träningsprocessen

Objektet Workspace innehåller referenser till andra resurser (notebook-filer, slutpunkter och så vidare) som inte användes i den här självstudien. Mer information finns i Vad är en Azure Machine Learning arbetsyta?.

OutputFileDatasetConfig flyttar upp utdata från en körning till en filbaserad datauppsättning. Mer information om datauppsättningar och hur du arbetar med data finns i Så här kommer du åt data.

Mer information om beräkningsmål och miljöer finns i Vad är beräkningsmål i Azure Machine Learning? och Vad är Azure Machine Learning miljöer?

ScriptRunConfig associerar en ComputeTarget och Environment med Python-källfiler. En PythonScriptStep tar det ScriptRunConfig och definierar dess indata och utdata, som i den här pipelinen var fildatauppsättningen OutputFileDatasetConfigsom skapades av .

Fler exempel på hur du skapar pipelines med hjälp av maskininlärnings-SDK finns i exempellagringsplatsen.