Tutorial: criar pipelines de aprendizado de máquina de produção

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

Observação

Para obter um tutorial que usa o SDK v1 para compilar um pipeline, consulte Tutorial: Criar um pipeline de Azure Machine Learning para classificação de imagem

O foco de um pipeline de machine learning é dividir uma tarefa completa de machine learning em um fluxo de trabalho de várias etapas. Cada etapa é um componente gerenciável que pode ser desenvolvido, otimizado, configurado e automatizado individualmente. As etapas são conectadas por meio de interfaces bem definidas. O serviço de pipeline do Azure Machine Learning orquestra automaticamente todas as dependências entre as etapas do pipeline. Os benefícios de usar um pipeline são a padronização da prática de MLOps, a colaboração escalonável em equipe, a eficiência de treinamento e a redução de custos. Para saber mais sobre os benefícios dos pipelines, confira O que são os pipelines do Azure Machine Learning.

Neste tutorial, você usará o Azure Machine Learning para criar um projeto de aprendizado de máquina pronto para a produção, usando o SDK v2 do Python para o Azure Machine Learning.

Isso significa que você poderá aproveitar o SDK do Python do Azure Machine Learning para:

  • Obter um identificador para o workspace do Azure Machine Learning
  • Criar ativos de dados do Azure Machine Learning
  • Criar componentes reutilizáveis do Azure Machine Learning
  • Criar, validar e executar pipelines do Azure Machine Learning

Neste tutorial, você criará um pipeline do Azure Machine Learning para treinar um modelo para a previsão padrão de crédito. O pipeline identifica duas etapas:

  1. Preparação de dados
  2. Treinamento e registro do modelo treinado

A próxima abaixo mostra um pipeline simples como você o veria no estúdio do Azure depois de submetido.

As duas etapas são a primeira preparação de dados e o segundo treinamento.

Diagram shows overview of the pipeline.

Este vídeo mostra como começar a usar o Estúdio do Azure Machine Learning para que você possa seguir as etapas no tutorial. O vídeo mostra como criar um notebook, criar uma instância de computação e clonar o notebook. Essas etapas estão descritas nas seções a seguir.

Pré-requisitos

  1. Para usar o Azure Machine Learning, primeiro você precisará de um workspace. Se você não tiver um, conclua Criar recursos necessários para começar para criar um workspace e saber mais sobre como usá-lo.

  2. Entre no estúdio e selecione seu workspace, caso ele ainda não esteja aberto.

  3. Faça o tutorial Carregar, acessar e explorar seus dados para criar o ativo de dados de que você precisa nesse tutorial. Certifique-se de executar o código inteiro para criar o ativo de dados inicial. Explore os dados e revise-os se quiser, mas nesse tutorial você só precisará dos dados iniciais.

  4. Abra ou crie um notebook em seu workspace:

    • Crie um novo notebook, se você quiser copiar/colar código em células.
    • Ou abra tutoriais/get-started-notebooks/quickstart.ipynb na seção Exemplos do estúdio. Em seguida, selecione Clonar para adicionar o notebook aos seus Arquivos. (Veja onde encontrar Exemplos.)

Definir o kernel

  1. Na barra superior acima do notebook aberto, crie uma instância de computação se você ainda não tiver uma.

    Screenshot shows how to create a compute instance.

  2. Se a instância de computação for interrompida, selecione Iniciar computação e aguarde até que ela esteja em execução.

    Screenshot shows how to start compute if it is stopped.

  3. Verifique se o kernel, encontrado no canto superior direito, é Python 3.10 - SDK v2. Caso contrário, use a lista suspensa para selecionar esse kernel.

    Screenshot shows how to set the kernel.

  4. Se você vir uma barra de notificação dizendo que você precisa de autenticação, selecione Autenticar.

Importante

O restante deste tutorial contém células do notebook do tutorial. Copie-as/cole-as no novo notebook ou, no caso de um notebook clonado, mude para ele.

Configurar os recursos de pipeline

A estrutura do Azure Machine Learning pode ser usada na CLI, no SDK do Python ou na interface do estúdio. Neste exemplo, você usará o SDK v2 do Python do Azure Machine Learning para criar um pipeline.

Antes de criar o pipeline, você precisa dos seguintes recursos:

  • O ativo de dados para treinamento
  • O ambiente de software para executar o pipeline
  • Um recurso de computação para o local onde o trabalho será executado

Criar identificador para o workspace

Antes de nos aprofundarmos no código, você precisa de uma maneira de referenciar seu workspace. Você criará um ml_client para um identificador do workspace. Em seguida, você usará ml_client para gerenciar recursos e trabalhos.

Na próxima célula, insira a ID da Assinatura, o nome do Grupo de Recursos e o nome do Espaço de trabalho. Para encontrar esses valores:

  1. Na barra de ferramentas do Estúdio do Azure Machine Learning superior direito, selecione o nome do espaço de trabalho.
  2. Copie o valor do workspace, do grupo de recursos e da ID da assinatura no código.
  3. Será necessário copiar um valor, fechar a área e colar, em seguida, voltar para o próximo.
from azure.ai.ml import MLClient
from azure.identity import DefaultAzureCredential

# authenticate
credential = DefaultAzureCredential()

SUBSCRIPTION="<SUBSCRIPTION_ID>"
RESOURCE_GROUP="<RESOURCE_GROUP>"
WS_NAME="<AML_WORKSPACE_NAME>"
# Get a handle to the workspace
ml_client = MLClient(
    credential=credential,
    subscription_id=SUBSCRIPTION,
    resource_group_name=RESOURCE_GROUP,
    workspace_name=WS_NAME,
)

Observação

A criação do MLClient não se conectará ao espaço de trabalho. A inicialização do cliente é lenta, e ele aguarda a primeira vez que precisa fazer uma chamada (isso acontecerá na próxima célula de código).

Verifique a conexão fazendo uma chamada para ml_client. Como esta é a primeira vez que você está fazendo uma chamada para o workspace, talvez seja solicitado que você se autentique.

# Verify that the handle works correctly.  
# If you ge an error here, modify your SUBSCRIPTION, RESOURCE_GROUP, and WS_NAME in the previous cell.
ws = ml_client.workspaces.get(WS_NAME)
print(ws.location,":", ws.resource_group)

Acessar o ativo de dados registrado

Comece obtendo os dados registrados anteriormente no Tutorial: carregar, acessar e explorar seus dados no Azure Machine Learning.

  • O Azure Machine Learning usa um objeto Data para registrar uma definição reutilizável de dados e consumir os dados em um pipeline.
# get a handle of the data asset and print the URI
credit_data = ml_client.data.get(name="credit-card", version="initial")
print(f"Data asset URI: {credit_data.path}")

Criar um ambiente de trabalho para etapas de pipeline

Até agora, você criou um ambiente de desenvolvimento na instância de computação, seu computador de desenvolvimento. Você também precisará de um ambiente para usar para cada etapa do pipeline. Cada etapa pode ter seu próprio ambiente ou você pode usar alguns ambientes comuns para várias etapas.

Neste exemplo, você criará um ambiente conda para seus trabalhos usando um arquivo conda YAML. Primeiro, crie um diretório para armazenar o arquivo.

import os

dependencies_dir = "./dependencies"
os.makedirs(dependencies_dir, exist_ok=True)

Agora, crie o arquivo no diretório de dependências.

%%writefile {dependencies_dir}/conda.yaml
name: model-env
channels:
  - conda-forge
dependencies:
  - python=3.8
  - numpy=1.21.2
  - pip=21.2.4
  - scikit-learn=0.24.2
  - scipy=1.7.1
  - pandas>=1.1,<1.2
  - pip:
    - inference-schema[numpy-support]==1.3.0
    - xlrd==2.0.1
    - mlflow== 2.4.1
    - azureml-mlflow==1.51.0

A especificação contém alguns pacotes comuns que você usará no seu pipeline (numpy, Pip), acompanhado de alguns pacotes específicos do Azure Machine Learning (azureml-defaults, azureml-mlflow).

Os pacotes do Azure Machine Learning não são obrigatórios para executar os trabalhos do Azure Machine Learning. No entanto, a adição desses pacotes permitirá que você interaja com o Azure Machine Learning para registrar métricas de log e registrar modelos, tudo isso no trabalho do Azure Machine Learning. Você os usará no script de treinamento mais adiante neste tutorial.

Use o arquivo YAML para criar e registrar esse ambiente personalizado em seu espaço de trabalho:

from azure.ai.ml.entities import Environment

custom_env_name = "aml-scikit-learn"

pipeline_job_env = Environment(
    name=custom_env_name,
    description="Custom environment for Credit Card Defaults pipeline",
    tags={"scikit-learn": "0.24.2"},
    conda_file=os.path.join(dependencies_dir, "conda.yaml"),
    image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest",
    version="0.2.0",
)
pipeline_job_env = ml_client.environments.create_or_update(pipeline_job_env)

print(
    f"Environment with name {pipeline_job_env.name} is registered to workspace, the environment version is {pipeline_job_env.version}"
)

Compilar o pipeline de treinamento

Agora que você tem todos os ativos necessários para executar seu pipeline, é hora de criar o pipeline em si.

Os pipelines do Azure Machine Learning são fluxos de trabalho de ML reutilizáveis que geralmente consistem em vários componentes. A vida típica de um componente é:

  • Escreva a especificação YAML do componente ou crie-o programaticamente usando ComponentMethod.
  • Opcionalmente, registre o componente com um nome e uma versão em seu espaço de trabalho, para torná-lo reutilizável e compartilhável.
  • Carregue esse componente do código de pipeline.
  • Implemente o pipeline usando entradas, saídas e parâmetros do componente.
  • Enviar o pipeline.

Há duas maneiras de criar um componente: definição programática e definição de YAML. As próximas duas seções orientam você na criação de um componente de ambas as maneiras. Você pode criar os dois componentes tentando ambas as opções ou escolher seu método preferido.

Observação

Neste tutorial, para simplificar, estamos usando a mesma computação para todos os componentes. No entanto, você pode definir cálculos diferentes para cada componente, por exemplo, adicionando uma linha como train_step.compute = "cpu-cluster". Para exibir um exemplo de criação de um pipeline com cálculos diferentes para cada componente, consulte a seção Trabalho de pipeline básico no tutorial de pipeline cifar-10.

Criar componente 1: preparação de dados (usando definição programática)

Vamos começar criando o primeiro componente. Esse componente manipula o pré-processamento dos dados. A tarefa de pré-processamento é executada no arquivo Python data_prep.py.

Primeiro, crie uma pasta de origem para o componente data_prep:

import os

data_prep_src_dir = "./components/data_prep"
os.makedirs(data_prep_src_dir, exist_ok=True)

Esse script executa a tarefa simples de dividir os dados em conjuntos de dados de treinamento e teste. O Azure Machine Learning monta conjuntos de dados como pastas para os cálculos. Portanto, criamos uma função auxiliar select_first_file para acessar o arquivo de dados na pasta de entrada montada.

MLFlow será usado para registrar os parâmetros e as métricas durante a execução do pipeline.

%%writefile {data_prep_src_dir}/data_prep.py
import os
import argparse
import pandas as pd
from sklearn.model_selection import train_test_split
import logging
import mlflow


def main():
    """Main function of the script."""

    # input and output arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("--data", type=str, help="path to input data")
    parser.add_argument("--test_train_ratio", type=float, required=False, default=0.25)
    parser.add_argument("--train_data", type=str, help="path to train data")
    parser.add_argument("--test_data", type=str, help="path to test data")
    args = parser.parse_args()

    # Start Logging
    mlflow.start_run()

    print(" ".join(f"{k}={v}" for k, v in vars(args).items()))

    print("input data:", args.data)

    credit_df = pd.read_csv(args.data, header=1, index_col=0)

    mlflow.log_metric("num_samples", credit_df.shape[0])
    mlflow.log_metric("num_features", credit_df.shape[1] - 1)

    credit_train_df, credit_test_df = train_test_split(
        credit_df,
        test_size=args.test_train_ratio,
    )

    # output paths are mounted as folder, therefore, we are adding a filename to the path
    credit_train_df.to_csv(os.path.join(args.train_data, "data.csv"), index=False)

    credit_test_df.to_csv(os.path.join(args.test_data, "data.csv"), index=False)

    # Stop Logging
    mlflow.end_run()


if __name__ == "__main__":
    main()

Agora que você tem um script que pode executar a tarefa desejada, crie um componente do Azure Machine Learning por meio dele.

Você usará o CommandComponent de uso geral que pode executar ações de linha de comando. Essa ação de linha de comando pode chamar diretamente comandos do sistema ou executar um script. As entradas/saídas são especificadas na linha de comando por meio da notação ${{ ... }}.

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

data_prep_component = command(
    name="data_prep_credit_defaults",
    display_name="Data preparation for training",
    description="reads a .xl input, split the input to train and test",
    inputs={
        "data": Input(type="uri_folder"),
        "test_train_ratio": Input(type="number"),
    },
    outputs=dict(
        train_data=Output(type="uri_folder", mode="rw_mount"),
        test_data=Output(type="uri_folder", mode="rw_mount"),
    ),
    # The source folder of the component
    code=data_prep_src_dir,
    command="""python data_prep.py \
            --data ${{inputs.data}} --test_train_ratio ${{inputs.test_train_ratio}} \
            --train_data ${{outputs.train_data}} --test_data ${{outputs.test_data}} \
            """,
    environment=f"{pipeline_job_env.name}:{pipeline_job_env.version}",
)

Opcionalmente, registre o componente no workspace para reutilização futura.

# Now we register the component to the workspace
data_prep_component = ml_client.create_or_update(data_prep_component.component)

# Create (register) the component in your workspace
print(
    f"Component {data_prep_component.name} with Version {data_prep_component.version} is registered"
)

Criar componente 2: treinamento (usando definição de YAML)

O segundo componente que você cria consumirá os dados de treinamento e teste, treinará um modelo baseado em árvore e retornará o modelo de saída. Use as funcionalidades de log do Azure Machine Learning para registrar e visualizar o progresso do aprendizado.

Você usou a classe CommandComponent para criar seu primeiro componente. Desta vez, você usará a definição de YAML para definir o segundo componente. Cada método tem suas próprias vantagens. Uma definição YAML pode realmente ser verificada ao longo do código e forneceria um acompanhamento de histórico legível. O método programático que usa CommandComponent pode ser mais fácil com documentação de classe interna e conclusão de código.

Crie o diretório para este componente:

import os

train_src_dir = "./components/train"
os.makedirs(train_src_dir, exist_ok=True)

Crie o script de treinamento no diretório:

%%writefile {train_src_dir}/train.py
import argparse
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import classification_report
import os
import pandas as pd
import mlflow


def select_first_file(path):
    """Selects first file in folder, use under assumption there is only one file in folder
    Args:
        path (str): path to directory or file to choose
    Returns:
        str: full path of selected file
    """
    files = os.listdir(path)
    return os.path.join(path, files[0])


# Start Logging
mlflow.start_run()

# enable autologging
mlflow.sklearn.autolog()

os.makedirs("./outputs", exist_ok=True)


def main():
    """Main function of the script."""

    # input and output arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("--train_data", type=str, help="path to train data")
    parser.add_argument("--test_data", type=str, help="path to test data")
    parser.add_argument("--n_estimators", required=False, default=100, type=int)
    parser.add_argument("--learning_rate", required=False, default=0.1, type=float)
    parser.add_argument("--registered_model_name", type=str, help="model name")
    parser.add_argument("--model", type=str, help="path to model file")
    args = parser.parse_args()

    # paths are mounted as folder, therefore, we are selecting the file from folder
    train_df = pd.read_csv(select_first_file(args.train_data))

    # Extracting the label column
    y_train = train_df.pop("default payment next month")

    # convert the dataframe values to array
    X_train = train_df.values

    # paths are mounted as folder, therefore, we are selecting the file from folder
    test_df = pd.read_csv(select_first_file(args.test_data))

    # Extracting the label column
    y_test = test_df.pop("default payment next month")

    # convert the dataframe values to array
    X_test = test_df.values

    print(f"Training with data of shape {X_train.shape}")

    clf = GradientBoostingClassifier(
        n_estimators=args.n_estimators, learning_rate=args.learning_rate
    )
    clf.fit(X_train, y_train)

    y_pred = clf.predict(X_test)

    print(classification_report(y_test, y_pred))

    # Registering the model to the workspace
    print("Registering the model via MLFlow")
    mlflow.sklearn.log_model(
        sk_model=clf,
        registered_model_name=args.registered_model_name,
        artifact_path=args.registered_model_name,
    )

    # Saving the model to a file
    mlflow.sklearn.save_model(
        sk_model=clf,
        path=os.path.join(args.model, "trained_model"),
    )

    # Stop Logging
    mlflow.end_run()


if __name__ == "__main__":
    main()

Como você pode ver neste script de treinamento, depois que o modelo é treinado, o arquivo de modelo é salvo e registrado no espaço de trabalho. Agora você pode usar o modelo registrado em pontos de extremidade de inferência.

Para o ambiente desta etapa, você usará um dos ambientes internos (coletados) do Azure Machine Learning. A marca azureml, informa ao sistema para usar a procura do nome em ambientes coletados. Primeiro, crie o arquivo YAML que descreve o componente:

%%writefile {train_src_dir}/train.yml
# <component>
name: train_credit_defaults_model
display_name: Train Credit Defaults Model
# version: 1 # Not specifying a version will automatically update the version
type: command
inputs:
  train_data: 
    type: uri_folder
  test_data: 
    type: uri_folder
  learning_rate:
    type: number     
  registered_model_name:
    type: string
outputs:
  model:
    type: uri_folder
code: .
environment:
  # for this step, we'll use an AzureML curate environment
  azureml:AzureML-sklearn-1.0-ubuntu20.04-py38-cpu:1
command: >-
  python train.py 
  --train_data ${{inputs.train_data}} 
  --test_data ${{inputs.test_data}} 
  --learning_rate ${{inputs.learning_rate}}
  --registered_model_name ${{inputs.registered_model_name}} 
  --model ${{outputs.model}}
# </component>

Agora, crie e registre o componente. Registrá-lo permite que você o reutiliza em outros pipelines. Além disso, qualquer outra pessoa com acesso ao seu workspace pode usar o componente registrado.

# importing the Component Package
from azure.ai.ml import load_component

# Loading the component from the yml file
train_component = load_component(source=os.path.join(train_src_dir, "train.yml"))

# Now we register the component to the workspace
train_component = ml_client.create_or_update(train_component)

# Create (register) the component in your workspace
print(
    f"Component {train_component.name} with Version {train_component.version} is registered"
)

Criar o pipeline a partir de componentes

Agora que os dois componentes estão definidos e registrados, você pode começar a implementar o pipeline.

Aqui, você usará dados de entrada, taxa de divisão e nome do modelo registrado como variáveis de entrada. Em seguida, chame os componentes e conecte-os por meio de seus identificadores de entradas/saídas. As saídas de cada etapa podem ser acessadas por meio da propriedade .outputs.

As funções de Python retornadas por load_component() funcionam como qualquer função de Python regular que usaremos em um pipeline para chamar cada etapa.

Para codificar o pipeline, você usará um decorador @dsl.pipeline específico que identifica os pipelines do Azure Machine Learning. No decorador, podemos especificar a descrição do pipeline e os recursos padrão, como computação e armazenamento. Como uma função de Python, os pipelines podem ter entradas. Em seguida, você pode criar várias instâncias de um único pipeline com entradas diferentes.

Aqui, usamosdados de entrada, taxa de divisão e nome do modelo registrado como variáveis de entrada. Em seguida, chamamos os componentes e conecte-os por meio de seus identificadores de entradas/saídas. As saídas de cada etapa podem ser acessadas por meio da propriedade .outputs.

# the dsl decorator tells the sdk that we are defining an Azure Machine Learning pipeline
from azure.ai.ml import dsl, Input, Output


@dsl.pipeline(
    compute="serverless",  # "serverless" value runs pipeline on serverless compute
    description="E2E data_perp-train pipeline",
)
def credit_defaults_pipeline(
    pipeline_job_data_input,
    pipeline_job_test_train_ratio,
    pipeline_job_learning_rate,
    pipeline_job_registered_model_name,
):
    # using data_prep_function like a python call with its own inputs
    data_prep_job = data_prep_component(
        data=pipeline_job_data_input,
        test_train_ratio=pipeline_job_test_train_ratio,
    )

    # using train_func like a python call with its own inputs
    train_job = train_component(
        train_data=data_prep_job.outputs.train_data,  # note: using outputs from previous step
        test_data=data_prep_job.outputs.test_data,  # note: using outputs from previous step
        learning_rate=pipeline_job_learning_rate,  # note: using a pipeline input as parameter
        registered_model_name=pipeline_job_registered_model_name,
    )

    # a pipeline returns a dictionary of outputs
    # keys will code for the pipeline output identifier
    return {
        "pipeline_job_train_data": data_prep_job.outputs.train_data,
        "pipeline_job_test_data": data_prep_job.outputs.test_data,
    }

Agora, use sua definição de pipeline para instanciar um pipeline com seu conjunto de dados, dividir a taxa de escolha e o nome escolhido para o modelo.

registered_model_name = "credit_defaults_model"

# Let's instantiate the pipeline with the parameters of our choice
pipeline = credit_defaults_pipeline(
    pipeline_job_data_input=Input(type="uri_file", path=credit_data.path),
    pipeline_job_test_train_ratio=0.25,
    pipeline_job_learning_rate=0.05,
    pipeline_job_registered_model_name=registered_model_name,
)

Enviar o trabalho

Agora é hora de enviar o trabalho a ser executado no Azure Machine Learning. Desta vez, você usa create_or_update em ml_client.jobs.

Aqui você também passará um nome de experimento. Um experimento é um contêiner para todas as iterações que se faz em um determinado projeto. Todos os trabalhos enviados com o mesmo nome de experimento serão listados um ao lado do outro no Estúdio do Azure Machine Learning.

Depois de concluído, o pipeline registrará um modelo no workspace como resultado do treinamento.

# submit the pipeline job
pipeline_job = ml_client.jobs.create_or_update(
    pipeline,
    # Project's name
    experiment_name="e2e_registered_components",
)
ml_client.jobs.stream(pipeline_job.name)

Você pode acompanhar o progresso do pipeline usando o link gerado na célula acima. Ao selecionar esse link pela primeira vez, você poderá ver que o pipeline ainda está em execução. Depois de concluído, você pode examinar os resultados de cada componente.

Clique duas vezes no componente Treinar Modelo de Padrões de Crédito .

Há dois importantes resultados que você deve conferir sobre o treinamento:

  • Exibir seus logs:

    1. Selecione a guia Saídas + logs.
    2. Abra as pastas para user_logs>std_log.txt Esta seção mostra o script executar stdout. Screenshot of std_log.txt.
  • Exibir suas métricas: selecione a guia Métricas. Esta seção mostra diferentes métricas registradas. Neste exemplo. mlflow autologging, registrou automaticamente as métricas de treinamento.

    Screenshot shows logged metrics.txt.

Implantar o modelo como um ponto de extremidade online

Para aprender como implantar seu modelo em um ponto de extremidade online, consulte Implantar um modelo como um tutorial de ponto de extremidade online.

Limpar os recursos

Se você planeja prosseguir agora para outros tutorial, vá diretamente para as Próximas etapas.

Parar a instância de computação

Se não for usá-la agora, pare a instância de computação:

  1. No estúdio, na área de navegação à esquerda, selecione Computação.
  2. Nas guias superiores, selecione Instâncias de computação
  3. Selecione a instância de computação na lista.
  4. Na barra de ferramentas superior, selecione Parar.

Excluir todos os recursos

Importante

Os recursos que você criou podem ser usados como pré-requisitos em outros tutoriais e artigos de instruções do Azure Machine Learning.

Se você não pretende usar nenhum dos recursos criados, exclua-os para não gerar custos:

  1. No portal do Azure, selecione Grupos de recursos no canto esquerdo.

  2. Selecione o grupo de recursos que você criou por meio da lista.

  3. Selecione Excluir grupo de recursos.

    Screenshot of the selections to delete a resource group in the Azure portal.

  4. Insira o nome do grupo de recursos. Em seguida, selecione Excluir.

Próximas etapas