Пошаговое руководство с примерами кода

Многие специалисты по данным, работающие с AWS, используют хостинг Amazon SageMaker для развертывания своих моделей машинного обучения. Однако на практике большинство решений машинного обучения начинаются с простых бизнес-правил (например, операторов if/then), а не сложных моделей машинного обучения. В этой статье я покажу, как развернуть простые бизнес-правила в SageMaker, чтобы специалисты по данным могли быстро вывести первоначальные бизнес-правила на рынок, прежде чем приступать к созданию более сложных моделей машинного обучения, не беспокоясь о создании совершенно новой модели. структура развертывания позже.

Во-первых, конечно, вам понадобится доступ к Amazon SageMaker. Запустите среду SageMaker Studio и создайте новую записную книжку с ядром Python 3 (Data Science) по умолчанию.

Теперь вы должны попасть в записную книжку Untitled.ipynb. Не стесняйтесь переименовывать его во что угодно.

Затем загрузите container.zip из этого репозитория GitHub на свой локальный компьютер и загрузите его в свою среду SageMaker, щелкнув стрелку вверх в разделе навигатора файлов в левой части экрана. Не стесняйтесь клонировать репозиторий непосредственно в среду SageMaker, если у вас настроено подключение к GitHub.

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

# Install and Load Packages

!pip install -q sagemaker-studio-image-build
import pandas as pd
import numpy as np
import sagemaker as sage

import boto3
import re
import os

from sklearn.datasets import load_iris
from sagemaker import get_execution_role
from sagemaker.serializers import CSVSerializer

Далее, давайте импортируем некоторые образцы данных. Мы будем использовать классический набор данных Iris из scikit-learn.

# Data Preparation

data = load_iris()
df = pd.DataFrame(data=data.data, columns=data.feature_names)
df.insert(loc=0, column='target', value=data.target)
mapping = {0:'setosa', 1:'versicolor', 2:'virginica'}
df['target'] = df['target'].map(mapping)
df.head()

Сохраните полученный набор данных в файле CSV в папке data.

os.makedirs('data', exist_ok=True)
df.to_csv('data/iris.csv', header=False, index=False)

Теперь давайте разархивируем файл container.zip, который мы загрузили ранее:

# Unzip Deployment Package

# Run the following conda install in case unzip is not found
# !conda install -y -c conda-forge unzip

!unzip container.zip

Не стесняйтесь просматривать файлы в папке container и знакомиться. README.md в папке содержит подробную документацию по каждому сценарию, поэтому мы не будем рассматривать ее все здесь. На высоком уровне этот контейнер изначально был разработан для обучения и размещения простой модели дерева решений, и я внес в него некоторые незначительные изменения, чтобы вместо размещения модели дерева решений в нем размещались некоторые произвольные правила. Для нашей цели container/model/predictor.py — это единственный файл, который нам нужно изменить, поэтому давайте посмотрим на него:

# This is the file that implements a flask server to do inferences. It's the file that you will modify to
# implement the scoring for your own algorithm.

from __future__ import print_function

import os
import json
import pickle
import StringIO
import sys
import signal
import traceback

import flask

import pandas as pd

prefix = '/opt/ml/'
model_path = os.path.join(prefix, 'model')

# A singleton for holding the model. This simply loads the model and holds it.
# It has a predict function that does a prediction based on the model and the input data.

class ScoringService(object):
    model = None                # Where we keep the model when it's loaded

    @classmethod
    def get_model(cls):
        """Get the model object for this instance, loading it if it's not already loaded."""
        if cls.model == None:
            with open(os.path.join(model_path, 'decision-tree-model.pkl'), 'r') as inp:
                cls.model = pickle.load(inp)
        return cls.model

    @classmethod
    def predict(cls, input):
        """For the input, do the predictions and return them.

        Args:
            input (a pandas dataframe): The data on which to do the predictions. There will be
                one prediction per row in the dataframe"""
        clf = cls.get_model()
        return clf.predict(input)

# The flask app for serving predictions
app = flask.Flask(__name__)

@app.route('/ping', methods=['GET'])
def ping():
    """Determine if the container is working and healthy. In this sample container, we declare
    it healthy if we can load the model successfully."""
    health = ScoringService.get_model() is not None  # You can insert a health check here

    status = 200 if health else 404
    return flask.Response(response='\n', status=status, mimetype='application/json')

@app.route('/invocations', methods=['POST'])
def transformation():
    """Do an inference on a single batch of data. In this sample server, we take data as CSV, convert
    it to a pandas data frame for internal use and then convert the predictions back to CSV (which really
    just means one prediction per line, since there's a single column.
    """
    data = None

    # Convert from CSV to pandas
    if flask.request.content_type == 'text/csv':
        data = flask.request.data.decode('utf-8')
        s = StringIO.StringIO(data)
        data = pd.read_csv(s, header=None)
    else:
        return flask.Response(response='This predictor only supports CSV data', status=415, mimetype='text/plain')

    print('Invoked with {} records'.format(data.shape[0]))

    # Do the prediction
    # predictions = ScoringService.predict(data)  # Model predictions
    predictions = np.where(data.iloc[:,0] > 7, 'a',
                           np.where((data.iloc[:,0] <= 7) & (data.iloc[:,1] <= 3), 'b',
                                    'c'))  # Simple rule predictions

    # Convert from numpy back to CSV
    out = StringIO.StringIO()
    pd.DataFrame({'results':predictions}).to_csv(out, header=False, index=False)
    result = out.getvalue()

    return flask.Response(response=result, status=200, mimetype='text/csv')

Этот файл содержит класс ScoringService, функцию здоровья ping и функцию transformation. Предсказание происходит внутри функции transformation. Увеличим немного:

# Do the prediction
    # predictions = ScoringService.predict(data)  # Model predictions
    predictions = np.where(data.iloc[:,0] > 7, 'a',
                           np.where((data.iloc[:,0] <= 7) & (data.iloc[:,1] <= 3), 'b',
                                    'c'))  # Simple rule predictions

Поэтому, если вы действительно хотите делать прогнозы на основе модели дерева решений, обученной ранее в этом контейнере, вы должны разрешить predictions = ScoringService.predict(data) . Однако, если вы хотите разместить некоторые произвольные правила, вы можете назначить набор логических операторов переменной predictions. В этом примере я использовал функцию np.where() из numpy для реализации своих логических операторов, а именно:

  • Если первый столбец в моих входных данных (длина чашелистика) больше 7, то output=’a’
  • В противном случае, если первый столбец меньше или равен 7, а второй столбец (ширина чашелистика) меньше или равен 3, тогда output=’b’
  • В противном случае вывод = 'c'

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

Теперь, когда мы завершили настройку нашего образа докера (довольно просто, верно?), мы можем приступить к его созданию и сохранению в Amazon ECR (Elastic Container Registry). Начнем с некоторых модификаций разрешений:

  1. Прикрепите политику доверия к роли IAM выполнения SageMaker для AWS CodeBuild. Это гарантирует, что в дополнение к Amazon SageMaker AWS CodeBuild также может взять на себя эту роль, чтобы автоматизировать создание образов Docker.
  • Перейдите в SageMaker Studio, затем щелкните свое «Имя пользователя».

  • Скопируйте имя роли исполнения (не полный ARN)

  • Перейдите на страницу службы IAM, затем нажмите «Роли», затем найдите роли по имени роли исполнения, которую вы скопировали выше, затем нажмите на единственный элемент, который отображается в разделе «Имя роли».

  • Перейдите на вкладку «Доверительные отношения» и нажмите «Изменить политику доверия», затем скопируйте и вставьте следующий код в редактор и нажмите «Обновить политику» внизу страницы.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "sagemaker.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "codebuild.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

2. Прикрепите дополнительную IAM-политику к исполнительной роли SageMaker, чтобы позволить ей создавать образ докера с помощью AWS CodeBuild.

  • Щелкните вкладку «Разрешения» в роли исполнения SageMaker, затем выберите параметр «Создать встроенную политику» в раскрывающемся меню «Добавить разрешения».
  • На странице «Создать политику» щелкните вкладку «JSON», затем скопируйте и вставьте следующий код в текстовую область, заменив текст по умолчанию, затем нажмите «Просмотреть политику». Выполните оставшиеся шаги, чтобы создать встроенную политику (не стесняйтесь называть ее как хотите).
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "codebuild:DeleteProject",
                "codebuild:CreateProject",
                "codebuild:BatchGetBuilds",
                "codebuild:StartBuild"
            ],
            "Resource": "arn:aws:codebuild:*:*:project/sagemaker-studio*"
        },
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogStream",
            "Resource": "arn:aws:logs:*:*:log-group:/aws/codebuild/sagemaker-studio*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:GetLogEvents",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:log-group:/aws/codebuild/sagemaker-studio*:log-stream:*"
        },
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ecr:CreateRepository",
                "ecr:BatchGetImage",
                "ecr:CompleteLayerUpload",
                "ecr:DescribeImages",
                "ecr:DescribeRepositories",
                "ecr:UploadLayerPart",
                "ecr:ListImages",
                "ecr:InitiateLayerUpload",
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage"
            ],
            "Resource": "arn:aws:ecr:*:*:repository/sagemaker-studio*"
        },
        {
            "Effect": "Allow",
            "Action": "ecr:GetAuthorizationToken",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::sagemaker-*/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket"
            ],
            "Resource": "arn:aws:s3:::sagemaker*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:GetRole",
                "iam:ListRoles"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::*:role/*",
            "Condition": {
                "StringLikeIfExists": {
                    "iam:PassedToService": "codebuild.amazonaws.com"
                }
            }
        }
    ]
}

Теперь вернемся к нашей записной книжке SageMaker Studio. Запустите следующий код в новом блоке ячеек, чтобы инициировать сборку докера. Обратите внимание, что это займет пару минут. Если он работает успешно, вы сможете увидеть URI изображения в конце вывода.

# Build Docker Container

%%sh

cd container

chmod +x model/train
chmod +x model/serve

sm-docker build . --repository sagemaker-iris-rule:latest --no-logs

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

# Train Model
## Note that this model is trained for demo purposes only - it's not the model that we deploy

prefix = 'sagemaker-iris-rule'
role = get_execution_role()
WORK_DIRECTORY = 'data'
data_location = sess.upload_data(WORK_DIRECTORY, key_prefix=prefix)

sess = sage.Session()
account = sess.boto_session.client('sts').get_caller_identity()['Account']
region = sess.boto_session.region_name
image = '{}.dkr.ecr.{}.amazonaws.com/sagemaker-iris-rule:latest'.format(account, region)

model = sage.estimator.Estimator(image,
                                 role, instance_count=1, instance_type='ml.c4.2xlarge',
                                 output_path='s3://{}/output'.format(sess.default_bucket()),
                                 sagemaker_session=sess)

file_location = data_location + '/iris.csv'
model.fit(file_location)

Развернуть бизнес-правило на данном этапе очень просто: просто вызовите метод deploy из нашего экземпляра model и укажите тип экземпляра, который вы хотите использовать для размещения. Опять же, это может занять несколько минут.

# Deploy Rule

predictor = model.deploy(initial_instance_count=1,
                         instance_type='ml.m4.xlarge',
                         serializer=CSVSerializer())

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

# Run Inference on Test Data

tdf = pd.read_csv(file_location, header=None)
tdf.drop(tdf.columns[[0]], axis=1, inplace=True)
tdf = tdf.sample(10)

print(predictor.predict(tdf.values).decode('utf-8'))

Наконец, если вы хотите удалить конечную точку модели, просто выполните:

# Cleanup

sess.delete_endpoint(predictor.endpoint_name)

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

По мере того, как области науки о данных продолжают расти и развиваться, все больше ожидается, что ученые, работающие с данными, смогут независимо внедрять свои идеи в производство. Хостинг SageMaker — отличный вариант как для размещения бизнес-правил, так и для модели машинного обучения, если вы работаете в среде AWS. Если вы хотите увидеть больше практических советов по науке о данных, нажмите «Подписаться» рядом с моим именем и следите за обновлениями! А сейчас до свидания :)