Это вторая часть моего пути к построению системы, сводящей к минимуму объем продающей электронной почты, с которой я сталкиваюсь каждый день. Напомним, что система подключается к Gmail пользователя через OAuth, определяет, исходит ли входящее электронное письмо от представителя отдела продаж (from_SDR=1), и перемещает такие электронные письма в специальную папку Читать позже. Если электронное письмо не from_SDR, оно оставляет классифицированное электронное письмо в основной папке "Входящие".

В моем последнем посте я извлекал помеченные электронные письма из своего почтового ящика, обучил модель машинного обучения классифицировать, пришли ли электронные письма из SDR, и оценил производительность модели. Здесь я описываю, как я развернул свою модель на конечной точке API, чтобы я мог вызывать ее из апплета Gmail.

Есть много рецептов, чтобы перенести вашу модель в облако. Я нашел этот пример из AWS Принеси свою собственную модель научного набора как самый простой, лучше всего объясненный и наиболее применимый к моему проекту. Шаги ниже показывают, как я контейнеризировал свою модель, поместил этот контейнер на сервер Sagemaker, а затем использовал Chalice для управления конечной точкой API на этом сервере.

Настройка моего контейнера Docker

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

Если вы следуете этому примеру AWS, обратите внимание на следующие важные обновления, необходимые для работы с Python 3: (i) я обновился до Python 3.7.7 в строке 3, что (ii) изменило расположение пакетов в строке 17.

Я скопировал каталог контейнера из примера AWS, который содержит необходимые файлы для упаковки алгоритма для Amazon SageMager. Например, этот каталог содержит код оболочки для создания и отправки образа контейнера в AWS ECR с использованием docker push. Обратите внимание, что я изменил код примера для работы с AWS CLI v2 (см. строки 45–50):

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

Добавление моего сценария обучения в контейнер

Я заменил файл train в контейнере примеров своим собственным обучающим скриптом (подробности об этом см. в первой части этой серии):

Обратите внимание на два импортированных модуля из preprocess.py, которые преобразуют данные в формат, приемлемый для моей модели машинного обучения. Эти классы и функции включены в одну папку:

Наконец, я изменил файл predictor.py в контейнере примера следующим образом:

Мои изменения в основном отражены в строках 64–78, где я обновил пример AWS, чтобы использовать последнюю версию StringIO и включить заголовки в кадр данных data, чтобы они соответствовали ожидаемым входным данным моей модели.

После редактирования этих файлов я запустил скрипт сборки и отправки:

$ sh build_and_push.sh sg_linearsvm

который создал контейнер Docker и отправил его в AWS ECR.

Тестирование моего алгоритма на локальном хосте перед его развертыванием

Перед развертыванием модели полезно определить, правильно ли работает контейнерный код. Пример AWS предоставляет для этой цели подкаталог local_test. Я клонировал этот репозиторий и добавил образцы обучающих данных в соответствующую папку /local_test/test_dir/input/data/training, а затем запустил:

$ ./train_local.sh sg_linearsvm

Этот сценарий оболочки запускает образ докера в режиме train:

image=$1
mkdir -p test_dir/model
mkdir -p test_dir/output
rm test_dir/model/*
rm test_dir/output/*
docker run -v $(pwd)/test_dir:/opt/ml --rm ${image} train

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

./serve_local.sh sg_linearsvm

который представляет собой сценарий оболочки, который выполняет следующий код:

image=$1
docker run -v $(pwd)/test_dir:/opt/ml -p 8080:8080 --rm ${image} serve

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

./predict.sh payload.csv text/csv

где payload.csv был файлом CSV, который имитировал ожидаемый ввод модели:

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

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

Развертывание моего контейнера в Amazon SageMaker

Сначала я настроил среду, указав корзину S3 и роль SageMaker. Я также создал sess для запоминания параметров подключения, которые я использовал для выполнения различных операций SageMaker.

Затем я указал, где модель должна найти данные обучения в S3 (строки 1–3), и определил image, используя соответствующую учетную запись, регион и имена контейнеров (строки 5–11).

Чтобы соответствовать моему алгоритму, я создал SageMaker Estimator, который определяет, как использовать контейнер для обучения (строки 1–4 ниже). Затем я использовал .fit на estimator для обучения данным, загруженным на data_location (строка 6 ниже).

Для развертывания модели на хостинге SageMaker требовался вызов развертывания для подобранной модели (строка 9 выше). Этот вызов принимает количество экземпляров, тип экземпляра и, возможно, функции сериализатора и десериализатора.

Благодаря этому у меня была обученная модель для получения прогнозов в реальном времени. В следующем разделе я опишу, как предоставить конечную точку API, доступную через Интернет.

Делаем модель доступной через API

Для этого проекта я выбрал AWS Chalice для создания и развертывания приложений с использованием Amazon API Gateway и AWS Lambda. Из коробки он обеспечивает:

• Инструмент командной строки для создания, развертывания и управления вашим приложением
• Знакомый и простой в использовании API для объявления представлений в коде Python
• Автоматическое создание политик IAM.

Из командной строки я запустил:

$ chalice new-project sg_to_api

Затем я перешел к этой папке и отредактировал файл app.py, который определяет представления и результирующую логику. Вот как я настроил свой API:

Я перехватываю входящий запрос и расшифровываю его (строки 24–25). Затем я перебираю данные, чтобы создать словарь (строки 27–36), который я загружаю в фрейм данных Pandas (строки 38–39), чтобы я мог переформатировать текст в удобную полезную нагрузку CSV (строка 40). Далее, в строках 46–51, я вызываю sagemaker.invoke_endpoint(), ссылаясь на имя конечной точки в предыдущем разделе этого поста. Наконец, результат сохраняется и передается в виде HTML-ответа (строки 53–92), поэтому я могу продемонстрировать это в веб-браузере.

Чтобы развернуть это приложение, я перешел в каталог sg_to_api и запустил chalice deploy:

$ chalice deploy
...
Initiating first time deployment...
https://xyz123.execute-api.us-east-1.amazonaws.com/api/

Вот и все. У меня был запущен и запущен API с использованием API Gateway и Lambda.

(Мне нравится, что я могу обновить файл app.py, а затем быстро повторно развернуть изменения API, снова запустив chalice deploy.)

Тестирование конечной точки моего API в дикой природе

Хотя я мог использовать свой API с помощью curl, мне не терпелось показать это некоторым нетехническим друзьям, которым было бы неудобно использовать командную строку. Для них я разместил статическую веб-страницу с помощью S3, который принимает ввод текста и отправляет запрос POST на мою конечную точку, а также выводит ответ HTML от app.py.

Сначала я создал корзину S3:

$ aws s3api create-bucket --bucket sg-learner-test-1 --region us-east-1

Затем я настроил свою корзину для поддержки статического хостинга веб-сайтов:

$ aws s3 website s3://sg-learner-test-1/ --index-document index.html --error-document error.html

Наконец, я создал файл index.html, который скопировал в свою корзину S3 с глобальными правами доступа:

$ aws s3 cp index.html s3://sg-learner-test-1/index.html --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers

Ради этого примера я не тратил время на приукрашивание веб-страницы — пожалуйста, смиритесь с ее уродством:

Вставив этот код, я просмотрел свой почтовый ящик и вставил электронные письма в часть «Тело электронного письма» на веб-странице. Если я никогда не писал отправителю по электронной почте, то я сделал поле «Холодный контакт» = 1, иначе я ввожу 0.

Видеть результаты было похоже на волшебство! И хотя я хотел бы предоставить конечную точку здесь, чтобы вы могли протестировать модель самостоятельно, размещение конечной точки SageMaker стоит 0,28 доллара в час (~ 201 доллар в месяц), что немного дорого, если вы захотите поиграть с ней. 😉

Вместо этого я записал для вас несколько примеров:

(Вам интересно, почему на анимации выше есть значок ветка? Все просто: ветка — это более быстрый способ пометить электронное письмо как «не спам

Будущие направления

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

Слишком много людей, которых нужно поблагодарить за то, что они сделали этот пост возможным. Вот несколько человек, которые значительно помогли мне в этом путешествии: Куинн Ланнерсразвертывании модели Scikit-Learn на AWS), Леон Герритсенсоздании REST API with Chalice), Patrick Michelberger (о развертывании бессерверного микросервиса машинного обучения) и David Arpin, Tom Faulhaber и др. (на тему Создание собственного контейнера алгоритмов).