Учебник. Создание конвейера машинного обучения Azure для классификации изображений

ОБЛАСТЬ ПРИМЕНЕНИЯ:Пакет SDK для Python для ML Azure версии 1

Из этого учебника вы узнаете, как создать конвейер машинного обучения Azure для подготовки данных и обучения модели машинного обучения. Конвейеры машинного обучения оптимизируют ваш рабочий процесс за счет ускорения, мобильности и повторного использования, позволяя вам сосредоточиться непосредственно на задачах обучения, а не на сложностях инфраструктуры.

В этом примере небольшая сверточная нейронная сеть Keras обучается классификации изображений в наборе данных Fashion MNIST.

В этом руководстве выполняются следующие задачи:

  • Настройка рабочей области
  • Создание эксперимента для хранения результатов работы
  • Подготовка ComputeTarget для выполнения работы
  • Создание набора данных для хранения сжатых данных
  • Создание этапа конвейера для подготовки данных для обучения
  • Определение среды выполнения, в которой будет выполняться обучение
  • Создание этапа конвейера для определения нейронной сети и выполнения обучения
  • Составление конвейера из этапов конвейера
  • Запуск конвейера в эксперименте
  • Проверка выходных данных этапов и обученной нейронной сети
  • Регистрация модели для дальнейшего использования

Если у вас еще нет подписки Azure, создайте бесплатную учетную запись, прежде чем начинать работу. Опробуйте бесплатную или платную версию Машинного обучения Azure уже сегодня.

Предварительные требования

  • Выполните инструкции из краткого руководства по началу работы с Машинным обучением Azure, если у вас еще нет рабочей области службы "Машинное обучение Azure".
  • Среда Python, в которой установлены пакеты azureml-core и azureml-pipeline. Эта среда предназначена для определения ресурсов машинного обучения Azure и управления ими и отделена от среды, используемой для запуска обучения.

Важно!

В настоящее время самым последним выпуском Python, совместимым с azureml-pipeline, является Python 3.8. Если вы не смогли установить пакет azureml-pipeline, убедитесь, что python --version — совместимый выпуск. Инструкции см. в документации по диспетчеру виртуальных сред Python (venv, conda и т. д.).

Запуск интерактивного сеанса Python

В этом учебнике используется пакет Python SDK для Azure ML для создания конвейера машинного обучения Azure и управления им. В руководстве предполагается, что вы будете запускать фрагменты кода в интерактивном режиме в среде Python REPL или в записной книжке Jupyter Notebook.

  • Этот учебник основан на записной книжке image-classification.ipynb, которая находится в каталоге python-sdk/tutorial/using-pipelines репозитория примеров AzureML. Исходный код для самих этапов находится в подкаталоге keras-mnist-fashion.

Типы импорта

Импортируйте все типы машинного обучения Azure, необходимые для работы с этим учебником:

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 ML SDK Version: ", azureml.core.VERSION)

Версия пакета SDK для Azure ML должна быть 1.37 или более поздняя. Если это не так, выполните обновление с помощью pip install --upgrade azureml-core.

Настройка рабочей области

В имеющейся рабочей области Машинного обучения Azure создайте объект.

workspace = Workspace.from_config()

Важно!

Этот фрагмент кода ищет конфигурацию рабочей области в текущем или родительском каталоге. Дополнительные сведения о создании рабочей области см. в разделе Создание ресурсов рабочей области. Дополнительные сведения о сохранении конфигурации в файле см. в разделе Создание файла конфигурации рабочей области.

Создание инфраструктуры для конвейера

Создайте объект Experiment для хранения результатов выполнения конвейера:

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

Создайте объект ComputeTarget, представляющий ресурс компьютера, на котором будет выполняться конвейер. Простая нейронная сеть, используемая в этом учебнике, обучается всего за несколько минут даже на компьютере на основе ЦП. Если вы хотите использовать GPU для обучения, задайте для параметра use_gpu значение True. Подготовка целевого объекта вычислений обычно занимает около пяти минут.

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

Примечание

Доступность GPU зависит от квоты подписки Azure и от емкости Azure. См. статью Управление квотами на ресурсы для Машинного обучения Azure и их увеличение.

Создание набора данных для данных, хранящихся в Azure

Fashion-MNIST — это набор изображений объектов моды, разделенный на 10 классов. Каждое изображение представляет собой изображение в оттенках серого 28x28, и имеется 60 000 обучающих и 10 000 тестовых изображений. С точки зрения классификации изображений, Fashion-MNIST сложнее, чем классическая база данных MNIST с рукописными цифрами. Она распространяется в той же сжатой двоичной форме, что и исходная база данных с рукописными цифрами.

Чтобы создать Dataset, ссылающийся на веб-данные, выполните следующую команду:

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

Этот код выполняется быстро. Базовые данные остаются в ресурсе хранилища Azure, указанном в массиве data_urls.

Создание этапа конвейера подготовки данных

На первом этапе этого конвейера сжатые файлы данных fashion_ds будут преобразованы в набор данных в вашей собственной рабочей области, состоящий из CSV-файлов, готовых для использования в обучении. После регистрации в рабочей области участники совместной работы могут получить доступ к этим данным для собственного анализа, обучения и т. д.

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

Приведенный выше код задает набор данных, основанный на выходных данных этапа конвейера. Базовые обработанные файлы будут размещены в хранилище BLOB-объектов рабочей области по умолчанию по пути, указанному в destination. Набор данных будет зарегистрирован в рабочей области с именем prepared_fashion_ds.

Создание источника этапа конвейера

Код, который вы выполняли до текущего момента, создавал и контролировал ресурсы Azure. Теперь пришло время написать код, который выполняет первый этап в домене.

Если вы следуете примеру в репозитории примеров AzureML, исходный файл уже доступен как keras-mnist-fashion/prepare.py.

Если вы работаете с нуля, создайте подкаталог с именем keras-mnist-fashion/. Создайте новый файл, добавьте в него следующий код и назовите файл 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,
)

Код в prepare.py принимает два аргумента командной строки: первый назначается mounted_input_path, а второй — mounted_output_path. Если этот подкаталог не существует, вызов os.makedirs создает его. Затем программа преобразует данные для обучения и тестирования и выводит файлы с разделителями-запятыми в mounted_output_path.

Определение этапа конвейера

В среде Python, которую вы используете для определения конвейера, запустите следующий код, чтобы создать PythonScriptStep для подготовительного кода:

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

Вызов метода PythonScriptStep указывает на следующее при выполнении этапа конвейера.

  • Все файлы в каталоге script_folder передаются в compute_target
  • Среди переданных исходных файлов будет выполняться файл prepare.py
  • Наборы данных fashion_ds и prepared_fashion_ds будут подключены к compute_target и будут отображаться в виде каталогов
  • Путь к файлам fashion_ds будет первым аргументом для prepare.py. В prepare.py этому аргументу присваивается значение mounted_input_path
  • Путь к параметру prepared_fashion_ds будет вторым аргументом для prepare.py. В prepare.py этому аргументу присваивается значение mounted_output_path
  • Так как параметр allow_reuse имеет значение True, он не будет перезапущен до изменения исходных файлов или входных данных
  • Этот PythonScriptStep будет называться prepare step

Модульность и многократное использование являются ключевыми преимуществами конвейеров. Машинное обучение Azure может автоматически определять изменения исходного кода или набора данных. Выходные данные этапа, который не затрагивается, будут повторно использоваться без повторного выполнения этапов, если allow_reuse имеет значение True. Если этап зависит от источника данных, внешнего по отношению к Машинному обучению Azure, который может измениться (например, URL-адрес, содержащий данные о продажах), задайте для allow_reuse значение False, и этап конвейера будет выполняться при каждом выполнении конвейера.

Создание этапа обучения

После преобразования данных из сжатого формата в CSV-файлы их можно использовать для обучения сверточной нейронной сети.

Создание источника этапа обучения

При использовании больших конвейеров рекомендуется размещать исходный код каждого этапа в отдельном каталоге (src/prepare/, src/train/ и т. д.), но в рамках этого учебника просто используйте или создайте файл train.py в том же исходном каталоге 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")

Большая часть этого кода должна быть знакома разработчикам ML:

  • Данные разделены на обучающие и проверочные наборы для обучения, а также отдельные тестовые подмножества для окончательной оценки
  • Входной фигурой является 28x28x1 (только 1, поскольку входные данные представлены в оттенках серого), в пакете будет 256 входных данных, а также 10 классов
  • Количество эпох обучения будет равно 10
  • Модель имеет три сверточных слоя с максимальным объединением в пул и выпадением, а затем плотным слоем и головкой softmax
  • Модель предназначена для 10 эпох обучения, после чего она оценивается
  • Архитектура модели записывается в outputs/model/model.json, а весовые коэффициенты в outputs/model/model.h5

Однако часть кода относится только к Машинному обучению Azure. run = Run.get_context() извлекает объект Run, который содержит текущий контекст службы. Источник train.py использует этот объект run для извлечения входного набора данных по его имени (альтернатива коду в prepare.py, который извлекает набор данных через массив argv аргументов скрипта).

Объект run также используется для регистрации хода обучения в конце каждой эпохи и, в конце обучения, для регистрации графа потерь и точности с течением времени.

Создание этапа обучения конвейера

Этап обучения имеет немного более сложную конфигурацию, чем этап подготовки. На этапе подготовки использовались только стандартные библиотеки Python. Чаще всего требуется изменить среду выполнения, в которой выполняется исходный код.

Создайте файл conda_dependencies.yml со следующим содержимым:

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

Класс Environment представляет среду выполнения, в которой выполняется задача машинного обучения. Свяжите указанную выше спецификацию с кодом обучения с помощью следующего:

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

При создании самого этапа обучения используется код, аналогичный коду, который используется для создания шага подготовки:

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

Создание и запуск конвейера

Теперь, когда вы указали входные и выходные данные и создали этапы конвейера, вы можете объединить их в конвейер и запустить его:

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

Создаваемый вами объект Pipeline выполняется в workspace и состоит из указанных вами этапов подготовки и обучения.

Примечание

Этот конвейер имеет простой граф зависимостей: этап обучения зависит от этапа подготовки, а этап подготовки зависит от набора данных fashion_ds. Рабочие конвейеры часто имеют гораздо более сложные зависимости. Этапы могут опираться на несколько вышестоящих этапов, изменение исходного кода на раннем этапе может иметь слишком большое значение и т. д. Машинное обучение Azure отслеживает эти проблемы. Вам нужно только передать массив steps, и Машинное обучение Azure позаботится о расчете графа выполнения.

Вызов submitExperiment завершается быстро и создает выходные данные примерно следующим образом:

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

Вы можете отслеживать выполнение конвейера, открыв ссылку, или заблокировать его до завершения, выполнив следующее:

run.wait_for_completion(show_output=True)

Важно!

Первый запуск конвейера занимает примерно 15 минут. Необходимо скачать все зависимости, создать образ Docker и подготовить и создать среду Python. Повторный запуск конвейера занимает значительно меньше времени, так как эти ресурсы используются повторно, а не создаются. Однако общее время запуска для конвейера зависит от рабочей нагрузки ваших скриптов и процессов, выполняемых в каждом шаге конвейера.

После завершения конвейера можно получить метрики, которые вы зарегистрировали на этапе обучения:

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

Если вы удовлетворены метриками, вы можете зарегистрировать модель в рабочей области:

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

Очистка ресурсов

Не выполняйте инструкции из этого раздела, если вы собираетесь изучать другие руководства по Машинному обучению Azure.

Остановка вычислительной операции

Если вы использовали вычислительный экземпляр, завершите работу неиспользуемой виртуальной машины, чтобы сократить расходы.

  1. В своей рабочей области выберите Вычисление.

  2. В списке выберите имя вычислительного экземпляра.

  3. Выберите Остановить.

  4. Когда вам снова понадобится использовать сервер, выберите Запустить.

Удаление всех ресурсов

Если вы не планируете использовать созданные ресурсы, удалите их, чтобы с вас не взималась плата.

  1. На портале Azure в меню слева выберите Группы ресурсов.
  2. В списке групп ресурсов выберите созданную группу ресурсов.
  3. Выберите Удалить группу ресурсов.
  4. Введите имя группы ресурсов. Затем нажмите кнопку Удалить.

Вы также можете сохранить группу ресурсов, но удалить одну рабочую область. Отобразите свойства рабочей области и нажмите кнопку Удалить.

Дальнейшие действия

В рамках этого учебника вы использовали следующие типы.

  • Workspace представляет рабочую область машинного обучения Azure. Она содержит следующее:
    • объект Experiment, содержащий результаты запусков обучения конвейера;
    • объект Dataset, который отложенно загружал данные, хранящиеся в хранилище данных MNIST;
    • объект ComputeTarget, представляющий компьютеры, на которых выполняются этапы конвейера;
    • объект Environment, являющийся средой выполнения, в которой выполняются этапы конвейера;
    • объект Pipeline, который объединяет этапы PythonScriptStep в единое целое;
    • объект Model, который вы зарегистрировали после того, как остались удовлетворены процессом обучения.

Объект Workspace содержит ссылки на другие ресурсы (записные книжки, конечные точки и т. д.), которые не использовались в этом учебнике. Подробные сведения см. в разделе Что такое рабочая область Машинного обучения Azure?.

Объект OutputFileDatasetConfig передает выходные данные выполнения в файловый набор данных. Дополнительные сведения о наборах данных и работе с данными см. в разделе Получение доступа к данным.

Дополнительные сведения о целевых объектах вычислений и средах см. в статьях Что такое целевые объекты вычислений в Машинном обучении Azure? и Что такое среды Машинного обучения Azure?

Объект ScriptRunConfig связывает ComputeTarget и Environment с исходными файлами Python. Объект PythonScriptStep берет этот ScriptRunConfig и определяет его входные и выходные данные, которые в этом конвейере были файловым набором данных, созданным OutputFileDatasetConfig.

Дополнительные примеры создания конвейеров с помощью пакета SDK для машинного обучения см. в репозитории примеров.