Минимальный рабочий пример для специалистов по обработке данных

· 1. Введение
· 2. Настройка среды
2.1 Использование conda
2.2 Использование pip
2.3 Создание для него среды conda
· 3. Обучить минимальную модель машинного обучения
· 4. Создание REST API
4.1 Понимание кода
4.2 Раскрутка REST API
· 5. Тестировать API
· Заключение
· Обо мне
· Ссылки

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

1. Введение

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

Интерфейс прикладного программирования (API) — это веб-служба, которая предоставляет доступ к определенным данным и методам, к которым другие приложения могут получить доступ через стандартные протоколы HTTP, а передача репрезентативного состояния (REST) ​​— один из самых популярных архитектурных стилей API для веб-службы. С другой стороны, Python является наиболее предпочтительным языком среди специалистов по данным, и есть две популярные веб-среды: Django и Flask. По сравнению с Django, Flask славится своей легкой и быстрой разработкой. Он также имеет множество расширений для добавления определенных функций в ванильное приложение Flask, и Flask-RESTful — идеальный выбор, позволяющий действительно легко создать полностью функционирующий REST API.

Здесь я собираюсь рассказать вам, как создать минимально жизнеспособный REST API с использованием Flask-RESTful, с примером и всеми кодами, которые вам нужно следовать. В этом посте 3 основных раздела:

  • Создание модели машинного обучения: простая модель с использованием игрушечного набора данных.
  • Создание REST API: основная часть поста. Для обслуживания только что изготовленной модели ML
  • Протестируйте API: используйте модель, чтобы делать прогнозы, вызывая API.

2. Настройка среды

Поскольку это минимальный пример, он не требует большого количества пакетов. Вы можете использовать conda или pip. Для версий с 2.1 по 2.3, приведенных ниже, выберите любой из интересующих вас методов. После завершения любого из них вы можете сразу перейти к разделу 3.

2.1 Использование конды

Если у вас установлена ​​conda, вы можете запустить:

conda install -c conda-forge numpy scikit-learn flask-restful requests

2.2 Использование пункта

если у вас не установлен conda, pip также может сделать это, запустив:

pip install numpy scikit-learn flask-restful requests

2.3 Создайте для него среду conda

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

conda create --name flask_api -c conda-forge numpy scikit-learn flask-restful requests

Это создаст другую среду с именем flask_api с установленными пакетами, и вы можете переключиться на новую среду, выполнив:

conda activate flask_api

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

3. Обучите минимальную модель машинного обучения

После того, как все настроено, давайте сначала создадим игрушечную модель машинного обучения. За более полным кодом и результатами обращайтесь к Jupyter Notebook, но ниже приведен минимально работоспособный код для этого раздела, который также можно скачать здесь. Мы назовем его train_model.py, и вы можете просто запустить его, используя python train_model.py.

Если вы знакомы с машинным обучением и имели некоторый практический опыт работы с scikit-learn , код должен быть вам понятен.

По сути, мы сначала загружаем игрушечный набор данных iris, как показано ниже:

Есть 150 записей. Каждый из них имеет 4 признака и относится к одному из 3 классов (сетозный, разноцветный и виргинский).

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

[0 2 0 1 2 2 2 0 2 0 1 0 0 0 1 2 2 1 0 1 0 1 2 1 0 2 2 1 0 0 0 1 2 0 2 0 1 1]

Где числа представляют каждый из 3 классов. Сравнивая с истинными метками, мы обнаруживаем, что точность составляет 97%, а матрица путаницы показана ниже:

Наша производительность достаточно хороша (вероятно, слишком хороша в реальной жизни). Затем мы сохраняем обученную модель, сериализуя ее в файле рассола.

4. Создайте REST API

4.1 Понять код

Теперь, когда простая модель готова к обслуживанию, давайте создадим REST API. Опять же, ниже приведен код, и я объясню его шаг за шагом. Вы также можете скачать его с мой GitHub. Мы называем это api.py

app = Flask(__name__)
api = Api(app)

Во-первых, мы импортируем модули, и две приведенные выше строки почти всегда должны присутствовать в верхней части кода для запуска приложения и API фляги.

# Create parser for the payload data
parser = reqparse.RequestParser()
parser.add_argument('data')

Приведенный выше фрагмент кода создает анализатор запроса для анализа аргументов, которые будут отправлены вместе с запросом. В нашем случае, поскольку мы обслуживаем модель ML, мы обычно отправляем данные в сериализованном формате JSON и называем ключ как data, поэтому мы просим синтаксический анализатор искать данные, содержащиеся в запросе.

# Define how the api will respond to the post requests
class IrisClassifier(Resource):
    def post(self):
        args = parser.parse_args()
        X = np.array(json.loads(args['data']))
        prediction = model.predict(X)
        return jsonify(prediction.tolist())

api.add_resource(IrisClassifier, '/iris')

Затем мы создаем класс с именем IrisClassifier, наследуя от класса Resource, который мы импортировали из flask-restful, который уже определяет различные методы обработки различных типов запросов, включая get post put delete и так далее. Наша цель — переписать метод post и рассказать ему, как использовать модель для прогнозирования заданных данных. Поскольку целью нашего API является обслуживание моделей машинного обучения, нам нужен только метод post, а об остальных можно не беспокоиться.

В методе post мы сначала вызываем только что определенный синтаксический анализатор для получения аргументов. Данные (первоначально np.array) сериализуются в строковый формат в JSON, поэтому мы используем json.loads для их десериализации в список, а затем обратно в массив NumPy. Часть предсказания остается такой же, как и всегда в моделях scikit-learn. На последнем шаге нам нужно вернуть предсказанные метки (np.array) в список и вызвать функцию jsonify, импортированную из flask, чтобы снова сериализовать ее, чтобы они были возвращены обратно в приложение в правильном формате.

После того, как класс определен, мы добавляем наш IrisClassifier (по сути, модифицированный класс resource) в наш API вместе с относительным маршрутом для доступа к нему, в нашем случае это /iris. Тогда полный URL-адрес нашей модели машинного обучения будет выглядеть примерно так: http://127.0.0.1:5000/iris, если мы просто запустим нашу флягу локально.

if __name__ == '__main__':
    # Load model
    with open('model.pickle', 'rb') as f:
        model = pickle.load(f)

    app.run(debug=True)

В последней части кода в api.py мы загружаем модель, сохраненную из последнего раздела, чтобы приложение знало, где взять модель, если будет запрошен какой-либо прогноз. Затем мы запускаем приложение flask в режиме отладки, где оно просто позволяет выполнять произвольный код непосредственно в браузере, если происходит какая-либо ошибка.

4.2 Развернуть REST API

Если у вас есть код, сохраненный как api.py , вы можете запустить его, используя:

python api.py

Будут сообщения вроде:

* Serving Flask app "api" (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: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 117-609-315

Тогда вы готовы идти!

5. Протестируйте API

Если вы выполняли предыдущие разделы, у вас должен быть запущен REST API на вашем локальном компьютере. Теперь пришло время проверить и посмотреть, работает ли это. Опять же, ниже приведен весь код (минимальный), который вам нужно скопировать, вставить и запустить. Более полный код и результаты см. в Jupyter Notebook, а приведенный ниже код доступен здесь.

Затем я объясню код шаг за шагом. Назовем его test_api.py, и вы сможете запустить его, вызвав python test_api.py.

# Load data
iris = load_iris()

# Split into train and test sets using the same random state
X_train, X_test, y_train, y_test = \
    train_test_split(iris['data'], iris['target'], random_state=12)

После импорта соответствующих модулей первое, что нужно сделать, — это получить подмножество данных (только функции) для проверки прогнозов, возвращаемых API. Для облегчения сравнения мы можем просто использовать тот же набор тестов, который мы разделили в разделе 3. Мы можем загрузить набор данных радужной оболочки и использовать то же случайное состояние (12), чтобы получить точное подмножество данных X_test.

# Serialize the data into json and send the request to the model
payload = {'data': json.dumps(X_test.tolist())}
y_predict = requests.post('http://127.0.0.1:5000/iris', data=payload).json()

Затем мы создаем переменную payload для сериализации списка X_test в формате JSON с ключом data, точно так же, как мы определили inapi.py, чтобы наш API знал, где найти входные данные. Затем мы отправляем полезную нагрузку в определенную нами конечную точку и получаем результаты прогнозирования.

# Make array from the list
y_predict = np.array(y_predict)
print(y_predict)

Последний шаг является необязательным, но мы можем вернуть данные в массив NumPy и распечатать прогнозы, что точно так же, как мы делали ранее в разделе 3, когда мы просто создавали модель. Матрица путаницы точно такая же:

[0 2 0 1 2 2 2 0 2 0 1 0 0 0 1 2 2 1 0 1 0 1 2 1 0 2 2 1 0 0 0 1 2 0 2 0 1 1]

На стороне REST API после использования метода post мы видим сообщение, показывающее Response of 200, что означает, что запрос был успешно обработан:

127.0.0.1 - - [01/Nov/2021 17:01:42] "POST /iris HTTP/1.1" 200 -

Поэтому мы протестировали только что созданный REST API и получили точно такие же результаты, которые были возвращены исходным объектом модели. Наш API работает!

Заключение

Мы только что рассмотрели минимальные знания и шаги, необходимые для создания полностью функционирующего REST API с использованием Python и Flask-RESTFul. Если мы просто посмотрим на часть построения API (раздел 4), то увидим, что она действительно очень проста — менее 30 строк кода, и большинство из них — это стандартные операторы. Также очень легко изменить код: все, что вам нужно сделать, чтобы адаптировать его к вашей модели, — это заменить модель, которую вы хотите использовать, указать, как работает метод post, и указать правильный маршрут для доступа к API.

Чтобы в дальнейшем использовать REST API, который мы только что создали для предоставления наших моделей машинного обучения другим приложениям, мы можем развернуть его на сервере или использовать любую из популярных служб облачного веб-хостинга: AWS, Google Cloud, Heroku и т. д. Через правильных конфигураций, любой, у кого есть разрешение, сможет получить доступ к нашей модели из любой точки мира.

Спасибо за чтение! Если вам понравилась эта статья, пожалуйста, подпишитесь на мой канал и/или станьте моим рекомендателем сегодня (очень ценю это 🙏). Я буду продолжать писать, чтобы делиться своими идеями и проектами в области науки о данных. Не стесняйтесь обращаться ко мне, если у вас есть какие-либо вопросы.



Обо мне

Я специалист по данным в Санофи. Я осваиваю технологии и каждый день осваиваю новые навыки. Вы можете связаться со мной из Medium Blog, LinkedIn или GitHub. Мое мнение является моим собственным, а не мнением моего работодателя.

Пожалуйста, смотрите мои другие статьи:

Рекомендации

[1] Как использовать модуль запросов Python с REST API: https://www.nylas.com/blog/use-python-requests-module-rest-apis/

[2] Учебное пособие по Python REST API — создание Flask REST API: https://www.youtube.com/watch?v=GMppyAPbLYk&t=3769s&ab_channel=TechWithTim