Недавно я наткнулся на одну из новинок от AWS - Amazon SageMaker.

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

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

Возможно, лучшая функция SageMaker - это размещенные на хосте Jupyter Notebooks. Мне нравится интеграция уценки и графиков / визуальных элементов с моим кодом при изучении моделей.

Я должен предварять это руководство двумя утверждениями:

  1. Я не претендую на знание Python или ML. Если вы столкнетесь с ошибкой, недоразумением или «плохим» способом написания Python, пожалуйста, дайте мне знать. Я пишу алгоритмы машинного обучения как хобби, а не как карьеру.
  2. Я пишу это, поскольку впервые смотрю на SageMaker, так что могут быть «лучшие» способы делать что-то.

В любом случае давайте рассмотрим простой пример линейной регрессии с SageMaker!

Что мы построим

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

В этом примере я собираюсь взять некоторые данные матчей AFL (Австралийский футбол по правилам) и попытаться найти взаимосвязь между статистикой матча и очками Fantasy. Очки фэнтези рассчитываются путем линейной комбинации подмножества статистики матча. Статистика и линейные веса являются общедоступными и известными, что означает, что мы можем проверить, насколько близко модель подходит к их поиску.

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

Подготовка к настройке

Шаг 1. Настройте S3 и IAM

Чтобы использовать SageMaker, вам понадобится корзина S3 для хранения моделей, данных и результатов. Убедитесь, что у вас есть корзина.

В этом упражнении вы можете использовать test.sagemeaker.your.name

Вам также необходимо настроить роль пользователя IAM, чтобы SageMaker мог получить доступ к корзине S3 для чтения / записи данных.

Выберите любое имя для этой роли доступа IAM, просто убедитесь, что вы предоставили этой роли программный доступ.

В разделе разрешений для этого пользователя вы можете перейти к «Прикрепить существующие политики напрямую» и найти AmazonS3FullAccess и AmazonSageMakerFullAccess.

После того, как вы создали IAM, вам нужно будет скопировать User ARN, который доступен в сводке пользователя для этой роли IAM. Это понадобится вам для настройки экземпляра Notebook в SageMaker.

2. Создайте экземпляр записной книжки в SageMaker

Просто нажмите Создать новый экземпляр на панели управления SageMaker и дайте своему экземпляру Notebook имя. В поле ввода роли IAM вам нужно будет выбрать Введите настраиваемую роль ARN IAM и вставить ARN из роли, которую мы создали ранее. Это должно быть все, что требуется для запуска экземпляра, и вы можете нажать Создать экземпляр записной книжки.

Подготовка экземпляра займет несколько минут, но как только он будет готов, вы сможете открыть записную книжку и увидеть, как экземпляр Jupyter Notebooks открыт в вашем браузере.

Вы заметите несколько вкладок в экземпляре Notebook. Примеры SageMaker - отличный ресурс для ознакомления с реализацией пары примеров моделей SageMaker.

3. Создайте новый .ipynb (Блокнот)

Для начала создадим новый блокнот и начнем писать код. В правом верхнем углу вы увидите кнопку Создать для создания новой записной книжки. В этом примере я собираюсь использовать записную книжку conda_python3.

Настройка модели

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

Затем мы можем получить доступ к CSV в нашем коде следующим образом

# import numpy and pandas libraries for working with data
import numpy as np
import pandas as pd
# Read in csv and store in a pandas dataframe
df = pd.read_csv('2018MatchData.csv, sep=',', encoding='latin1')

Если вы никогда раньше не работали с записной книжкой на Python, вам просто нужно нажать Shift + Enter, чтобы выполнить код внутри блока.

Чтобы убедиться, что csv был прочитан правильно, вы можете выполнить df.head (), чтобы получить список из 5 лучших записей в вашем фреймворке данных.

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

# keep player name for readability and manual checking
data = df.loc[:, ['player_name', 'K', 'H', 'M', 'T', 'G', 'B', 'HO', 'FF', 'FA', 'AF']]
# Remove player name as it is irrelevant for calcs
playerStats = data.loc[:, ['K', 'H','M','T','G','B','HO','FF','FA']]
# confirm we got the data we wanted
data.head(10)

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

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

Удар ногой (3), Удар рукой (2), Метка (3), Отбор (4), Цель (6), Позади (1), Удар (1), Штрафной удар для (1), Штрафной удар ( -3)

Я заказал их в том же порядке, что и наш массив, чтобы мы могли создать массив weightings именно в этом порядке.

weightings = [3, 2, 3, 4, 6, 1, 1, 1, -3]

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

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

def calculate_fantasy_points(playerStats, Weightings):
    return np.dot(playerStats, np.transpose(weightings))

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

# Calculate Fantasy Points
data['calculated'] = calculate_fantasy_points(playerStats, weightings)
# Get the difference between actual points and predicted
data['diff'] = data['AF'] - calculate_fantasy_points(playerStats, weightings)
# Take the sum of the difference over all data points and verify that is is zero
data['diff'].sum()

На этом этапе мы видим, что действительно созданный нами весовой вектор правильный и действительно генерирует ожидаемые фэнтезийные очки. Следующий шаг - проверить, сможет ли SageMaker Linear Learner найти этот весовой вектор, если он был нам неизвестен.

Использование SageMaker Linear Learner

Первое, что нам нужно сделать, это подготовить данные в формате, который может использовать SageMaker. Для Linear Learner требуется массив типа float32.

# Kicks, handballs, goals etc
modelData = np.array(data.iloc[:, 1:10]).astype('float32')
# Actual Fantasy Points
target = np.array(data.iloc[:, 10]).astype('float32')
#Verify that the conversion worked
print(modelData[0])

Затем нам нужно импортировать некоторые библиотеки для связи с экземплярами ML.

import boto3
import sagemaker
import io
import os
import sagemaker.amazon.common as smac
# Create new sagemaker session
sess = sagemaker.Session()
# S3 bucket to export results to
bucket = "test.sagemaker.michael.timbs"
prefix = "AFLFantasy/test"
# Use the IO buffer as dataset is small
buf = io.BytesIO()
smac.write_numpy_to_dense_tensor(buf, modelData, target)
buf.seek(0)
key = 'linearlearner'
boto3.resource('s3').Bucket(bucket).Object(os.path.join(prefix, 'train', key)).upload_fileobj(buf)
s3_train_data = 's3://{}/{}/train/{}'.format(bucket, prefix, key)
print('uploaded training data location: {}'.format(s3_train_data))
output_location = 's3://{}/{}/output'.format(bucket, prefix)
print('training artifacts will be uploaded to: {}'.format(output_location))
# Use all regions for ML model
containers = {'us-west-2': '174872318107.dkr.ecr.us-west-2.amazonaws.com/linear-learner:latest',
              'us-east-1': '382416733822.dkr.ecr.us-east-1.amazonaws.com/linear-learner:latest',
              'us-east-2': '404615174143.dkr.ecr.us-east-2.amazonaws.com/linear-learner:latest',
              'eu-west-1': '438346466558.dkr.ecr.eu-west-1.amazonaws.com/linear-learner:latest',
              'ap-northeast-1': '351501993468.dkr.ecr.ap-northeast-1.amazonaws.com/linear-learner:latest'}

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

from sagemaker import get_execution_role
role = get_execution_role()
linear = sagemaker.estimator.Estimator(containers[boto3.Session().region_name],
                                       role, 
                                       train_instance_count=1, 
                                       train_instance_type='ml.c4.xlarge',
                                       output_path=output_location,
                                       sagemaker_session=sess)

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

linear.set_hyperparameters(feature_dim=9,
                           predictor_type='regressor',
                           normalize_data=False)

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

linear.fit({'train': s3_train_data})
linear_predictor = linear.deploy(initial_instance_count=1,
                                 instance_type='ml.m4.xlarge')

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

Доступ к результатам

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

# Set up
from sagemaker.predictor import csv_serializer, json_deserializer
linear_predictor.content_type = 'text/csv'
linear_predictor.serializer = csv_serializer
linear_predictor.deserializer = json_deserializer

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

# Pass the first row of data to the predictor
result = linear_predictor.predict(modelData[0])
print(result)

Давайте просто передадим все данные и вернем все результаты

predictions = []
for array in modelData:
    result = linear_predictor.predict(array)
    predictions += [r['score'] for r in result['predictions']]
predictions = np.array(predictions)
# Push into our pandas dataframe
data['Predicted'] = predictions.astype(int))

Полученные результаты

Удивительно, но веса, найденные линейным учеником, не были точными и имели небольшую ошибку. Это может быть связано с заданными по умолчанию критериями остановки в настройке модели.

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

Я поиграю с настройкой параметров и выясню, почему точность прогнозов не была 100% (для очень простой модели), и напишу следующий пост.