Обучайте и развертывайте модели машинного обучения в мультиоблачной среде с использованием Amazon SageMaker

Обучайте и развертывайте модели машинного обучения в Amazon SageMaker

Поскольку клиенты ускоряют миграцию в облако и преобразуют свой бизнес, некоторые оказываются в ситуациях, когда им приходится управлять IT-операциями в многоблочной среде. Например, вы могли приобрести компанию, которая уже работала на другом облачном провайдере, или у вас может быть рабочая нагрузка, которая генерирует ценность из уникальных возможностей, предоставляемых AWS. Еще один пример – это независимые разработчики программного обеспечения (ISV), которые предлагают свои продукты и услуги на различных облачных платформах для получения преимуществ для своих конечных клиентов. Или организация может работать в регионе, где основной облачный провайдер недоступен, и чтобы удовлетворить требования к суверенности данных или местонахождению данных, они могут использовать вторичного облачного провайдера.

В этих сценариях, когда вы начинаете использовать генеративный ИИ, большие языковые модели (LLM) и технологии машинного обучения (ML) как основную часть вашего бизнеса, вы можете искать варианты использования возможностей искусственного интеллекта и машинного обучения AWS за пределами AWS в многоблочной среде. Например, вы можете использовать Amazon SageMaker для создания и обучения модели ML, или использовать Amazon SageMaker Jumpstart для развертывания заранее созданных моделей ML сторонних разработчиков, которые можно развернуть всего несколькими щелчками мыши. Или вы можете воспользоваться Amazon Bedrock для создания и масштабирования приложений, основанных на генеративном ИИ, или использовать предварительно обученные AI-сервисы AWS, для работы с которыми не требуются навыки машинного обучения. AWS обеспечивает поддержку сценариев, когда организации хотят привнести свою собственную модель в Amazon SageMaker или в Amazon SageMaker Canvas для прогнозирования.

В этой статье мы демонстрируем один из множества вариантов использования самого широкого и глубокого набора возможностей AI/ML от AWS в многоблочной среде. Мы показываем, как вы можете создать и обучить модель ML в AWS, а затем развернуть модель на другой платформе. Мы обучаем модель с помощью Amazon SageMaker, сохраняем артефакты модели в хранилище данных Amazon Simple Storage Service (Amazon S3) и развертываем и запускаем модель в Azure. Этот подход полезен, если вы используете службы AWS для ML из-за их самого полного набора функций, но вам нужно запустить вашу модель на другом облачном провайдере в одной из обсуждаемых ситуаций.

Основные понятия

Amazon SageMaker Studio – это веб-интерфейс интегрированной среды разработки (IDE) для машинного обучения. SageMaker Studio позволяет специалистам по данным, инженерам по машинному обучению и инженерам по данным подготовить данные, создать, обучить и развернуть модели ML в одном веб-интерфейсе. С помощью SageMaker Studio вы можете получить доступ к инструментам, созданным специально для каждого этапа жизненного цикла разработки ML, от подготовки данных до создания, обучения и развертывания моделей ML, увеличивая производительность команды по науке о данных в десять раз. Записные книжки SageMaker Studio – это быстрые совместные записные книжки, интегрированные с инструментами ML, разработанными специально для SageMaker и других служб AWS.

SageMaker – это комплексный сервис ML, позволяющий бизнес-аналитикам, ученым по данным и инженерам MLOps создавать, обучать и развертывать модели ML для любого случая использования, независимо от опыта работы с ML.

AWS предоставляет контейнеры глубокого обучения (DLC) для популярных ML-фреймворков, таких как PyTorch, TensorFlow и Apache MXNet, которые можно использовать с SageMaker для обучения и вывода. DLC доступны в виде образов Docker в хранилище контейнеров Amazon Elastic Container Registry (Amazon ECR). Образы Docker предварительно установлены и протестированы с последними версиями популярных фреймворков глубокого обучения, а также с другими зависимостями, необходимыми для обучения и вывода. Для полного списка заранее созданных образов Docker, управляемых SageMaker, см. Пути реестра Docker и примеры кода. Amazon ECR поддерживает сканирование безопасности и интегрирован с сервисом управления уязвимостями Amazon Inspector для обеспечения соответствия требованиям безопасности изображений вашей организации и автоматизации сканирования уязвимостей. Организации также могут использовать AWS Trainium и AWS Inferentia для достижения лучшего соотношения цена/производительность при выполнении задач обучения ML или вывода.

Обзор решения

В этом разделе мы описываем, как создать и обучить модель с использованием SageMaker и развернуть модель в Azure Functions. Мы используем записную книжку SageMaker Studio для создания, обучения и развертывания модели. Мы обучаем модель в SageMaker с использованием предварительно созданного образа Docker для PyTorch. Хотя в этом случае мы развертываем обученную модель в Azure, вы можете использовать тот же подход для развертывания модели на других платформах, таких как внутренние ресурсы или другие облачные платформы.

При создании задания обучения SageMaker запускает вычислительные экземпляры ML и использует наш код обучения и обучающий набор данных для обучения модели. Он сохраняет результаты артефактов модели и другие выходные данные введенного нами входного S3-ведра. После завершения обучения модели мы используем библиотеку среды выполнения Open Neural Network Exchange (ONNX), чтобы экспортировать модель PyTorch в виде модели ONNX.

Наконец, мы развертываем модель ONNX вместе с настраиваемым кодом вывода, написанным на Python, в Azure Functions с использованием Azure CLI. ONNX поддерживает большинство популярных фреймворков и инструментов машинного обучения. Следует отметить, что преобразование модели ML в формат ONNX полезно, если вы хотите использовать другой целевой фреймворк развертывания, например, PyTorch в TensorFlow. Если вы используете один и тот же фреймворк как на исходной, так и на целевой платформе, вам не нужно преобразовывать модель в формат ONNX.

Следующая диаграмма иллюстрирует архитектуру для данного подхода.

Мы используем блокнот SageMaker Studio вместе с SageMaker Python SDK для создания и обучения нашей модели. SageMaker Python SDK – это библиотека с открытым исходным кодом для обучения и развертывания моделей ML на SageMaker. Дополнительные сведения см. в разделе Создание или открытие блокнота Amazon SageMaker Studio.

Фрагменты кода в следующих разделах были протестированы в среде блокнота SageMaker Studio с использованием образа Data Science 3.0 и ядра Python 3.0.

В этом решении мы продемонстрируем следующие шаги:

  1. Обучить модель PyTorch.
  2. Экспортировать модель PyTorch в ONNX-модель.
  3. Упаковать модель и код вывода.
  4. Развернуть модель на Azure Functions.

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

У вас должны быть следующие предварительные требования:

  • Учетная запись AWS.
  • Домен SageMaker и пользователь SageMaker Studio. Для получения инструкций по созданию этих компонентов см. Подключение к домену Amazon SageMaker с помощью быстрой настройки.
  • Azure CLI.
  • Доступ к Azure и учетные данные для служебного принципала, который имеет разрешения на создание и управление Azure Functions.

Обучение модели с помощью PyTorch

В этом разделе мы подробно рассмотрим шаги по обучению модели PyTorch.

Установка зависимостей

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

pip install torchvision onnx onnxruntime

Завершить начальную настройку

Мы начинаем с импорта AWS SDK для Python (Boto3) и SageMaker Python SDK. В рамках настройки мы определяем следующее:

  • Объект сеанса, который предоставляет удобные методы в контексте SageMaker и нашей учетной записи.
  • ARN роли SageMaker, используемой для передачи разрешений службам обучения и размещения. Нам это нужно, чтобы эти службы имели доступ к ведрам S3, где хранятся наши данные и модель. Для получения инструкций по созданию роли, отвечающей вашим бизнес-потребностям, см. Роли SageMaker. Для этого сообщения мы используем ту же роль выполнения, что и наш экземпляр блокнота Studio. Мы получаем эту роль, вызывая sagemaker.get_execution_role().
  • Регион по умолчанию, в котором будет выполняться наша задача обучения.
  • Корзина по умолчанию и префикс, которые мы используем для хранения вывода модели.

См. следующий код:

import sagemaker
import boto3
import os

execution_role = sagemaker.get_execution_role()
region = boto3.Session().region_name
session = sagemaker.Session()
bucket = session.default_bucket()
prefix = "sagemaker/mnist-pytorch"

Создание обучающего набора данных

Мы используем набор данных, доступный в общем ведре sagemaker-example-files-prod-{region}. Набор данных содержит следующие файлы:

  • train-images-idx3-ubyte.gz – Содержит изображения обучающего набора
  • train-labels-idx1-ubyte.gz – Содержит метки обучающего набора
  • t10k-images-idx3-ubyte.gz – Содержит изображения тестового набора
  • t10k-labels-idx1-ubyte.gz – Содержит метки тестового набора

Мы используем модуль torchvision.datasets для загрузки данных из общего ведра локально перед их загрузкой в нашу корзину с обучающими данными. Мы передаем эту локацию ведра в качестве входных данных для задачи обучения SageMaker. В нашем сценарии обучения этот адрес используется для загрузки и подготовки обучающих данных, а затем для обучения модели. См. следующий код:

MNIST.mirrors = [
    f"https://sagemaker-example-files-prod-{region}.s3.amazonaws.com/datasets/image/MNIST/"
]

MNIST(
    "data",
    download=True,
    transform=transforms.Compose(
        [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]
    ),
)

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

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

По завершении обучения SageMaker сохраняет выходную модель в S3-ведро, которое мы указали в качестве параметра для задания обучения.

Наш код обучения адаптирован из следующего примера скрипта PyTorch. В следующем фрагменте кода показано определение модели и функции обучения:

# определение сети

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        output = F.log_softmax(x, dim=1)
        return output

# обучение

def train(args, model, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % args.log_interval == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))
            if args.dry_run:
                break

Обучение модели

Теперь, когда мы настроили наше окружение и создали набор входных данных и пользовательский скрипт обучения, мы можем начать обучение модели с помощью SageMaker. Мы используем оценщик PyTorch в SageMaker Python SDK для запуска задания обучения на SageMaker. Мы передаем необходимые параметры в оценщик и вызываем метод fit. При вызове fit для оценщика PyTorch SageMaker запускает задание обучения с использованием нашего скрипта в качестве кода обучения:

from sagemaker.pytorch import PyTorch

output_location = f"s3://{bucket}/{prefix}/output"
print(f"артефакты обучения будут загружены в: {output_location}")

hyperparameters={
    "batch-size": 100,
    "epochs": 1,
    "lr": 0.1,
    "gamma": 0.9,
    "log-interval": 100
}

instance_type = "ml.c4.xlarge"
estimator = PyTorch(
    entry_point="train.py",
    source_dir="code",  # каталог вашего скрипта обучения
    role=execution_role,
    framework_version="1.13",
    py_version="py39",
    instance_type=instance_type,
    instance_count=1,
    volume_size=250,
    output_path=output_location,
    hyperparameters=hyperparameters
)

estimator.fit(inputs = {
    'training': f"{inputs}",
    'testing':  f"{inputs}"
})

Экспорт обученной модели в ONNX-модель

После завершения обучения и сохранения нашей модели в заранее определенном месте в Amazon S3 мы экспортируем модель в ONNX-модель с использованием ONNX-рантайма.

Мы включаем код экспорта нашей модели в ONNX в нашем скрипте обучения для запуска после завершения обучения.

PyTorch экспортирует модель в ONNX, выполняя модель с использованием нашего входа и записывая отслеживание операторов, используемых для вычисления выхода. Мы используем случайный вход правильного типа с помощью функции torch.onnx.export PyTorch для экспорта модели в ONNX. Мы также указываем первое измерение нашего входа как динамическое, чтобы наша модель принимала переменный размер batch_size входов во время вывода.

def export_to_onnx(model, model_dir, device):
    logger.info("Экспорт модели в ONNX.")
    dummy_input = torch.randn(1, 1, 28, 28).to(device)
    input_names = [ "input_0" ]
    output_names = [ "output_0" ]
    path = os.path.join(model_dir, 'mnist-pytorch.onnx')
    torch.onnx.export(model, dummy_input, path, verbose=True, input_names=input_names, output_names=output_names,
                     dynamic_axes={'input_0' : {0 : 'batch_size'},    # переменная длина осей
                                'output_0' : {0 : 'batch_size'}})

ONNX – это открытый стандартный формат для моделей глубокого обучения, который обеспечивает взаимодействие между фреймворками глубокого обучения, такими как PyTorch, Microsoft Cognitive Toolkit (CNTK) и другими. Это означает, что вы можете использовать любой из этих фреймворков для обучения модели и последующего экспорта предобученных моделей в формате ONNX. Экспортируя модель в ONNX, вы получаете преимущество более широкого выбора устройств и платформ для развертывания.

Загрузка и извлечение артефактов модели

ONNX-модель, которую сохраняет наш сценарий обучения, была скопирована SageMaker в Amazon S3 в место вывода, которое мы указали при запуске задания обучения. Артефакты модели хранятся в виде сжатого архивного файла с именем model.tar.gz. Мы загружаем этот архивный файл в локальный каталог нашего рабочего пространства в блокноте Studio и извлекаем артефакты модели, а именно ONNX-модель.

import tarfile

local_model_file = 'model.tar.gz'
model_bucket,model_key = estimator.model_data.split('/',2)[-1].split('/',1)
s3 = boto3.client("s3")
s3.download_file(model_bucket,model_key,local_model_file)

model_tar = tarfile.open(local_model_file)
model_file_name = model_tar.next().name
model_tar.extractall('.')
model_tar.close()

Проверка ONNX-модели

ONNX-модель экспортируется в файл с именем mnist-pytorch.onnx нашим сценарием обучения. После того, как мы загрузили и извлекли этот файл, мы можем дополнительно проверить ONNX-модель, используя модуль onnx.checker. Функция check_model в этом модуле проверяет согласованность модели. Если тест не проходит, вызывается исключение.

import onnx

onnx_model = onnx.load("mnist-pytorch.onnx")
onnx.checker.check_model(onnx_model)

Упаковка модели и кода вывода

В этой статье мы используем развертывание в формате .zip для Azure Functions. В этом методе мы упаковываем нашу модель, сопроводительный код и настройки Azure Functions в .zip-файл и публикуем его в Azure Functions. Ниже приведен пример структуры каталогов нашего пакета развертывания:

mnist-onnx ├── function_app.py ├── model │ └── mnist-pytorch.onnx └── requirements.txt

Перечисление зависимостей

Мы перечисляем зависимости для нашего кода вывода в файле requirements.txt в корне нашего пакета. Этот файл используется для создания среды Azure Functions при публикации пакета.

azure-functions numpy onnxruntime

Написание кода вывода

Мы используем Python для написания следующего кода вывода, используя библиотеку ONNX Runtime для загрузки нашей модели и выполнения вывода. Это указывает приложению Azure Functions сделать конечную точку доступной по относительному пути /classify.

import logging
import azure.functions as func
import numpy as np
import os
import onnxruntime as ort
import json


app = func.FunctionApp()

def preprocess(input_data_json):
    # преобразование данных JSON во входной тензор
    return np.array(input_data_json['data']).astype('float32')
    
def run_model(model_path, req_body):
    session = ort.InferenceSession(model_path)
    input_data = preprocess(req_body)
    logging.info(f"Форма входных данных: {input_data.shape}.")
    input_name = session.get_inputs()[0].name  # получить идентификатор первого входа модели
    try:
        result = session.run([], {input_name: input_data})
    except (RuntimeError) as e:
        print("Форма={0} и ошибка={1}".format(input_data.shape, e))
    return result[0] 

def get_model_path():
    d=os.path.dirname(os.path.abspath(__file__))
    return os.path.join(d , './model/mnist-pytorch.onnx')

@app.function_name(name="mnist_classify")
@app.route(route="classify", auth_level=func.AuthLevel.ANONYMOUS)
def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP-функция обработала запрос.')
    # Получить значение img из сообщения POST.
    try:
        req_body = req.get_json()
    except ValueError:
        pass

    if req_body:
        # выполнить модель
        result = run_model(get_model_path(), req_body)
        # сопоставить вывод с целым числом и вернуть строку с результатом
        digits = np.argmax(result, axis=1)
        logging.info(type(digits))
        return func.HttpResponse(json.dumps({"digits": np.array(digits).tolist()}))
    else:
        return func.HttpResponse(
             "Данная функция, инициированная через HTTP, успешно завершила работу.",
             status_code=200
        )

Развертывание модели в Azure Functions

Теперь, когда мы упаковали код в требуемый формат .zip, мы готовы опубликовать его в Azure Functions. Для этого мы используем Azure CLI, командную утилиту для создания и управления ресурсами Azure. Установите Azure CLI с помощью следующего кода:

!pip install -q azure-cli

Затем выполните следующие шаги:

  1. Войдите в Azure:

    !az login
  2. Настройте параметры создания ресурса:

    import random
    
    random_suffix = str(random.randint(10000,99999))
    resource_group_name = f"multicloud-{random_suffix}-rg"
    storage_account_name = f"multicloud{random_suffix}"
    location = "ukwest"
    sku_storage = "Standard_LRS"
    functions_version = "4"
    python_version = "3.9"
    function_app = f"multicloud-mnist-{random_suffix}"
  3. Используйте следующие команды для создания приложения Azure Functions вместе с необходимыми ресурсами:

    !az group create --name {resource_group_name} --location {location}
    !az storage account create --name {storage_account_name} --resource-group {resource_group_name} --location {location} --sku {sku_storage}
    !az functionapp create --name {function_app} --resource-group {resource_group_name} --storage-account {storage_account_name} --consumption-plan-location "{location}" --os-type Linux --runtime python --runtime-version {python_version} --functions-version {functions_version}
  4. Настройте Azure Functions так, чтобы при развертывании пакета Functions использовался файл requirements.txt для создания зависимостей нашего приложения:

    !az functionapp config appsettings set --name {function_app} --resource-group {resource_group_name} --settings @./functionapp/settings.json
  5. Настройте приложение Functions для запуска модели Python v2 и выполнения сборки кода после развертывания .zip:

    {
        "AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
        "SCM_DO_BUILD_DURING_DEPLOYMENT": true
    }
  6. После настройки группы ресурсов, контейнера хранения и приложения Functions с правильной конфигурацией опубликуйте код в приложении Functions:

    !az functionapp deployment source config-zip -g {resource_group_name} -n {function_app} --src {function_archive} --build-remote true

Тестирование модели

Мы развернули модель ML в Azure Functions в качестве HTTP-триггера, что означает, что мы можем использовать URL приложения Functions для отправки HTTP-запроса к функции, чтобы вызвать функцию и запустить модель.

Для подготовки входных данных загрузите файлы тестовых изображений из ведра примеров SageMaker и подготовьте набор образцов в формате, требуемом моделью:

from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import matplotlib.pyplot as plt

transform=transforms.Compose(
        [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]
)

test_dataset = datasets.MNIST(root='../data',  download=True, train=False, transform=transform)
test_loader = DataLoader(test_dataset, batch_size=16, shuffle=True)

test_features, test_labels = next(iter(test_loader))

Используйте библиотеку requests для отправки POST-запроса к конечной точке вывода с входными данными. Конечная точка вывода имеет следующий формат:

import requests, json

def to_numpy(tensor):
    return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()

url = f"https://{function_app}.azurewebsites.net/api/classify"
response = requests.post(url, 
                json.dumps({"data":to_numpy(test_features).tolist()})
            )
predictions = json.loads(response.text)['digits']

Очистка

Когда вы закончите тестирование модели, удалите группу ресурсов вместе с содержащимися ресурсами, включая контейнер хранения и приложение Functions:

!az group delete --name {resource_group_name} --yes

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

Заключение

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

В этом посте не были показаны все возможные способы развертывания и запуска модели в многокластерной среде. Например, вы также можете упаковать свою модель в контейнерное изображение вместе с кодом вывода и зависимыми библиотеками, чтобы запускать модель как контейнеризованное приложение на любой платформе. Для получения дополнительной информации об этом подходе обратитесь к статье “Развертывание контейнерных приложений в многокластерной среде с помощью Amazon CodeCatalyst”. Цель поста – показать, как организации могут использовать возможности искусственного интеллекта и машинного обучения AWS в многокластерной среде.