Criar e executar pipelines de aprendizado de máquina usando componentes com o SDK do Azure Machine Learning v2

APLICA-SE A: Python SDK azure-ai-ml v2 (atual)

Neste artigo, você aprenderá a criar um pipeline do Azure Machine Learning usando o Python SDK v2 para concluir uma tarefa de classificação de imagem contendo três etapas: preparar dados, treinar um modelo de classificação de imagem e pontuar o modelo. Os pipelines de aprendizado de máquina otimizam seu fluxo de trabalho com velocidade, portabilidade e reutilização, para que você possa se concentrar no aprendizado de máquina em vez de infraestrutura e automação.

O exemplo treina uma pequena rede neural convolucional Keras para classificar imagens no conjunto de dados Fashion MNIST. O pipeline parece seguir.

Captura de tela mostrando o gráfico de pipeline do exemplo Keras de classificação de imagem.

Neste artigo, você conclui as seguintes tarefas:

  • Preparar dados de entrada para o trabalho de pipeline
  • Crie três componentes para preparar os dados, treinar e pontuar
  • Compor um pipeline a partir dos componentes
  • Obtenha acesso ao espaço de trabalho com computação
  • Enviar o trabalho de pipeline
  • Revise a saída dos componentes e a rede neural treinada
  • (Opcional) Registrar o componente para posterior reutilização e compartilhamento no espaço de trabalho

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

Pré-requisitos

  • Espaço de trabalho do Azure Machine Learning - se você não tiver um, conclua o tutorial Criar recursos.

  • Um ambiente Python no qual você instalou o SDK do Python do Azure Machine Learning v2 - instruções de instalação - verifique a seção de introdução. Esse ambiente serve para definir e controlar seus recursos do Azure Machine Learning e é separado do ambiente usado em tempo de execução para treinamento.

  • Repositório de exemplos de clonagem

    Para executar os exemplos de treinamento, primeiro clone o repositório de exemplos e altere para o sdk diretório:

    git clone --depth 1 https://github.com/Azure/azureml-examples
    cd azureml-examples/sdk
    

Iniciar uma sessão interativa do Python

Este artigo usa o SDK do Python para Azure Machine Learning para criar e controlar um pipeline do Azure Machine Learning. O artigo pressupõe que você executará os trechos de código interativamente em um ambiente Python REPL ou em um notebook Jupyter.

Este artigo é baseado no bloco de anotações image_classification_keras_minist_convnet.ipynb encontrado no sdk/python/jobs/pipelines/2e_image_classification_keras_minist_convnet diretório do repositório de Exemplos do Azure Machine Learning .

Importar bibliotecas necessárias

Importe todas as bibliotecas necessárias do Azure Machine Learning necessárias para este artigo:

# import required libraries
from azure.identity import DefaultAzureCredential, InteractiveBrowserCredential

from azure.ai.ml import MLClient
from azure.ai.ml.dsl import pipeline
from azure.ai.ml import load_component

Preparar dados de entrada para seu trabalho de pipeline

Você precisa preparar os dados de entrada para esse pipeline de classificação de imagem.

Fashion-MNIST é um conjunto de dados de imagens de moda dividido em 10 classes. Cada imagem é uma imagem em tons de cinza 28x28 e há 60.000 imagens de treinamento e 10.000 imagens de teste. Como um problema de classificação de imagem, o Fashion-MNIST é mais difícil do que o clássico banco de dados de dígitos manuscritos MNIST. É distribuído na mesma forma binária compactada que o banco de dados de dígitos manuscritos original.

Importe todas as bibliotecas necessárias do Azure Machine Learning de que necessita.

Ao definir um Input, você cria uma referência ao local da fonte de dados. Os dados permanecem em sua localização existente, portanto, nenhum custo de armazenamento extra é incorrido.

Criar componentes para a construção de pipeline

A tarefa de classificação de imagens pode ser dividida em três etapas: preparar dados, treinar modelo e modelo de pontuação.

O componente Azure Machine Learning é uma parte de código independente que executa uma etapa em um pipeline de aprendizado de máquina. Neste artigo, você criará três componentes para a tarefa de classificação de imagens:

  • Preparar dados para treinamento e teste
  • Treinar uma rede neural para classificação de imagens usando dados de treinamento
  • Pontuar o modelo usando dados de teste

Para cada componente, você precisa preparar o seguinte:

  1. Prepare o script Python que contém a lógica de execução

  2. Definir a interface do componente

  3. Adicione outros metadados do componente, incluindo ambiente de tempo de execução, comando para executar o componente e etc.

A próxima seção mostrará os componentes de criação de duas maneiras diferentes: os dois primeiros componentes usando a função Python e o terceiro componente usando a definição YAML.

Criar o componente de preparação de dados

O primeiro componente neste pipeline irá converter os arquivos de dados compactados em fashion_ds dois arquivos csv, um para treinamento e outro para pontuação. Você usará a função Python para definir esse componente.

Se você estiver acompanhando o exemplo no repositório de exemplos do Azure Machine Learning, os arquivos de origem já estão disponíveis na prep/ pasta. Esta pasta contém dois arquivos para construir o componente: prep_component.py, que define o componente e conda.yaml, que define o ambiente de tempo de execução do componente.

Definir componente usando a função Python

command_component() Usando a função como decorador, você pode facilmente definir a interface do componente, metadados e código para executar a partir de uma função Python. Cada função Python decorada será transformada em uma única especificação estática (YAML) que o serviço de pipeline pode processar.

# Converts MNIST-formatted files at the passed-in input path to training data output path and test data output path
import os
from pathlib import Path
from mldesigner import command_component, Input, Output


@command_component(
    name="prep_data",
    version="1",
    display_name="Prep Data",
    description="Convert data to CSV file, and split to training and test data",
    environment=dict(
        conda_file=Path(__file__).parent / "conda.yaml",
        image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04",
    ),
)
def prepare_data_component(
    input_data: Input(type="uri_folder"),
    training_data: Output(type="uri_folder"),
    test_data: Output(type="uri_folder"),
):
    convert(
        os.path.join(input_data, "train-images-idx3-ubyte"),
        os.path.join(input_data, "train-labels-idx1-ubyte"),
        os.path.join(training_data, "mnist_train.csv"),
        60000,
    )
    convert(
        os.path.join(input_data, "t10k-images-idx3-ubyte"),
        os.path.join(input_data, "t10k-labels-idx1-ubyte"),
        os.path.join(test_data, "mnist_test.csv"),
        10000,
    )


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

O código acima define um componente com nome Prep Data de exibição usando @command_component decorador:

  • name é o identificador exclusivo do componente.

  • version é a versão atual do componente. Um componente pode ter várias versões.

  • display_name é um nome de exibição amigável do componente na interface do usuário, que não é exclusivo.

  • description geralmente descreve qual tarefa esse componente pode concluir.

  • environment Especifica o ambiente de tempo de execução para este componente. O ambiente deste componente especifica uma imagem docker e refere-se ao conda.yaml arquivo.

    O conda.yaml arquivo contém todos os pacotes usados para o componente, como segue:

    name: imagekeras_prep_conda_env
    channels:
      - defaults
    dependencies:
      - python=3.7.11
      - pip=20.0
      - pip:
        - mldesigner==0.1.0b4
    
  • A prepare_data_component função define uma entrada para input_data e duas saídas para training_data e test_data. input_data é o caminho de dados de entrada. training_data e test_data são caminhos de dados de saída para dados de treinamento e dados de teste.

  • Este componente converte os dados de um csv de dados de treinamento para training_data e um csv de dados de input_data teste para test_data.

A seguir está a aparência de um componente na interface do usuário do estúdio.

  • Um componente é um bloco em um gráfico de pipeline.
  • O input_data, training_data e test_data são portas do componente, que se conecta a outros componentes para streaming de dados.

Captura de tela do componente Prep Data na interface do usuário e no código.

Agora, você preparou todos os arquivos de origem para o Prep Data componente.

Criar o componente train-model

Nesta seção, você criará um componente para treinar o modelo de classificação de imagem na função Python como o Prep Data componente.

A diferença é que, como a lógica de treinamento é mais complicada, você pode colocar o código de treinamento original em um arquivo Python separado.

Os arquivos de origem desse componente estão na train/ pasta no repositório de exemplos do Azure Machine Learning. Esta pasta contém três arquivos para construir o componente:

  • train.py: contém a lógica real para treinar o modelo.
  • train_component.py: define a interface do componente e importa a função em train.py.
  • conda.yaml: define o ambiente de tempo de execução do componente.

Obter um script contendo lógica de execução

O train.py arquivo contém uma função Python normal, que executa a lógica do modelo de treinamento para treinar uma rede neural Keras para classificação de imagem. Para visualizar o código, consulte o arquivo train.py no GitHub.

Definir componente usando a função Python

Depois de definir a função de treinamento com êxito, você pode usar @command_component no SDK do Azure Machine Learning v2 para encapsular sua função como um componente, que pode ser usado nos pipelines do Azure Machine Learning.

import os
from pathlib import Path
from mldesigner import command_component, Input, Output


@command_component(
    name="train_image_classification_keras",
    version="1",
    display_name="Train Image Classification Keras",
    description="train image classification with keras",
    environment=dict(
        conda_file=Path(__file__).parent / "conda.yaml",
        image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04",
    ),
)
def keras_train_component(
    input_data: Input(type="uri_folder"),
    output_model: Output(type="uri_folder"),
    epochs=10,
):
    # avoid dependency issue, execution logic is in train() func in train.py file
    from train import train

    train(input_data, output_model, epochs)

O código acima define um componente com nome Train Image Classification Keras de exibição usando @command_component:

  • A keras_train_component função define uma entrada input_data de onde vêm os dados de treinamento, uma entrada epochs especificando épocas durante o treinamento e uma saída output_model onde produz o arquivo de modelo. O valor padrão de epochs é 10. A lógica de execução deste componente é da train() função acima train.py .

O componente train-model tem uma configuração um pouco mais complexa do que o componente prep-data. O conda.yaml é como segue:

name: imagekeras_train_conda_env
channels:
  - defaults
dependencies:
  - python=3.7.11
  - pip=20.2
  - pip:
    - mldesigner==0.1.0b12
    - azureml-mlflow==1.50.0
    - tensorflow==2.7.0
    - numpy==1.21.4
    - scikit-learn==1.0.1
    - pandas==1.3.4
    - matplotlib==3.2.2
    - protobuf==3.20.0

Agora, você preparou todos os arquivos de origem para o Train Image Classification Keras componente.

Criar o componente de modelo de pontuação

Nesta seção, além dos componentes anteriores, você criará um componente para pontuar o modelo treinado por meio da especificação e do script do Yaml.

Se você estiver acompanhando o exemplo no repositório de exemplos do Azure Machine Learning, os arquivos de origem já estão disponíveis na score/ pasta. Esta pasta contém três arquivos para construir o componente:

  • score.py: contém o código-fonte do componente.
  • score.yaml: define a interface e outros detalhes do componente.
  • conda.yaml: define o ambiente de tempo de execução do componente.

Obter um script contendo lógica de execução

O score.py arquivo contém uma função Python normal, que executa a lógica do modelo de treinamento.

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

import argparse
from pathlib import Path
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
import mlflow


def get_file(f):

    f = Path(f)
    if f.is_file():
        return f
    else:
        files = list(f.iterdir())
        if len(files) == 1:
            return files[0]
        else:
            raise Exception("********This path contains more than one file*******")


def parse_args():
    # setup argparse
    parser = argparse.ArgumentParser()

    # add arguments
    parser.add_argument(
        "--input_data", type=str, help="path containing data for scoring"
    )
    parser.add_argument(
        "--input_model", type=str, default="./", help="input path for model"
    )

    parser.add_argument(
        "--output_result", type=str, default="./", help="output path for model"
    )

    # parse args
    args = parser.parse_args()

    # return args
    return args


def score(input_data, input_model, output_result):

    test_file = get_file(input_data)
    data_test = pd.read_csv(test_file, header=None)

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

    # Read test data
    X_test = np.array(data_test.iloc[:, 1:])
    y_test = to_categorical(np.array(data_test.iloc[:, 0]))
    X_test = (
        X_test.reshape(X_test.shape[0], img_rows, img_cols, 1).astype("float32") / 255
    )

    # Load model
    files = [f for f in os.listdir(input_model) if f.endswith(".h5")]
    model = load_model(input_model + "/" + files[0])

    # Log metrics of the model
    eval = model.evaluate(X_test, y_test, verbose=0)

    mlflow.log_metric("Final test loss", eval[0])
    print("Test loss:", eval[0])

    mlflow.log_metric("Final test accuracy", eval[1])
    print("Test accuracy:", eval[1])

    # Score model using test data
    y_predict = model.predict(X_test)
    y_result = np.argmax(y_predict, axis=1)

    # Output result
    np.savetxt(output_result + "/predict_result.csv", y_result, delimiter=",")


def main(args):
    score(args.input_data, args.input_model, args.output_result)


# run script
if __name__ == "__main__":
    # parse args
    args = parse_args()

    # call main function
    main(args)

O código no score.py usa três argumentos de linha de comando: input_data, input_model e output_result. O programa pontua o modelo de entrada usando dados de entrada e, em seguida, produz o resultado da pontuação.

Definir componente via Yaml

Nesta seção, você aprenderá a criar uma especificação de componente no formato de especificação de componente YAML válido. Este ficheiro especifica as seguintes informações:

  • Metadados: nome, display_name, versão, tipo e assim por diante.
  • Interface: entradas e saídas
  • Command, code, & environment: O comando, o código e o ambiente usados para executar o componente
$schema: https://azuremlschemas.azureedge.net/latest/commandComponent.schema.json
type: command

name: score_image_classification_keras
display_name: Score Image Classification Keras
inputs:
  input_data: 
    type: uri_folder
  input_model:
    type: uri_folder
outputs:
  output_result:
    type: uri_folder
code: ./
command: python score.py --input_data ${{inputs.input_data}} --input_model ${{inputs.input_model}} --output_result ${{outputs.output_result}}
environment:
  conda_file: ./conda.yaml
  image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04
  • name é o identificador exclusivo do componente. Seu nome de exibição é Score Image Classification Keras.
  • Este componente tem duas entradas e uma saída.
  • O caminho do código-fonte é definido na code seção e quando o componente é executado na nuvem, todos os arquivos desse caminho serão carregados como o instantâneo desse componente.
  • A command seção especifica o comando a ser executado durante a execução desse componente.
  • A environment seção contém uma imagem docker e um arquivo conda yaml. O arquivo de origem está no repositório de exemplo.

Agora, você tem todos os arquivos de origem para o componente de modelo de pontuação.

Carregar componentes para construir pipeline

Para o componente prep-data e o componente train-model definidos pela função Python, você pode importar os componentes da mesma forma que as funções normais do Python.

No código a seguir, você importa prepare_data_component() e keras_train_component() funciona do prep_component.py arquivo em prep pasta e train_component arquivo em train pasta, respectivamente.

%load_ext autoreload
%autoreload 2

# load component function from component python file
from prep.prep_component import prepare_data_component
from train.train_component import keras_train_component

# print hint of components
help(prepare_data_component)
help(keras_train_component)

Para o componente de pontuação definido pelo yaml, você pode usar load_component() a função para carregar.

# load component function from yaml
keras_score_component = load_component(source="./score/score.yaml")

Construa seu pipeline

Agora que você criou e carregou todos os componentes e dados de entrada para criar o pipeline. Você pode compô-los em um pipeline:

Nota

Para usar a computação sem servidor, adicione from azure.ai.ml.entities import ResourceConfiguration ao topo. Em seguida, substitua:

  • default_compute=cpu_compute_target, com default_compute="serverless",
  • train_node.compute = gpu_compute_target com train_node.resources = "ResourceConfiguration(instance_type="Standard_NC6s_v3",instance_count=2)
# define a pipeline containing 3 nodes: Prepare data node, train node, and score node
@pipeline(
    default_compute=cpu_compute_target,
)
def image_classification_keras_minist_convnet(pipeline_input_data):
    """E2E image classification pipeline with keras using python sdk."""
    prepare_data_node = prepare_data_component(input_data=pipeline_input_data)

    train_node = keras_train_component(
        input_data=prepare_data_node.outputs.training_data
    )
    train_node.compute = gpu_compute_target

    score_node = keras_score_component(
        input_data=prepare_data_node.outputs.test_data,
        input_model=train_node.outputs.output_model,
    )


# create a pipeline
pipeline_job = image_classification_keras_minist_convnet(pipeline_input_data=mnist_ds)

O pipeline tem uma computação cpu_compute_targetpadrão, o que significa que, se você não especificar computação para um nó específico, esse nó será executado na computação padrão.

O pipeline tem uma entrada pipeline_input_datade nível de pipeline. Você pode atribuir valor à entrada do pipeline ao enviar um trabalho de pipeline.

O pipeline contém três nós, prepare_data_node, train_node e score_node.

  • O input_data de prepare_data_node usa o valor de pipeline_input_data.

  • O input_data de train_node é da training_data saída do prepare_data_node.

  • O input_data de score_node é da test_data saída de prepare_data_node, e o input_model é do output_model de train_node.

  • Uma vez train_node que irá treinar um modelo CNN, você pode especificar seu cálculo como o gpu_compute_target, o que pode melhorar o desempenho do treinamento.

Envie seu trabalho de pipeline

Agora que você construiu o pipeline, pode enviar para o seu espaço de trabalho. Para enviar um trabalho, você precisa primeiro se conectar a um espaço de trabalho.

Obtenha acesso ao seu espaço de trabalho

Configurar credencial

Usaremos DefaultAzureCredential para ter acesso ao espaço de trabalho. DefaultAzureCredential deve ser capaz de lidar com a maioria dos cenários de autenticação do SDK do Azure.

Referência para mais credenciais disponíveis se não funcionar para você: configure credential example, azure-identity reference doc.

try:
    credential = DefaultAzureCredential()
    # Check if given credential can get token successfully.
    credential.get_token("https://management.azure.com/.default")
except Exception as ex:
    # Fall back to InteractiveBrowserCredential in case DefaultAzureCredential not work
    credential = InteractiveBrowserCredential()

Obter um identificador para um espaço de trabalho com computação

Crie um MLClient objeto para gerenciar os serviços do Azure Machine Learning. Se você usa computação sem servidor, não há necessidade de criar esses cálculos.

# Get a handle to workspace
ml_client = MLClient.from_config(credential=credential)

# Retrieve an already attached Azure Machine Learning Compute.
cpu_compute_target = "cpu-cluster"
print(ml_client.compute.get(cpu_compute_target))
gpu_compute_target = "gpu-cluster"
print(ml_client.compute.get(gpu_compute_target))

Importante

Este trecho de código espera que o arquivo json de configuração do espaço de trabalho seja salvo no diretório atual ou em seu pai. Para obter mais informações sobre como criar um espaço de trabalho, consulte Criar recursos do espaço de trabalho. Para obter mais informações sobre como salvar a configuração no arquivo, consulte Criar um arquivo de configuração do espaço de trabalho.

Enviar trabalho de pipeline para o espaço de trabalho

Agora que você já entendeu seu espaço de trabalho, pode enviar seu trabalho de pipeline.

pipeline_job = ml_client.jobs.create_or_update(
    pipeline_job, experiment_name="pipeline_samples"
)
pipeline_job

O código acima envia este trabalho de pipeline de classificação de imagem para o experimento chamado pipeline_samples. Ele criará automaticamente o experimento se não existir. Os pipeline_input_data usos fashion_ds.

A chamada para pipeline_jobproduz resultados semelhantes a:

A chamada para submit o Experiment é concluída rapidamente e produz resultados semelhantes a:

Experimentação Nome Tipo Status Details Page
pipeline_samples sharp_pipe_4gvqx6h1fb gasoduto Preparação Link para o estúdio de Aprendizado de Máquina do Azure.

Você pode monitorar a execução do pipeline abrindo o link ou pode bloquear até que ele seja concluído executando:

# wait until the job completes
ml_client.jobs.stream(pipeline_job.name)

Importante

A primeira execução do pipeline leva cerca de 15 minutos. Todas as dependências devem ser baixadas, uma imagem do Docker é criada e o ambiente Python é provisionado e criado. Executar o pipeline novamente leva 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 etapa do pipeline.

Fazer check-out de saídas e depurar seu pipeline na interface do usuário

Você pode abrir o Link to Azure Machine Learning studio, que é a página de detalhes do trabalho do seu pipeline. Você verá o gráfico de pipeline como segue.

Captura de tela da página de detalhes do trabalho de pipeline.

Você pode verificar os logs e saídas de cada componente clicando com o botão direito do mouse no componente ou selecionando o componente para abrir seu painel de detalhes. Para saber mais sobre como depurar seu pipeline na interface do usuário, consulte Como usar a falha do pipeline de depuração.

(Opcional) Registrar componentes no espaço de trabalho

Na seção anterior, você criou um pipeline usando três componentes para o E2E concluir uma tarefa de classificação de imagem. Você também pode registrar componentes em seu espaço de trabalho para que eles possam ser compartilhados e processados dentro do espaço de trabalho. Segue-se um exemplo para registar o componente prep-data.

try:
    # try get back the component
    prep = ml_client.components.get(name="prep_data", version="1")
except:
    # if not exists, register component using following code
    prep = ml_client.components.create_or_update(prepare_data_component)

# list all components registered in workspace
for c in ml_client.components.list():
    print(c)

Usando ml_client.components.get()o , você pode obter um componente registrado por nome e versão. Usando ml_client.components.create_or_update()o , você pode registrar um componente carregado anteriormente da função Python ou yaml.

Próximos passos