Создание и запуск конвейеров машинного обучения с помощью компонентов с пакетом SDK Машинное обучение Azure версии 2

ОБЛАСТЬ ПРИМЕНЕНИЯ: Пакет SDK для Python azure-ai-ml версии 2 (current)

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

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

Screenshot showing pipeline graph of the image classification Keras example.

В этой статье вы выполните следующие задачи:

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

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

Необходимые компоненты

  • Машинное обучение Azure рабочей области. Если у вас нет рабочей области, завершите Создание учебника по ресурсам.

  • Среда Python, в которой вы установили пакет SDK для Python Машинного обучения Azure версии 2. Инструкции по установке этой среды см. в разделе "Начало работы". Эта среда предназначена для определения ресурсов машинного обучения Azure и управления ими и отделена от среды, используемой для запуска обучения.

  • Клонирование репозитория примеров

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

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

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

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

Эта статья основана на записной книжке image_classification_keras_minist_convnet.ipynb, найденной в sdk/python/jobs/pipelines/2e_image_classification_keras_minist_convnet каталоге репозитория Машинное обучение Azure Examples.

Импорт обязательных библиотек

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

# 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

Подготовка входных данных для задания конвейера

Вам необходимо подготовить входные данные для этого конвейера классификации изображений.

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

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

from azure.ai.ml import Input

fashion_ds = Input(
    path="wasbs://demo@data4mldemo6150520719.blob.core.windows.net/mnist-fashion/"
)

Определяя Input, вы создаете ссылку на расположение источника данных. Данные хранятся только в исходном расположении, а значит не потребуется лишних расходов на хранение.

Создание компонентов для сборки конвейера

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

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

  • Подготовка данных для обучения и тестирования
  • Обучение нейронной сети для классификации изображений с помощью обучающих данных
  • Оценка модели с использованием тестовых данных

Для каждого компонента необходимо подготовить следующее:

  1. Подготовка скрипта Python, содержащего логику выполнения

  2. Определение интерфейса компонента

  3. Добавление других метаданных компонента, включая среду выполнения, команду для запуска компонента и т. д.

В следующем разделе показано, как создать компоненты двумя разными способами: первые два компонента с помощью функции Python и третьего компонента с помощью определения YAML.

Создание компонента подготовки данных

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

Если вы используете пример в репозитории Машинное обучение Azure примеров, исходные файлы уже доступны в prep/ папке. Эта папка содержит два файла для создания компонента: prep_component.py, который определяет компонент, и conda.yaml, который определяет среду выполнения компонента.

Определение компонента с помощью функции Python

Используя command_component() функцию в качестве декоратора, можно легко определить интерфейс компонента, метаданные и код для выполнения из функции Python. Каждая декорированная функция Python будет преобразована в одну статическую спецификацию (YAML), которую может обрабатывать служба конвейера.

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

В приведенном выше коде определяется компонент с отображаемым именем Prep Data с помощью декоратора @command_component:

  • name — уникальный идентификатор компонента.

  • version — текущая версия компонента. Компонент может иметь несколько версий.

  • display_name — понятное отображаемое имя компонента в пользовательском интерфейсе, которое не является уникальным.

  • description обычно описывает задачу, которую может выполнить этот компонент.

  • environment указывает среду выполнения для этого компонента. В среде этого компонента указывается образ Docker и создается ссылка на файл conda.yaml.

    Файл conda.yaml содержит все пакеты, используемые для компонента, как показано ниже:

    name: imagekeras_prep_conda_env
    channels:
      - defaults
    dependencies:
      - python=3.7.11
      - pip=20.0
      - pip:
        - mldesigner==0.1.0b4
    
  • Функция prepare_data_component определяет один элемент входных данных для input_data и два элемента выходных данных для training_data и test_data. input_data — путь к входным данным. training_data и test_data — пути к выходным данным для данных обучения и тестовых данных.

  • Этот компонент преобразует данные из input_data в CSV-файл для данных обучения training_data и в CSV-файл для тестовых данных test_data.

Ниже показано, как выглядит компонент в пользовательском интерфейсе Студии.

  • Компонент представляет собой блок в графе конвейера.
  • input_data, training_data и test_data — порты компонента, который подключается к другим компонентам для потоковой передачи данных.

Screenshot of the Prep Data component in the UI and code.

Теперь вы подготовили все исходные файлы для компонента Prep Data.

Создание компонента обучения модели

В этом разделе вы создадите компонент для обучения модели классификации изображений в функции Python, такой как Prep Data компонент.

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

Исходные файлы этого компонента находятся train/ в папке в репозитории Машинное обучение Azure. Эта папка содержит три файла для создания компонента:

  • train.py: содержит фактическую логику для обучения модели.
  • train_component.py: определяет интерфейс компонента и импортирует функцию в train.py.
  • conda.yaml: определяет среду выполнения компонента.

Получение сценария, содержащего логику выполнения

Файл train.py содержит обычную функцию Python, которая выполняет логику обучения модели для обучения нейронной сети Keras для классификации изображений. Чтобы просмотреть код, ознакомьтесь с файлом train.py на GitHub.

Определение компонента с помощью функции Python

После успешного определения функции обучения можно использовать @command_component в пакете SDK Машинное обучение Azure версии 2 для упаковки функции в качестве компонента, который можно использовать в конвейерах Машинное обучение Azure.

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)

В приведенном выше коде определяется компонент с отображаемым именем Train Image Classification Keras с помощью @command_component:

  • Функция keras_train_component определяет один элемент входных данных input_data, из которого поступают обучающие данные, один элемент входных данных epochs, задающий эпохи во время обучения, и один элемент выходных данных output_model, содержащий выходные данные для файла модели. Значение по умолчанию для параметра epochs — 10. Логика выполнения этого компонента находится в функции train() в файле train.py выше.

Компонент обучения модели имеет немного более сложную конфигурацию, чем компонент подготовки данных. conda.yaml имеет следующий вид:

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

Теперь вы подготовили все исходные файлы для компонента Train Image Classification Keras.

Создание компонента оценки модели

В этом разделе наряду с предыдущими компонентами вы создадите компонент для оценки обученной модели с помощью спецификации Yaml и сценария.

Если вы используете пример в репозитории Машинное обучение Azure примеров, исходные файлы уже доступны в score/ папке. Эта папка содержит три файла для создания компонента:

  • score.py: содержит исходный код компонента.
  • score.yaml: определяет интерфейс и другие сведения о компоненте.
  • conda.yaml: определяет среду выполнения компонента.

Получение сценария, содержащего логику выполнения

Файл score.py содержит обычную функцию Python, которая выполняет логику модели обучения.

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)

Код в файле score.py принимает три аргумента командной строки: input_data, input_model и output_result. Программа оценивает входную модель с использованием входных данных, а затем выводит результат оценки.

Определение компонента с помощью YAML

В этом разделе вы узнаете, как создать спецификацию компонента в допустимом формате спецификации компонентов YAML. В этом файле указывается следующая информация.

  • Метаданные: имя, display_name, версия, тип и так далее.
  • Интерфейс: входные и выходные данные
  • Команда, код и среда: команда, код и среда, используемая для запуска компонента
$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 — уникальный идентификатор компонента. Его отображаемое имя — Score Image Classification Keras.
  • Этот компонент содержит два элемента входных данных и один элемент выходных данных.
  • Путь к исходному коду компонента определяется в разделе code, и при запуске компонента в облаке все файлы, находящиеся по этому пути, будут отправлены в виде моментального снимка этого компонента.
  • В разделе command указывается команда, выполняемая при запуске этого компонента.
  • Раздел environment содержит образ Docker и файл YAML conda. Исходный файл находится в репозитории с примерами.

Теперь у вас есть все исходные файлы для компонента оценки модели.

Загрузка компонентов для создания конвейера

Для компонента подготовки данных и компонента модели обучения, определенного функцией Python, можно импортировать компоненты так же, как обычные функции Python.

В следующем коде импортируются функции prepare_data_component() и keras_train_component() из файла prep_component.py в папке prep и из файла train_component в папке train соответственно.

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

Для загрузки компонента оценки, определенного с помощью YAML, можно использовать функцию load_component().

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

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

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

Примечание.

Чтобы использовать бессерверные вычисления, добавьте from azure.ai.ml.entities import ResourceConfiguration в начало. Затем замените:

  • default_compute=cpu_compute_target, с default_compute="serverless",
  • train_node.compute = gpu_compute_target с 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=fashion_ds)

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

Конвейер содержит входные данные уровня конвейера pipeline_input_data. Вы можете назначить значение входным данным конвейера при отправке задания конвейера.

Конвейер содержит три узла: prepare_data_node, train_node и score_node.

  • Элемент input_data в узле prepare_data_node использует значение pipeline_input_data.

  • Элемент input_data в узле train_node заполняется на основе выходных данных training_data узла prepare_data_node.

  • Элемент input_data в узле score_node заполняется на основе элемента выходных данных test_data в узле prepare_data_node, и элемент input_model заполняется на основе элемента output_model в узле train_node.

  • Так как узел train_node будет обучать модель CNN, вы можете указать его вычислительные ресурсы в качестве параметра gpu_compute_target, что может повысить производительность обучения.

Отправка задания конвейера

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

Получение доступа к рабочей области

Настройка учетных данных

Мы будем использовать DefaultAzureCredential для получения доступа к рабочей области. DefaultAzureCredential должен поддерживать большинство сценариев проверки подлинности пакета SDK для Azure.

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

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

Получение дескриптора рабочей области с помощью вычисления

Создайте объект MLClient для управления службами Машинного обучения Azure. Если вы используете бессерверные вычисления , вам не нужно создавать эти вычисления.

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

Важно!

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

Отправка задания конвейера в рабочую область

Теперь вы получите дескриптор рабочей области и сможете отправить задание конвейера.

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

Приведенный выше код отправляет это задание конвейера классификации изображений в эксперимент pipeline_samples. Если эксперимента не существует, он будет создан автоматически. Элемент pipeline_input_data использует fashion_ds.

Выходные данные для вызова pipeline_job имеют следующий вид:

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

Эксперимент Имя. Тип Состояние Страница сведений
pipeline_samples sharp_pipe_4gvqx6h1fb конвейер Подготовка Ссылка на Студию машинного обучения Azure.

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

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

Важно!

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

Проверка выходных данных и отладка конвейера в пользовательском интерфейсе

Вы можете открыть страницу Link to Azure Machine Learning studio, на которой приведены сведения о задании для конвейера. Вы увидите граф конвейера, похожий на приведенный ниже.

Screenshot of the pipeline job detail page.

Вы можете проверить журналы и выходные данные каждого компонента, щелкнув компонент правой кнопкой мыши или выбрав компонент, чтобы открыть область сведений. Дополнительные сведения о отладке конвейера в пользовательском интерфейсе см. в статье "Использование сбоя конвейера отладки".

(Необязательно) Регистрация компонентов в рабочей области

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

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)

С помощью метода ml_client.components.get() можно получить зарегистрированный компонент по имени и версии. С помощью ml_client.components.create_or_update()можно зарегистрировать компонент, ранее загруженный из функции Python или yaml.

Следующие шаги