Partilhar via


Tutorial: Criar um pipeline do Azure Machine Learning para classificação de imagens

APLICA-SE A:SDK python azureml v1

Neste tutorial, vai aprender a criar um pipeline do Azure Machine Learning para preparar dados e preparar um modelo de machine learning. Os pipelines de machine learning otimizam o seu fluxo de trabalho com velocidade, portabilidade e reutilização, para que possa concentrar-se na aprendizagem automática em vez da infraestrutura e automatização.

O exemplo prepara uma pequena rede neural convolucional do Keras para classificar imagens no conjunto de dados MNIST da Moda .

Neste tutorial, vai concluir as seguintes tarefas:

  • Configurar a área de trabalho
  • Criar uma Experimentação para manter o seu trabalho
  • Aprovisionar um ComputeTarget para fazer o trabalho
  • Criar um Conjunto de Dados no qual armazenar dados comprimidos
  • Criar um passo de pipeline para preparar os dados para preparação
  • Definir um Ambiente de runtime no qual realizar a preparação
  • Criar um passo de pipeline para definir a rede neural e realizar a preparação
  • Compor um Pipeline a partir dos passos do pipeline
  • Executar o pipeline na experimentação
  • Reveja o resultado dos passos e a rede neural preparada
  • Registar o modelo para utilização adicional

Se não tiver uma subscrição do Azure, crie uma conta gratuita antes de começar. Experimente a versão gratuita ou paga do Azure Machine Learning hoje mesmo.

Pré-requisitos

  • Conclua Criar recursos para começar se ainda não tiver uma área de trabalho do Azure Machine Learning.
  • Um ambiente Python no qual instalou os azureml-core pacotes e azureml-pipeline . Este ambiente destina-se a definir e controlar os seus recursos do Azure Machine Learning e é separado do ambiente utilizado no runtime para a preparação.

Importante

Atualmente, a versão mais recente do Python compatível com azureml-pipeline é o Python 3.8. Se tiver dificuldades em instalar o azureml-pipeline pacote, certifique-se de que python --version é uma versão compatível. Consulte a documentação do gestor de ambiente virtual do Python (venv, conda, etc.) para obter instruções.

Iniciar uma sessão interativa do Python

Este tutorial utiliza o SDK python para o Azure Machine Learning para criar e controlar um pipeline do Azure Machine Learning. O tutorial pressupõe que irá executar os fragmentos de código interativamente num ambiente REPL do Python ou num bloco de notas do Jupyter.

  • Este tutorial baseia-se no image-classification.ipynb bloco de notas encontrado no python-sdk/tutorial/using-pipelines diretório do repositório de Exemplos do Azure Machine Learning . O código fonte para os passos em si está no keras-mnist-fashion subdiretório.

Tipos de importação

Importe todos os tipos do Azure Machine Learning necessários para este tutorial:

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)

A versão do SDK do Azure Machine Learning deve ser a 1.37 ou superior. Se não estiver, atualize com pip install --upgrade azureml-core.

Configurar a área de trabalho

Crie um objeto de área de trabalho a partir da área de trabalho do Azure Machine Learning existente.

workspace = Workspace.from_config()

Importante

Este fragmento de código espera que a configuração da área de trabalho seja guardada no diretório atual ou no respetivo principal. Para obter mais informações sobre como criar uma área de trabalho, veja Criar recursos da área de trabalho. Para obter mais informações sobre como guardar a configuração no ficheiro, veja Criar um ficheiro de configuração da área de trabalho.

Criar a infraestrutura para o pipeline

Crie um Experiment objeto para conter os resultados das execuções do pipeline:

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

Crie um ComputeTarget que represente o recurso da máquina no qual o pipeline será executado. A rede neural simples utilizada neste tutorial prepara-se em apenas alguns minutos, mesmo num computador baseado na CPU. Se quiser utilizar uma GPU para preparação, defina use_gpu como True. Geralmente, o aprovisionamento de um destino de computação demora cerca de cinco minutos.

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

A disponibilidade da GPU depende da quota da sua subscrição do Azure e da capacidade do Azure. Veja Gerir e aumentar as quotas dos recursos com o Azure Machine Learning.

Criar um conjunto de dados para os dados armazenados no Azure

Fashion-MNIST é um conjunto de dados de imagens de moda dividido em 10 classes. Cada imagem é uma imagem em tons de cinzento 28x28 e existem 60 000 imagens de preparação e 10 000 imagens de teste. Como um problema de classificação de imagens, Fashion-MNIST é mais difícil do que a base de dados de dígitos escritas à mão MNIST clássica. É distribuído na mesma forma binária comprimida que a base de dados original de dígitos escritos à mão .

Para criar um Dataset que faça referência aos dados baseados na Web, execute:

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

Este código é concluído rapidamente. Os dados subjacentes permanecem no recurso de armazenamento do Azure especificado na data_urls matriz.

Criar o passo do pipeline de preparação de dados

O primeiro passo neste pipeline irá converter os ficheiros de dados comprimidos de num conjunto de fashion_ds dados na sua própria área de trabalho que consiste em ficheiros CSV prontos para serem utilizados na preparação. Depois de registados na área de trabalho, os seus colaboradores podem aceder a estes dados para a sua própria análise, formação, etc.

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

O código acima especifica um conjunto de dados baseado na saída de um passo de pipeline. Os ficheiros processados subjacentes serão colocados no armazenamento de blobs do arquivo de dados predefinido do arquivo de dados no caminho especificado em destination. O conjunto de dados será registado na área de trabalho com o nome prepared_fashion_ds.

Criar a origem do passo do pipeline

O código que executou até agora tem recursos do Azure criados e controlados. Agora é altura de escrever código que efetue o primeiro passo no domínio.

Se estiver a seguir o exemplo no repositório exemplos do Azure Machine Learning, o ficheiro de origem já está disponível como keras-mnist-fashion/prepare.py.

Se estiver a trabalhar de raiz, crie um subdiretório chamado keras-mnist-fashion/. Crie um novo ficheiro, adicione o seguinte código ao mesmo e dê-lhe o prepare.pynome .

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

O código em prepare.py utiliza dois argumentos da linha de comandos: o primeiro é atribuído a mounted_input_path e o segundo para mounted_output_path. Se esse subdiretório não existir, a chamada para os.makedirs o criará. Em seguida, o programa converte os dados de preparação e teste e produz os ficheiros separados por vírgulas para o mounted_output_path.

Especificar o passo do pipeline

De volta ao ambiente Python que está a utilizar para especificar o pipeline, execute este código para criar um PythonScriptStep para o código de preparação:

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

A chamada a PythonScriptStep especifica que, quando o passo do pipeline é executado:

  • Todos os ficheiros no script_folder diretório são carregados para o compute_target
  • Entre os ficheiros de origem carregados, o ficheiro prepare.py será executado
  • Os fashion_ds conjuntos de dados e prepared_fashion_ds serão montados no compute_target e serão apresentados como diretórios
  • O caminho para os fashion_ds ficheiros será o primeiro argumento para prepare.py. No prepare.py, este argumento é atribuído a mounted_input_path
  • O caminho para o prepared_fashion_ds será o segundo argumento para prepare.py. No prepare.py, este argumento é atribuído a mounted_output_path
  • Uma allow_reuse vez que é True, não será novamente executado até que os respetivos ficheiros ou entradas de origem sejam alterados
  • Este PythonScriptStep nome será atribuído prepare step

A modularidade e a reutilização são os principais benefícios dos pipelines. O Azure Machine Learning pode determinar automaticamente o código fonte ou as alterações do Conjunto de dados. O resultado de um passo que não é afetado será reutilizado sem voltar a executar os passos se allow_reuse for True. Se um passo depender de uma origem de dados externa ao Azure Machine Learning que pode ser alterada (por exemplo, um URL que contém dados de vendas), defina allow_reuse como False e o passo do pipeline será executado sempre que o pipeline for executado.

Criar o passo de preparação

Depois de os dados serem convertidos do formato comprimido para ficheiros CSV, podem ser utilizados para preparar uma rede neural convolucional.

Criar a origem do passo de preparação

Com pipelines maiores, é uma boa prática colocar o código fonte de cada passo num diretório separado (src/prepare/, src/train/, etc.), mas neste tutorial, basta utilizar ou criar o ficheiro train.py no mesmo keras-mnist-fashion/ diretório de origem.

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

A maior parte deste código deve ser familiar para os programadores de ML:

  • Os dados são particionados em conjuntos de preparação e validação para preparação e um subconjunto de teste separado para classificação final
  • A forma de entrada é 28x28x1 (apenas 1 porque a entrada é tons de cinzento), haverá 256 entradas num lote e existem 10 classes
  • O número de épocas de preparação será de 10
  • O modelo tem três camadas convolucionais, com agrupamento máximo e dropout, seguido de uma camada densa e cabeça de softmax
  • O modelo é ajustado para 10 épocas e, em seguida, avaliado
  • A arquitetura do modelo é escrita outputs/model/model.json em e os pesos para outputs/model/model.h5

No entanto, alguns dos códigos são específicos do Azure Machine Learning. run = Run.get_context() obtém um Run objeto, que contém o contexto de serviço atual. A origem train.py utiliza este run objeto para obter o conjunto de dados de entrada através do respetivo nome (uma alternativa ao código no prepare.py qual obteve o conjunto de dados através da argv matriz de argumentos de script).

O run objeto também é utilizado para registar o progresso da preparação no final de cada época e, no final da preparação, para registar o gráfico de perda e precisão ao longo do tempo.

Criar o passo do pipeline de preparação

O passo de preparação tem uma configuração ligeiramente mais complexa do que o passo de preparação. O passo de preparação utilizou apenas bibliotecas Python padrão. Mais frequentemente, terá de modificar o ambiente de runtime no qual o código fonte é executado.

Crie um ficheiro conda_dependencies.yml com os seguintes conteúdos:

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

A Environment classe representa o ambiente de runtime no qual uma tarefa de machine learning é executada. Associe a especificação acima ao código de preparação com:

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

A criação do próprio passo de preparação utiliza código semelhante ao código utilizado para criar o passo de preparação:

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

Criar e executar o pipeline

Agora que especificou entradas e saídas de dados e criou os passos do pipeline, pode compô-los num pipeline e executá-los:

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

O Pipeline objeto que criar é executado no seu workspace e é composto pelos passos de preparação e preparação que especificou.

Nota

Este pipeline tem um gráfico de dependência simples: o passo de preparação depende do passo de preparação e o passo de preparação depende do fashion_ds conjunto de dados. Os pipelines de produção terão muitas vezes dependências muito mais complexas. Os passos podem depender de vários passos a montante, uma alteração do código fonte num passo inicial pode ter consequências de longo alcance e assim sucessivamente. O Azure Machine Learning monitoriza estas preocupações por si. Só precisa de transmitir a matriz de steps e o Azure Machine Learning trata de calcular o gráfico de execução.

A chamada para submit a Experiment conclusão é concluída rapidamente e produz um resultado semelhante a:

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

Pode monitorizar a execução do pipeline ao abrir a ligação ou pode bloquear até que seja concluída ao executar:

run.wait_for_completion(show_output=True)

Importante

A primeira execução do pipeline demora cerca de 15 minutos. Todas as dependências têm de ser transferidas, é criada uma imagem do Docker e o ambiente python é aprovisionado e criado. Executar o pipeline novamente demora significativamente menos tempo porque esses recursos são reutilizados em vez de criados. No entanto, o tempo total de execução do pipeline depende da carga de trabalho dos scripts e dos processos em execução em cada passo de pipeline.

Assim que o pipeline estiver concluído, pode obter as métricas que registou no passo de preparação:

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

Se estiver satisfeito com as métricas, pode registar o modelo na área de trabalho:

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

Limpar os recursos

Não conclua esta secção se planear executar outros tutoriais do Azure Machine Learning.

Parar a instância de computação

Se utilizou uma instância de computação, pare a VM quando não estiver a utilizá-la para reduzir os custos.

  1. Na área de trabalho, selecione Computação.

  2. Na lista, selecione o nome da instância de computação.

  3. Selecione Parar.

  4. Quando estiver pronto para voltar a utilizar o servidor, selecione Iniciar.

Eliminar tudo

Se não planear utilizar os recursos que criou, elimine-os, para que não incorra em custos:

  1. No portal do Azure, no menu esquerdo, selecione Grupos de recursos.
  2. Na lista de grupos de recursos, selecione o grupo de recursos que criou.
  3. Selecione Eliminar grupo de recursos.
  4. Introduza o nome do grupo de recursos. Em seguida, selecione Eliminar.

Também pode manter o grupo de recursos, mas eliminar uma única área de trabalho. Apresente as propriedades da área de trabalho e, em seguida, selecione Eliminar.

Passos seguintes

Neste tutorial, utilizou os seguintes tipos:

  • O Workspace representa a sua área de trabalho do Azure Machine Learning. Continha:
    • O Experiment que contém os resultados das execuções de preparação do pipeline
    • O Dataset que carregou preguiçosamente os dados guardados no arquivo de dados Fashion-MNIST
    • O ComputeTarget que representa as máquinas em que os passos do pipeline são executados
    • O Environment que é o ambiente de runtime no qual os passos do pipeline são executados
    • O Pipeline que compõe os PythonScriptStep passos num todo
    • O Model que registou depois de estar satisfeito com o processo de preparação

O Workspace objeto contém referências a outros recursos (blocos de notas, pontos finais, etc.) que não foram utilizados neste tutorial. Para obter mais informações, consulte O que é uma área de trabalho do Azure Machine Learning?.

O OutputFileDatasetConfig promove a saída de uma execução para um conjunto de dados baseado em ficheiros. Para obter mais informações sobre conjuntos de dados e trabalhar com dados, veja Como aceder a dados.

Para obter mais informações sobre destinos e ambientes de computação, veja O que são destinos de computação no Azure Machine Learning? e O que são ambientes do Azure Machine Learning?

Os ScriptRunConfig associados a ComputeTarget e Environment com ficheiros de origem python. A PythonScriptStep utiliza e ScriptRunConfig define as entradas e saídas, que neste pipeline foi o conjunto de dados de ficheiros criado pelo OutputFileDatasetConfig.

Para obter mais exemplos de como criar pipelines com o SDK de machine learning, veja o repositório de exemplo.