Tutorial: Criar um pipeline do Azure Machine Learning para classificação de imagem
APLICA-SE A: SDK do Python azureml v1
Observação
Para ver um tutorial que usa o SDK v2 para criar um pipeline, confira Tutorial: usar pipelines de ML para fluxos de trabalho de ML de produção com o SDK do Python v2 em um Jupyter Notebook.
Neste tutorial, você aprenderá a criar um pipeline do Azure Machine Learning para preparar dados e treinar um modelo de machine learning. Os pipelines de aprendizado de máquina otimizam o fluxo de trabalho com velocidade, portabilidade e reutilização, de modo que você possa se concentrar no aprendizado de máquina em vez de na infraestrutura e na automação.
O exemplo treina uma pequena rede neural convolucional Keras para classificar imagens no conjunto de dados Fashion MNIST.
Neste tutorial, você completa as seguintes tarefas:
- Configurar o workspace
- Criar um experimento para armazenar seu trabalho
- Provisionar um ComputeTarget para fazer o trabalho
- Criar um conjunto de dados no qual os dados compactados serão armazenados
- Criar uma etapa de pipeline para preparar os dados para treinamento
- Definir um ambiente de runtime no qual o treinamento será executado
- Criar uma etapa de pipeline para definir a rede neural e executar o treinamento
- Compor um pipeline com base nas etapas do pipeline
- Executar o pipeline no experimento
- Revisar a saída das etapas e a rede neural treinada
- Registrar o modelo para uso posterior
Caso não tenha uma assinatura 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
- Conclua Criar recursos para começar se você ainda não tiver um workspace do Azure Machine Learning.
- Um ambiente do Python no qual você instalou os pacotes
azureml-core
eazureml-pipeline
. Esse ambiente serve para definir e controlar seus recursos do Azure Machine Learning e é separado do ambiente usado em runtime para treinamento.
Importante
Atualmente, a versão mais recente do Python compatível com azureml-pipeline
é o Python 3.8. Caso tenha dificuldade para instalar o pacote azureml-pipeline
, verifique se python --version
é uma versão compatível. Consulte a documentação do gerenciador de ambiente virtual do Python (venv
, conda
etc.) para obter instruções.
Iniciar uma sessão interativa do Python
Este tutorial usa o SDK do Python para o Azure Machine Learning para criar e controlar um pipeline do Azure Machine Learning. O tutorial pressupõe que você executará os snippets de código de maneira interativa em um ambiente REPL do Python ou em um notebook Jupyter.
- Este tutorial se baseia no notebook
image-classification.ipynb
encontrado no diretóriopython-sdk/tutorial/using-pipelines
do repositório Exemplos do Azure Machine Learning. O código-fonte das etapas em si está no subdiretóriokeras-mnist-fashion
.
Tipos de importação
Importe todos os tipos do Azure Machine Learning que você precisará 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 1.37 ou superior. Caso contrário, atualize-a com pip install --upgrade azureml-core
.
Configurar o workspace
Crie um objeto de workspace do Workspace do Azure Machine Learning existente.
workspace = Workspace.from_config()
Importante
Esse snippet de código espera que a configuração do workspace seja salva no diretório atual ou no pai dele. Para obter mais informações sobre como criar um workspace, consulte Criar recursos de workspace. Para obter mais informações sobre como salvar a configuração no arquivo, confira Criar um arquivo de configuração de workspace.
Criar a infraestrutura para o pipeline
Crie um objeto Experiment
para armazenar os resultados das execuções de pipeline:
exp = Experiment(workspace=workspace, name="keras-mnist-fashion")
Crie um ComputeTarget
que representa o recurso do computador no qual o pipeline será executado. A rede neural simples usada neste tutorial faz o treinamento em apenas alguns minutos, mesmo em um computador baseado em CPU. Caso deseje usar uma GPU para treinamento, defina use_gpu
como True
. O provisionamento de um destino de computação geralmente leva 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())
Observação
A disponibilidade da GPU depende da cota da sua assinatura do Azure e da capacidade do Azure. Confira Gerenciar e aumentar cotas para recursos com o Azure Machine Learning.
Criar um conjunto de dados para os dados armazenados no Azure
O Fashion-MNIST é um conjunto de dados de imagens de moda dividido em dez classes. Cada imagem é uma imagem de escala de cinza 28x28, e há 60 mil imagens de treinamento e dez mil imagens de teste. Como um problema de classificação de imagem, o Fashion-MNIST é mais difícil do que o banco de dados de dígito manuscrito clássico do MNIST. Ele é distribuído no mesmo formato binário compactado do banco de dados de dígito manuscrito original.
Para criar um Dataset
que referencie os 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())
Esse código é concluído rapidamente. Os dados subjacentes permanecem no recurso de armazenamento do Azure especificado na matriz data_urls
.
Criar a etapa de pipeline de preparação de dados
A primeira etapa deste pipeline converterá os arquivos de dados compactados de fashion_ds
em um conjunto de dados no seu workspace que consiste em arquivos CSV prontos para uso no treinamento. Depois de registrados no workspace, os colaboradores poderão acessar esses dados para análise, treinamento 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 uma etapa de pipeline. Os arquivos processados subjacentes serão colocados no armazenamento de blobs do armazenamento de dados padrão do workspace no caminho especificado em destination
. O conjunto de dados será registrado no workspace com o nome prepared_fashion_ds
.
Criar a origem da etapa de pipeline
O código que você executou até agora criou e controlou recursos do Azure. Agora é hora de escrever um código que execute a primeira etapa no domínio.
Se você estiver acompanhando o exemplo no repositório Exemplos do Azure Machine Learning, o arquivo de origem já estará disponível como keras-mnist-fashion/prepare.py
.
Se estiver trabalhando do zero, crie um subdiretório chamado keras-mnist-fashion/
. Crie um arquivo, adicione o código a seguir a ele e nomeie o arquivo prepare.py
.
# 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
usa dois argumentos de linha de comando: o primeiro é atribuído a mounted_input_path
e o segundo, a mounted_output_path
. Se esse subdiretório não existir, a chamada a os.makedirs
o criará. Em seguida, o programa converte os dados de treinamento e de teste e gera os arquivos separados por vírgula no mounted_output_path
.
Especificar a etapa de pipeline
De volta ao ambiente do Python que você está usando 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 a etapa de pipeline for executada:
- Todos os arquivos do diretório
script_folder
serão carregados nocompute_target
- Entre esses arquivos de origem carregados, o arquivo
prepare.py
será executado - Os conjuntos de dados
fashion_ds
eprepared_fashion_ds
serão montados nocompute_target
e serão exibidos como diretórios - O caminho para os arquivos
fashion_ds
será o primeiro argumento paraprepare.py
. Emprepare.py
, esse argumento é atribuído amounted_input_path
- O caminho para o
prepared_fashion_ds
será o segundo argumento paraprepare.py
. Emprepare.py
, esse argumento é atribuído amounted_output_path
- Como
allow_reuse
éTrue
, ele só será executado novamente quando as entradas ou os respectivos arquivos de origem forem alterados - Esse
PythonScriptStep
será nomeadoprepare 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 no conjunto de dados. A saída de uma etapa que não é afetada será reutilizada sem uma nova execução das etapas se allow_reuse
for True
. Se uma etapa depender de uma fonte de dados externa ao Azure Machine Learning que possa ser alterada (por exemplo, uma URL que contenha dados de vendas), defina allow_reuse
como False
e a etapa de pipeline será executada sempre que o pipeline for executado.
Criar a etapa de treinamento
Depois que os dados são convertidos do formato compactado em arquivos CSV, eles podem ser usados para treinar uma rede neural convolucional.
Criar a origem da etapa de treinamento
Com pipelines maiores, é uma boa prática colocar o código-fonte de cada etapa em um diretório separado (src/prepare/
, src/train/
etc.), mas para este tutorial, basta usar ou criar o arquivo train.py
no mesmo diretório de origem keras-mnist-fashion/
.
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 desse código deve ser conhecida para os desenvolvedores de ML:
- Os dados são particionados em conjuntos de treinamento e validação para o treinamento e em um subconjunto de teste separado para a pontuação final
- A forma de entrada é 28x28x1 (apenas 1 porque a entrada é escala de cinza), haverá 256 entradas em um lote e há dez classes
- O número de épocas de treinamento será dez
- O modelo tem três camadas convolucionais, com o máximo de pools e abandono, seguido por uma camada densa e um cabeçalho softmax
- O modelo é ajustado para dez épocas e avaliado
- A arquitetura do modelo é gravada em
outputs/model/model.json
, e os pesos, emoutputs/model/model.h5
No entanto, uma parte do código é específica do Azure Machine Learning. run = Run.get_context()
recupera um objeto Run
que contém o contexto de serviço atual. A origem train.py
usa esse objeto run
para recuperar o conjunto de dados de entrada por meio do nome (uma alternativa para o código em prepare.py
que recuperou o conjunto de dados por meio da matriz argv
de argumentos de script).
O objeto run
também é usado para registrar o progresso do treinamento no final de cada época e, no final do treinamento, para registrar em log o grafo de perda e precisão ao longo do tempo.
Criar a etapa de pipeline de treinamento
A etapa de treinamento tem uma configuração um pouco mais complexa do que a etapa de preparação. A etapa de preparação usou apenas bibliotecas padrão do Python. Mais frequentemente, você precisará modificar o ambiente de runtime no qual o código-fonte é executado.
Crie um arquivo conda_dependencies.yml
com o seguinte conteúdo:
dependencies:
- python=3.7
- pip:
- azureml-core
- azureml-dataset-runtime
- keras==2.4.3
- tensorflow==2.4.3
- numpy
- scikit-learn
- pandas
- matplotlib
A classe Environment
representa o ambiente de runtime no qual uma tarefa de machine learning é executada. Associe a especificação acima ao código de treinamento a:
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 da etapa de treinamento em si usa um código semelhante ao código usado para criar a etapa 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 você especificou as entradas e as saídas de dados e criou as etapas do pipeline, você pode compô-las em um pipeline e executá-las:
pipeline = Pipeline(workspace, steps=[prep_step, train_step])
run = exp.submit(pipeline)
O objeto Pipeline
criado é executado no workspace
e é composto pelas etapas de preparação e de treinamento que você especificou.
Observação
Esse pipeline tem um grafo de dependência simples: a etapa de treinamento depende da etapa de preparação e a etapa de preparação depende do conjunto de dados fashion_ds
. Os pipelines de produção geralmente terão dependências muito mais complexas. As etapas podem depender de várias etapas upstream, uma alteração de código-fonte em uma etapa inicial pode ter consequências abrangentes etc. O Azure Machine Learning controla essas preocupações para você. Você só precisa transmitir a matriz de steps
e o Azure Machine Learning cuida do cálculo do grafo de execução.
A chamada para submit
o Experiment
é concluída rapidamente e produz uma saída semelhante a:
Submitted PipelineRun 5968530a-abcd-1234-9cc1-46168951b5eb
Link to Azure Machine Learning Portal: https://ml.azure.com/runs/abc-xyz...
Monitore a execução do pipeline abrindo o link ou bloqueie-a até que ela seja concluída executando:
run.wait_for_completion(show_output=True)
Importante
A primeira execução do pipeline leva aproximadamente 15 minutos. Todas as dependências precisam ser baixadas, uma imagem do Docker é criada e o ambiente do Python é provisionado e criado. Executar o pipeline novamente leva significativamente menos tempo, porque esses recursos são reutilizados, em vez de serem criados. No entanto, o tempo de execução total do pipeline depende da carga de trabalho dos seus scripts e dos processos sendo executados em cada etapa de pipeline.
Depois que o pipeline for concluído, você poderá recuperar as métricas registradas em log na etapa de treinamento:
run.find_step_run("train step")[0].get_metrics()
Se estiver satisfeito com as métricas, registre o modelo no seu workspace:
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 seção se desejar executar outros tutoriais do Azure Machine Learning.
Parar a instância de computação
Caso tenha usado uma instância de computação, interrompa a VM quando ela não estiver sendo usada para reduzir o custo.
No workspace, selecione Computação.
Na lista, selecione o nome da instância de computação.
Selecione Interromper.
Quando estiver pronto para usar o servidor novamente, selecione Iniciar.
Excluir tudo
Se você não pretende usar os recursos criados, exclua-os para não gerar encargos:
- No portal do Azure, no menu esquerdo, selecione Grupos de recursos.
- Na lista de grupos de recursos, selecione o grupo de recursos criado.
- Selecione Excluir grupo de recursos.
- Insira o nome do grupo de recursos. Em seguida, selecione Excluir.
Você também pode manter o grupo de recursos, mas excluir um único workspace. Exiba as propriedades do workspace e, em seguida, selecione Excluir.
Próximas etapas
Neste tutorial, você usou os seguintes tipos:
- O
Workspace
representa seu workspace do Azure Machine Learning. Ele continha:- O
Experiment
que contém os resultados das execuções de treinamento do pipeline - O
Dataset
que carregou lentamente os dados mantidos no armazenamento de dados Fashion-MNIST - O
ComputeTarget
que representa os computadores em que as etapas de pipeline são executadas - O
Environment
que é o ambiente de runtime no qual as etapas de pipeline são executadas - O
Pipeline
que compõe as etapasPythonScriptStep
como um todo - O
Model
que você registrou depois de estar satisfeito com o processo de treinamento
- O
O objeto Workspace
contém referências a outros recursos (notebooks, pontos de extremidade etc.) que não foram usados neste tutorial. Para saber mais, confira O que é um workspace do Azure Machine Learning?.
A OutputFileDatasetConfig
promove a saída de uma execução para um conjunto de dados baseado em arquivo. Para obter mais informações sobre conjuntos de dados e como usá-los, confira Como acessar dados.
Para saber mais sobre ambientes e destinos de computação, confira O que são destinos de computação no Azure Machine Learning? e O que são ambientes do Azure Machine Learning?
A ScriptRunConfig
associa um ComputeTarget
e Environment
a arquivos de origem do Python. Uma PythonScriptStep
usa essa ScriptRunConfig
e define as entradas e as saídas, que nesse pipeline foi o conjunto de dados do arquivo criado pela OutputFileDatasetConfig
.
Para ver mais exemplos de como criar pipelines usando o SDK de machine learning, confira o repositório de exemplos.