Träna PyTorch-modeller i stor skala med Azure Machine Learning

GÄLLER FÖR: Python SDK azure-ai-ml v2 (aktuell)

I den här artikeln lär du dig att träna, finjustera hyperparameter och distribuera en PyTorch-modell med Hjälp av Azure Machine Learning (AzureML) Python SDK v2.

Du använder exempelskripten i den här artikeln för att klassificera kyckling- och kalkonbilder för att skapa ett neuralt nätverk för djupinlärning (DNN) baserat på PyTorchs självstudie om överföringsinlärning. Överföringsinlärning är en teknik som tillämpar kunskap från att lösa ett problem på ett annat men relaterat problem. Överföringsinlärning förkortar träningsprocessen genom att kräva mindre data, tid och beräkningsresurser än träning från grunden. Mer information om överföringsinlärning finns i artikeln djupinlärning kontra maskininlärning .

Oavsett om du tränar en PyTorch-modell för djupinlärning från grunden eller om du för in en befintlig modell i molnet kan du använda AzureML för att skala ut träningsjobb med öppen källkod med hjälp av elastiska beräkningsresurser i molnet. Du kan skapa, distribuera, version och övervaka modeller i produktionsklass med AzureML.

Förutsättningar

För att dra nytta av den här artikeln måste du:

  • Få åtkomst till en Azure-prenumeration. Om du inte redan har ett skapar du ett kostnadsfritt konto.
  • Kör koden i den här artikeln med antingen en Azure Machine Learning-beräkningsinstans eller en egen Jupyter-anteckningsbok.
    • Azure Machine Learning-beräkningsinstans – inga nedladdningar eller installation krävs
      • Slutför snabbstarten: Kom igång med Azure Machine Learning för att skapa en dedikerad notebook-server som är förinstallerad med SDK och exempellagringsplatsen.
      • I mappen exempel på djupinlärning på notebook-servern hittar du en slutförd och expanderad notebook-fil genom att navigera till den här katalogen: v2 > sdk > python > jobs > single-step > pytorch > train-hyperparameter-tune-deploy-with-pytorch.
    • Jupyter Notebook-servern

Du hittar också en färdig Jupyter Notebook version av den här guiden på sidan GitHub-exempel.

Innan du kan köra koden i den här artikeln för att skapa ett GPU-kluster måste du begära en kvotökning för arbetsytan.

Konfigurera jobbet

Det här avsnittet konfigurerar jobbet för träning genom att läsa in nödvändiga Python-paket, ansluta till en arbetsyta, skapa en beräkningsresurs för att köra ett kommandojobb och skapa en miljö för att köra jobbet.

Ansluta till arbetsytan

Först måste du ansluta till din AzureML-arbetsyta. AzureML-arbetsytan är den översta resursen för tjänsten. Det ger dig en central plats där du kan arbeta med alla artefakter som du skapar när du använder Azure Machine Learning.

Vi använder DefaultAzureCredential för att få åtkomst till arbetsytan. Den här autentiseringsuppgiften bör kunna hantera de flesta Azure SDK-autentiseringsscenarier.

Om DefaultAzureCredential inte fungerar för dig kan du se azure-identity reference documentation eller Set up authentication för fler tillgängliga autentiseringsuppgifter.

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

# Authentication package
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()

Om du föredrar att använda en webbläsare för att logga in och autentisera bör du avkommentera följande kod och använda den i stället.

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

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

Hämta sedan ett handtag till arbetsytan genom att ange ditt prenumerations-ID, resursgruppsnamn och arbetsytenamn. Så här hittar du följande parametrar:

  1. Leta efter namnet på arbetsytan i det övre högra hörnet i Azure Machine Learning-studio verktygsfält.
  2. Välj namnet på arbetsytan för att visa resursgruppen och prenumerations-ID:t.
  3. Kopiera värdena för Resursgrupp och Prenumerations-ID till koden.
# 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>",
)

Resultatet av att köra det här skriptet är en arbetsytereferens som du använder för att hantera andra resurser och jobb.

Anteckning

  • Att skapa MLClient ansluter inte klienten till arbetsytan. Klientinitieringen är lat och väntar första gången den behöver göra ett anrop. I den här artikeln sker detta när beräkning skapas.

Skapa en beräkningsresurs för att köra jobbet

AzureML behöver en beräkningsresurs för att köra ett jobb. Den här resursen kan vara datorer med en eller flera noder med Linux eller Windows OS, eller en specifik beräkningsinfrastruktur som Spark.

I följande exempelskript etablerar vi en Linux compute cluster. Du kan se sidan Azure Machine Learning pricing för den fullständiga listan över VM-storlekar och priser. Eftersom vi behöver ett GPU-kluster för det här exemplet ska vi välja en STANDARD_NC6 modell och skapa en AzureML-beräkning.

from azure.ai.ml.entities import AmlCompute

gpu_compute_taget = "gpu-cluster"

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

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

    # Let's create the Azure ML compute object with the intended parameters
    gpu_cluster = AmlCompute(
        # Name assigned to the compute cluster
        name="gpu-cluster",
        # Azure ML Compute is the on-demand VM service
        type="amlcompute",
        # VM Family
        size="STANDARD_NC6",
        # 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
    gpu_cluster = ml_client.begin_create_or_update(gpu_cluster).result()

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

Skapa en jobbmiljö

Om du vill köra ett AzureML-jobb behöver du en miljö. En AzureML-miljö kapslar in de beroenden (till exempel programkörning och bibliotek) som behövs för att köra skriptet för maskininlärningsträning på beräkningsresursen. Den här miljön liknar en Python-miljö på din lokala dator.

Med AzureML kan du antingen använda en kuraterad (eller färdig) miljö eller skapa en anpassad miljö med en Docker-avbildning eller en Conda-konfiguration. I den här artikeln ska du återanvända den granskade AzureML-miljön AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu. Du använder den senaste versionen av den här miljön med hjälp @latest av direktivet.

curated_env_name = "AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu@latest"

Konfigurera och skicka ditt träningsjobb

I det här avsnittet börjar vi med att introducera data för träning. Sedan går vi igenom hur du kör ett träningsjobb med hjälp av ett träningsskript som vi har angett. Du lär dig att skapa träningsjobbet genom att konfigurera kommandot för att köra träningsskriptet. Sedan skickar du träningsjobbet som ska köras i AzureML.

Hämta träningsdata

Du använder data som lagras på en offentlig blob som en zip-fil. Den här datamängden består av cirka 120 träningsbilder vardera för två klasser (kalkoner och kycklingar), med 100 valideringsbilder för varje klass. Bilderna är en delmängd av Datauppsättningen Öppna bilder v5. Vi laddar ned och extraherar datamängden som en del av vårt träningsskript pytorch_train.py.

Förbereda träningsskriptet

I den här artikeln har vi tillhandahållit träningsskriptet pytorch_train.py. I praktiken bör du kunna använda alla anpassade träningsskript som de är och köra det med AzureML utan att behöva ändra koden.

Det angivna träningsskriptet laddar ned data, tränar en modell och registrerar modellen.

Skapa träningsjobbet

Nu när du har alla tillgångar som krävs för att köra jobbet är det dags att skapa det med Hjälp av AzureML Python SDK v2. I det här exemplet skapar vi en command.

En AzureML command är en resurs som anger all information som behövs för att köra träningskoden i molnet. Den här informationen omfattar indata och utdata, typ av maskinvara som ska användas, programvara som ska installeras och hur du kör koden. command Innehåller information för att köra ett enda kommando.

Konfigurera kommandot

Du använder det allmänna syftet command för att köra träningsskriptet och utföra önskade uppgifter. Skapa ett Command objekt för att ange konfigurationsinformation för ditt träningsjobb.

from azure.ai.ml import command
from azure.ai.ml import Input

job = command(
    inputs=dict(
        num_epochs=30, learning_rate=0.001, momentum=0.9, output_dir="./outputs"
    ),
    compute=gpu_compute_taget,
    environment=curated_env_name,
    code="./src/",  # location of source code
    command="python pytorch_train.py --num_epochs ${{inputs.num_epochs}} --output_dir ${{inputs.output_dir}}",
    experiment_name="pytorch-birds",
    display_name="pytorch-birds-image",
)
  • Indata för det här kommandot omfattar antalet epoker, inlärningshastighet, momentum och utdatakatalog.
  • För parametervärdena:
    • ange det beräkningskluster gpu_compute_target = "gpu-cluster" som du skapade för att köra det här kommandot.
    • ange den kuraterade miljö AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu som du initierade tidigare.
    • konfigurera själva kommandoradsåtgärden – i det här fallet är python pytorch_train.pykommandot . Du kan komma åt indata och utdata i kommandot via notationen ${{ ... }} och
    • konfigurera metadata, till exempel visningsnamn och experimentnamn. där ett experiment är en container för alla iterationer man gör i ett visst projekt. Alla jobb som skickas under samma experimentnamn visas bredvid varandra i AzureML Studio.

Skicka jobbet

Nu är det dags att skicka jobbet som ska köras i AzureML. Den här gången använder create_or_update du på ml_client.jobs.

ml_client.jobs.create_or_update(job)

När jobbet är klart registrerar det en modell på din arbetsyta (som ett resultat av träningen) och skickar ut en länk för att visa jobbet i AzureML Studio.

Varning

Azure Machine Learning kör träningsskript genom att kopiera hela källkatalogen. Om du har känsliga data som du inte vill ladda upp använder du en .ignore-fil eller tar inte med den i källkatalogen.

Vad händer under jobbkörningen?

När jobbet körs går det igenom följande steg:

  • Förbereder: En docker-avbildning skapas enligt den definierade miljön. Avbildningen laddas upp till arbetsytans containerregister och cachelagras för senare körningar. Loggar strömmas också till jobbhistoriken och kan visas för att övervaka förloppet. Om en kuraterad miljö anges används den cachelagrade avbildningsstöd som den kurerade miljön har.

  • Skalning: Klustret försöker skala upp om det krävs fler noder för att köra körningen än vad som för närvarande är tillgängligt.

  • Körs: Alla skript i skriptmappen src laddas upp till beräkningsmålet, datalager monteras eller kopieras och skriptet körs. Utdata från stdout och mappen ./logs strömmas till jobbhistoriken och kan användas för att övervaka jobbet.

Finjustera modellhyperparametrar

Du har tränat modellen med en uppsättning parametrar. Nu ska vi se om du kan förbättra modellens noggrannhet ytterligare. Du kan finjustera och optimera modellens hyperparametrar med hjälp av Funktionerna i Azure Machine Learning sweep .

Om du vill finjustera modellens hyperparametrar definierar du det parameterutrymme som du vill söka i under träningen. Det gör du genom att ersätta några av de parametrar som skickas till träningsjobbet med särskilda indata från azure.ml.sweep paketet.

Eftersom träningsskriptet använder ett schema för inlärningsfrekvens för att förfalla inlärningshastigheten var och en av flera epoker, kan du justera den inledande inlärningshastigheten och momentumparametrarna.

from azure.ai.ml.sweep import Uniform

# we will reuse the command_job created before. we call it as a function so that we can apply inputs
job_for_sweep = job(
    learning_rate=Uniform(min_value=0.0005, max_value=0.005),
    momentum=Uniform(min_value=0.9, max_value=0.99),
)

Sedan konfigurerar du svepning på kommandojobbet med hjälp av några svepspecifika parametrar, till exempel det primära måttet att titta på och samplingsalgoritmen som ska användas.

I följande kod använder vi slumpmässig sampling för att prova olika konfigurationsuppsättningar av hyperparametrar i ett försök att maximera vårt primära mått, best_val_acc.

Vi definierar också en princip för tidig avslutning, BanditPolicy, för att avsluta dåligt presterande körningar tidigt. BanditPolicy Kommer att avsluta alla körningar som inte faller inom slack-faktorn för vårt primära utvärderingsmått. Du tillämpar den här principen varje epok (eftersom vi rapporterar vårt best_val_acc mått varje epok och evaluation_interval=1). Observera att vi fördröjer den första principutvärderingen tills efter de första 10 epokerna (delay_evaluation=10).

from azure.ai.ml.sweep import BanditPolicy

sweep_job = job_for_sweep.sweep(
    compute="gpu-cluster",
    sampling_algorithm="random",
    primary_metric="best_val_acc",
    goal="Maximize",
    max_total_trials=8,
    max_concurrent_trials=4,
    early_termination_policy=BanditPolicy(
        slack_factor=0.15, evaluation_interval=1, delay_evaluation=10
    ),
)

Nu kan du skicka det här jobbet som tidigare. Den här gången kör du ett svepjobb som sveper över ditt tågjobb.

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)

Du kan övervaka jobbet med hjälp av länken för studioanvändargränssnittet som visas under jobbkörningen.

Hitta den bästa modellen

När alla körningar har slutförts hittar du körningen som skapade modellen med högsta noggrannhet.

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 "outputs"
        path="azureml://jobs/{}/outputs/artifacts/paths/outputs/".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
        )
    )

Distribuera modellen som en onlineslutpunkt

Nu kan du distribuera din modell som en onlineslutpunkt, det villa vara en webbtjänst i Azure-molnet.

För att distribuera en maskininlärningstjänst behöver du vanligtvis:

  • De modelltillgångar som du vill distribuera. Dessa tillgångar inkluderar modellens fil och metadata som du redan har registrerat i ditt träningsjobb.
  • Kod som ska köras som en tjänst. Koden kör modellen på en angiven indatabegäran (ett postskript). Det här postskriptet tar emot data som skickas till en distribuerad webbtjänst och skickar dem till modellen. När modellen har bearbetat data returnerar skriptet modellens svar till klienten. Skriptet är specifikt för din modell och måste förstå de data som modellen förväntar sig och returnerar. När du använder en MLFlow-modell skapar AzureML automatiskt det här skriptet åt dig.

Mer information om distribution finns i Distribuera och poängsätta en maskininlärningsmodell med hanterad onlineslutpunkt med Python SDK v2.

Skapa en ny onlineslutpunkt

Som ett första steg för att distribuera din modell måste du skapa din onlineslutpunkt. Slutpunktsnamnet måste vara unikt i hela Azure-regionen. I den här artikeln skapar du ett unikt namn med hjälp av en universellt unik identifierare (UUID).

import uuid

# Creating a unique name for the endpoint
online_endpoint_name = "aci-birds-endpoint-" + str(uuid.uuid4())[:8]
from azure.ai.ml.entities import ManagedOnlineEndpoint

# create an online endpoint
endpoint = ManagedOnlineEndpoint(
    name=online_endpoint_name,
    description="Classify turkey/chickens using transfer learning with PyTorch",
    auth_mode="key",
    tags={"data": "birds", "method": "transfer learning", "framework": "pytorch"},
)

endpoint = ml_client.begin_create_or_update(endpoint).result()

print(f"Endpoint {endpoint.name} provisioning state: {endpoint.provisioning_state}")

När du har skapat slutpunkten kan du hämta den på följande sätt:

endpoint = ml_client.online_endpoints.get(name=online_endpoint_name)

print(
    f'Endpint "{endpoint.name}" with provisioning state "{endpoint.provisioning_state}" is retrieved'
)

Distribuera modellen till slutpunkten

När du har skapat slutpunkten kan du distribuera modellen med postskriptet. En slutpunkt kan ha flera distributioner. Med hjälp av regler kan slutpunkten sedan dirigera trafik till dessa distributioner.

I följande kod skapar du en enda distribution som hanterar 100 % av den inkommande trafiken. Vi har angett ett godtyckligt färgnamn (aci-blått) för distributionen. Du kan också använda andra namn, till exempel aci-green eller aci-red för distributionen. Koden för att distribuera modellen till slutpunkten gör följande:

  • distribuerar den bästa versionen av modellen som du registrerade tidigare.
  • poängsätt modellen med hjälp av score.py filen och
  • använder den granskade miljön (som du angav tidigare) för att utföra slutsatsdragning.
from azure.ai.ml.entities import (
    ManagedOnlineDeployment,
    Model,
    Environment,
    CodeConfiguration,
)

online_deployment_name = "aci-blue"

# create an online deployment.
blue_deployment = ManagedOnlineDeployment(
    name=online_deployment_name,
    endpoint_name=online_endpoint_name,
    model=model,
    environment=curated_env_name,
    code_configuration=CodeConfiguration(code="./score/", scoring_script="score.py"),
    instance_type="Standard_NC6s_v3",
    instance_count=1,
)

blue_deployment = ml_client.begin_create_or_update(blue_deployment).result()

Anteckning

Förvänta dig att den här distributionen tar lite tid att slutföra.

Testa den distribuerade modellen

Nu när du har distribuerat modellen till slutpunkten kan du förutsäga utdata för den distribuerade modellen med hjälp invoke av metoden på slutpunkten.

För att testa slutpunkten ska vi använda en exempelbild för förutsägelse. Först ska vi visa bilden.

# install pillow if PIL cannot imported
%pip install pillow
import json
from PIL import Image
import matplotlib.pyplot as plt

%matplotlib inline
plt.imshow(Image.open("test_img.jpg"))

Skapa en funktion för att formatera och ändra storlek på avbildningen.

# install torch and torchvision if needed
%pip install torch
%pip install torchvision

import torch
from torchvision import transforms


def preprocess(image_file):
    """Preprocess the input image."""
    data_transforms = transforms.Compose(
        [
            transforms.Resize(256),
            transforms.CenterCrop(224),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
        ]
    )

    image = Image.open(image_file)
    image = data_transforms(image).float()
    image = torch.tensor(image)
    image = image.unsqueeze(0)
    return image.numpy()

Formatera bilden och konvertera den till en JSON-fil.

image_data = preprocess("test_img.jpg")
input_data = json.dumps({"data": image_data.tolist()})
with open("request.json", "w") as outfile:
    outfile.write(input_data)

Du kan sedan anropa slutpunkten med denna JSON och skriva ut resultatet.

# test the blue deployment
result = ml_client.online_endpoints.invoke(
    endpoint_name=online_endpoint_name,
    request_file="request.json",
    deployment_name=online_deployment_name,
)

print(result)

Rensa resurser

Om du inte använder slutpunkten tar du bort den för att sluta använda resursen. Kontrollera att inga andra distributioner använder slutpunkten innan du tar bort den.

ml_client.online_endpoints.begin_delete(name=online_endpoint_name)

Anteckning

Förvänta dig att den här rensningen tar lite tid att slutföra.

Nästa steg

I den här artikeln har du tränat och registrerat ett neuralt djupinlärningsnätverk med PyTorch i Azure Machine Learning. Du har också distribuerat modellen till en onlineslutpunkt. Mer information om Azure Machine Learning finns i de här andra artiklarna.