Расширяем возможности для наших студентов. Теперь в OTUS есть целых два курса по Machine Learning: базовый и продвинутый. Оба курса стартуют в августе, в связи с чем мы предлагаем вам посмотреть запись дня открытых дверей в онлайн-формате, а также приглашаем записаться на бесплатные уроки: «Пайплайн работы с задачей ML» и «Поиск аномалий в данных».
В первой части этого руководства мы успешно сохранили вашу классификационную модель в локальном каталоге и завершили все работы по разработке модели, связанные с Jupyter Notebook. С этого момента основное внимание будет уделяться развертыванию нашей модели. Чтобы повторно использовать модель для прогнозирования, вы можете просто загрузить ее и вызвать метод predict(), как вы обычно это делаете в Jupyter Notebook.

Для того чтобы протестировать модель, в той же папке, где находится файл model.pkl, создайте файл main.py с этим кодом:

import pickle
# Импортируем все пакеты, которые необходимы для вашей модели
import numpy as np
from sklearn.neighbors import KNeighborsClassifier

# Загружаем модель в память
with open('./model.pkl', 'rb') as model_pkl:
   knn = pickle.load(model_pkl)

# Неизвестные данные (создаем новое наблюдение для тестирования)
unseen = np.array([[3.2, 1.1, 1.5, 2.1]])
result = knn.predict(unseen)

# Выводим результаты на консоль
print('Predicted result for observation ' + str(unseen) + ' is: ' + str(result))

Повторное использование модели для прогнозирования.

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

Traceback (most recent call last):
 File "main.py", line 4, in <module>
   from sklearn.neighbors import KNeighborsClassifier
ImportError: No module named sklearn.neighbors

Это связано с тем, что используемый нами пакет недоступен в среде, в которой вы запускаете файл. Это значит, что среда, используемая для разработки модели (conda), не идентична среде выполнения (среда python за пределами conda), и это можно рассматривать как потенциальную проблему при запуске нашего кода в других средах. Я специально хотел, чтобы вы увидели эту ошибку, чтобы помочь вам узнать о проблеме, и еще раз подчеркнуть важность использования контейнеров для развертывания нашего кода, чтобы избежать подобных проблем. На данный момент вы можете просто вручную установить все необходимые пакеты с помощью команды «pip install». Мы вернемся сюда позже, чтобы сделать это автоматически.

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

Predicted result for observation [[3.2 1.1 1.5 2.1]] is: [1]

Как вы можете здесь увидеть, для тестирования модели мы используем захардкоженные неизвестные данные. Эти числа представляют собой длину чашелистика, его ширину, длину лепестка и его ширину соответственно. Однако, поскольку мы хотим предоставлять нашу модель как сервис, она должна быть представлена ??как функция, принимающая запросы, содержащие эти четыре параметра, и возвращающая результат прогноза. Затем эту функцию можно использовать для сервер API (бекенда) или развернуть в бессерверной среде выполнения, такой как Google Cloud Functions. В этом руководстве мы попытаемся вместе создать сервер API и поместить его в контейнер Docker.



Как работает API?


Давайте поговорим о том, как сегодня устроены веб-приложения. В большинстве веб-приложений есть два основных компонента, которые покрывают почти все функции, необходимые приложению: фронтенд и бекенд. Фронтенд ориентирован на обслуживание интерфейса (веб-страницы) для пользователя, а фронтенд сервер часто хранит HTML, CSS, JS и другие статические файлы, такие как изображения и звуки. С другой стороны, бекенд сервер будет обрабатывать всю бизнес-логику, которая отвечает на любые запросы, отправленные из фронтенда.


Иллюстрация структуры веб-приложений.

Вот что произойдет, когда вы откроете Medium в своем браузере.

  1. Ваш браузер отправляет HTTP-запрос на адрес medium.com. Потребуется ряд операций на DNS-сервере, маршрутизаторах, межсетевых экранах и т. д., но для простоты этой статьи мы их проигнорируем.
  2. Фронтенд сервер отправляет обратно * .html, * .css, * .js и все другие файлы, необходимые для рендеринга веб-страницы в вашем браузере.
  3. Теперь в браузере вы должны увидеть страницу Medium и начать с ней взаимодействовать. Допустим, вы только что нажали кнопку «clap» (похлопать) на статье.
  4. Скрипты (javascript) в вашем браузере отправят HTTP-запрос на бекенд сервер с id истории. URL-адрес запроса сообщит бекенду, какое действие следует выполнить. В этом примере он скажет бекенду обновить количество хлопков в истории с id XXXXXXX.
  5. Бекенд программа (которая, может быть написана на любом языке) получит текущее количество хлопков в базе данных и увеличит его на единицу.
  6. Затем бекенд программа отправляет актуальное количество хлопков обратно в базу данных.
  7. Бекенд отправляет новое количество хлопков в браузер, чтобы его можно было отразить в интерфейсе.

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

Теперь я хочу, чтобы вы сосредоточили внимание на синих стрелках на рисунке выше. Это HTTP-запросы (отправленные из браузера) и HTTP-ответы (полученные браузером или отправленные в браузер). Компоненты, обрабатывающие запросы от браузера и возвращающие ответы на бекенд сервере, называются «API».

Ниже приведено определение API:
Из Вебопедии

Интерфейс прикладного программирования (API — application program interface) — это набор процедур, протоколов и инструментов для создания программных приложений. По сути, API определяет, как должны взаимодействовать программные компоненты.

Создаем наш собственный API!


Существует множество фреймворков, которые помогают нам создавать API с помощью Python, включая Flask, Django, Pyramid, Falcon и Tornado. Преимущества и недостатки, а также сравнение этих структур, перечислены здесь. В этом уроке я буду использовать Flask, но техника и рабочий процесс остаются такими же, как и для других, и в качестве альтернативы вы вполне можете использовать на этом этапе свой любимый фреймворк.

Последнюю версию Flask можно установить через pip с помощью этой команды:

pip install Flask

Все, что вам нужно сделать сейчас — это превратить код из предыдущего шага в функцию и зарегистрировать для нее эндпоинт API после инициализации приложения Flask. По умолчанию приложение Flask запускается на локалхосте (127.0.0.1) и будет прослушивать запросы на порту 5000.

import pickle
# Импортируем все пакеты, которые необходимы для вашей модели
import numpy as np
import sys
from sklearn.neighbors import KNeighborsClassifier

# Импортируем Flask для создания API
from flask import Flask, request

# Загружаем обученную модель из текущего каталога
with open('./model.pkl', 'rb') as model_pkl:
   knn = pickle.load(model_pkl)

# Инициализируем приложение Flask
app = Flask(__name__)

# Создайте конечную точку API
@app.route('/predict')
def predict_iris():
   # Считываем все необходимые параметры запроса
   sl = request.args.get('sl')
   sw = request.args.get('sw')
   pl = request.args.get('pl')
   pw = request.args.get('pw')

# Используем метод модели predict для
# получения прогноза для неизвестных данных
   unseen = np.array([[sl, sw, pl, pw]])
   result = knn.predict(unseen)
  # возвращаем результат 
   return 'Predicted result for observation ' + str(unseen) + ' is: ' + str(result)
if __name__ == '__main__':
   app.run()

Представление вашей модели как API

На терминале вы должны увидеть следующее:

* Serving Flask app "main" (lazy loading)
* Environment: production
  WARNING: This is a development server. Do not use it in a production deployment.
  Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Откройте браузер и введите в адресной строке следующий запрос:

http://localhost:5000/predict?sl=3.2&sw=1.1&pl=1.5&pw=2.1

Если в вашем браузере появляется что-то подобное, поздравляем! Теперь вы предоставляете свою модель машинного обучения в качестве службы с эндпоинтом API.

Predicted result for observation [['3.2' '1.1' '1.5' '2.1']] is: [1]

Тестирование API с помощью Postman


Недавно мы использовали наш браузер для быстрого тестирования API, но это не очень эффективный способ. Например, мы могли бы не использовать метод GET, а вместо этого использовать метод POST с токеном аутентификации в заголовке, а сделать так, чтобы браузер отправлял такой запрос, непросто. При разработке программного обеспечения Postman широко используется для тестирования API-интерфейсов и совершенно бесплатен для базового использования.


Пользовательский интерфейс Postman (со страницы загрузки Postman)
После загрузки и установки Postman откройте инструмент и следуйте инструкциям ниже, чтобы отправить запрос.


Отправка GET запроса с помощью Postman

  1. Убедитесь, что вы выбрали GET запрос, поскольку мы настраиваем API только для получения GET запроса. Это может не сработать, если вы случайно выберете POST запрос.
  2. Вставьте сюда URL вашего запроса.
  3. В этой таблице необходимо обновить параметры запроса. Не стесняйтесь поиграть с этими параметрами и посмотреть, что вы получите в результате.
  4. Нажмите кнопку «Отправить», чтобы отправить запрос на наш сервер API.
  5. Здесь будет отображаться ответ нашего сервера.
  6. Вы также можете проверить дополнительную информацию об этом HTTP-ответе. Это может быть очень полезно для отладки.

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

Читать первую часть.