Друзья, в конце марта мы запускаем новый поток по курсу «Data Scientist». И прямо сейчас начинаем делиться с вами полезным материалом по курсу.
Введение
Вспоминая ранний опыт своего увлечения машинным обучением (ML) могу сказать, что много усилий уходило на построение действительно хорошей модели. Я советовался с экспертами в этой области, чтобы понять, как улучшить свою модель, думал о необходимых функциях, пытался убедиться, что все предлагаемые ими советы учтены. Но все же я столкнулся с проблемой.
Как же внедрить модель в реальный проект? Идей на этот счет у меня не было. Вся литература, которую я изучал до этого момента, фокусировалась только на улучшении моделей. Я не видел следующего шага в их развитии.

Именно поэтому я сейчас пишу это руководство. Мне хочется, чтобы вы столкнулись с той проблемой, с которой столкнулся я в свое время, но смогли достаточно быстро ее решить. К концу этой статьи я покажу вам как реализовать модель машинного обучения используя фреймворк Flask на Python.
Содержание
Варианты реализации моделей машинного обучения.
В большинстве случаев реальное использование моделей машинного обучения – это центральная часть разработки, даже если это всего лишь маленький компонент системы автоматизации рассылки электронной почты или чатбот. Порой случаются моменты, когда барьеры в реализации кажутся непреодолимыми.
К примеру, большинство ML специалистов используют R или Python для своих научных исканий. Однако потребителями этих моделей будут инженеры-программисты, которые используют совсем другой стек технологий. Есть два варианта, которыми можно решить эту проблему:
Вариант 1: Переписать весь код на том языке, с которым работают инженеры-разработчики. Звучит в какой-то степени логично, однако необходимо большое количество сил и времени, чтобы тиражировать разработанные модели. По итогу это получается просто тратой времени. Большинство языков, как например JavaScript, не имеют удобных библиотек для работы с ML. Поэтому будет достаточно рациональным решением этот вариант не использовать.
Вариант 2: Использовать API. Сетевые API решили проблему работы с приложениями на разных языках. Если фронт-энд разработчику необходимо использовать вашу модель машинного обучения, чтобы на ее основе создать веб-приложение, им нужно всего лишь получить URL конечного сервера, обсуживающего API.
Что такое API?
Если говорить простыми словами, то API (Application Programming Interface) – это своеобразный договор между двумя программами, говорящий, что если пользовательская программа предоставляет входные данные в определенном формате, то программа разработчика (API) пропускает их через себя и выдает необходимые пользователю выходные данные.
Вы сможете самостоятельно прочитать пару статей, в которых хорошо описано, почему API – это достаточно популярный выбор среди разработчиков.
Большинство провайдеров крупных облачных сервисов и меньших по размеру компаний, занимающихся целенаправленно машинным обучением, предоставляют готовые к использованию API. Они удовлетворяют нуждам разработчиков, которые не разбираются в машинном обучении, но хотят внедрить эту технологию в свои решения.
Например, одним из таких поставщиков API является Google со своим Google Vision API.
Все, что необходимо сделать разработчику, это просто вызвать REST (Representational State Transfer) API с помощью SDK, предоставляемой Google. Посмотрите, что можно сделать используя Google Vision API.
Звучит замечательно, не так ли? В этой статье мы разберемся, как создать свое собственное API с использованием Flask, фреймворка на Python.
Внимание: Flask — это не единственный сетевой фреймворк для этих целей. Есть еще Django, Falcon, Hug и множество других, о которых в данной статье не говорится. Например, для R есть пакет, который называется plumber
Установка среды для Python и базовые сведения о Flask.
1) Создание виртуальной среды с использованием Anaconda. Если вам необходимо создать свою виртуальную среду для Python и сохранить необходимое состояние зависимостей, то Anaconda предлагает для этого хорошие решения. Дальше будет вестись работа с командной строкой.
2) Мы попробуем создать свое простое «Hello world» приложение на Flask с использованием gunicorn.


Ура! Вы написали свою первую программу на Flask! Поскольку у вас уже есть некоторый опыт в выполнении этих простых шагов, мы сможем создать сетевые конечные точки, которые могут быть доступны локально.
Используя Flask мы можем оборачивать наши модели и использовать их в качестве Web API. Если мы хотим создавать более сложные сетевые приложения (например, на JavaScript), то нам нужно добавить некоторые изменения.
Создание модели машинного обучения.
Находим null/Nan значения в столбцах:
Чтобы понять как мы его создали, прочитайте следующее.
Создадим пайплайн чтобы убедиться, что все шаги предобработки, которые мы делаем это работа оценщика scikit-learn.
Для поиска подходящих гипер-параметров (степень для полиномиальных объектов и альфа для ребра) сделаем поиск по сетке (Grid Search):
Наш пайплайн выглядит достаточно хорошо, чтобы перейти к следующему важному шагу: Сериализации модели машинного обучения.
Сохранение модели машинного обучения: Сериализация и Десериализация.
В Python консервация (pickling) – это стандартный способ хранение объектов и позже получения их в исходном состоянии. Чтобы звучало понятнее, приведу простой пример:
Затем мы снова выгрузим законсервированный объект:
Мы можем сохранять законсервированные объекты в файл и использовать их. Этот метод похож на создание
Заметка: Некоторым может не понравиться такой способ консервации для сериализации. Альтернативой может стать
У нас имеется пользовательский класс (Class), который нам нужно импортировать пока идет обучение (training), поэтому мы будем использовать модуль
Желательно создать отдельный файл
Модель сохранится в выбранной выше директории. Как только модель законсервирована, ее можно обернуть в Flask wrapper. Однако перед этим нужно убедиться, что законсервированный файл работает. Давайте загрузим его обратно и сделаем прогноз:
Поскольку мы выполнили шаги предобрабоки для того, чтобы вновь поступившие данные были частью пайплайна, нам просто нужно запустить predict(). Используя библиотеку scikit-learn достаточно просто работать с пайплайнами. Оценщики и пайплайны берегут ваше время и нервы, даже если первоначальная реализация кажется дикой.
Создание API с использованием Flask
Давайте сохраним структуру папок максимально простой:

В создании wrapper функции
HTTP сообщения создаются из заголовка и тела. В общем случае основное содержимое тела передается в формате JSON. Мы будем отправлять (
Заметка: Вы можете отправлять обычный текст, XML, cvs или картинку напрямую для взаимозаменяемости формата, однако предпочтительнее в нашем случае использовать именно JSON.
После выполнения, введите:
Давайте сгенерируем данные для прогнозирования и очередь для локального запуска API по адресу
Заключение
В этой статье мы прошли лишь половину пути, создав рабочее API, которое выдает прогнозы, и стали на шаг ближе к интеграции ML решений непосредственно в разрабатываемые приложения. Мы создали достаточно простое API, которое поможет в прототипировании продукта и сделает его действительно функциональным, но чтобы отправить его в продакшн, необходимо внести несколько корректив, которые уже не входят в сферу изучения машинного обучения.
Есть несколько вещей, о которых нельзя забывать, в процессе создания API:
Следующим логическим шагом будет создание механики для развертывания такого API на маленькой виртуальной машине. Есть разные способы сделать это, однако их мы рассмотрим в следующей статье.
Код и пояснения для этой статьи
Полезные источники:
[1] Don’t Pickle your data.
[2] Building Scikit Learn compatible transformers.
[3] Using jsonify in Flask.
[4] Flask-QuickStart.
Вот такой получился материал. Подписывайтесь на нас, если понравилась публикация, а также записывайтесь на бесплатный открытый вебинар по теме: «Метрические алгоритмы классификации», который уже 12 марта проведет разработчик и data scientist с 5-летним опытом — Александр Никитин.
Введение
Вспоминая ранний опыт своего увлечения машинным обучением (ML) могу сказать, что много усилий уходило на построение действительно хорошей модели. Я советовался с экспертами в этой области, чтобы понять, как улучшить свою модель, думал о необходимых функциях, пытался убедиться, что все предлагаемые ими советы учтены. Но все же я столкнулся с проблемой.
Как же внедрить модель в реальный проект? Идей на этот счет у меня не было. Вся литература, которую я изучал до этого момента, фокусировалась только на улучшении моделей. Я не видел следующего шага в их развитии.

Именно поэтому я сейчас пишу это руководство. Мне хочется, чтобы вы столкнулись с той проблемой, с которой столкнулся я в свое время, но смогли достаточно быстро ее решить. К концу этой статьи я покажу вам как реализовать модель машинного обучения используя фреймворк Flask на Python.
Содержание
- Варианты реализации моделей машинного обучения.
- Что такое API?
- Установка среды для Python и базовые сведения о Flask.
- Создание модели машинного обучения.
- Сохранения модели машинного обучения: Сериализация и Десериализация.
- Создание API с использованием Flask.
Варианты реализации моделей машинного обучения.
В большинстве случаев реальное использование моделей машинного обучения – это центральная часть разработки, даже если это всего лишь маленький компонент системы автоматизации рассылки электронной почты или чатбот. Порой случаются моменты, когда барьеры в реализации кажутся непреодолимыми.
К примеру, большинство ML специалистов используют R или Python для своих научных исканий. Однако потребителями этих моделей будут инженеры-программисты, которые используют совсем другой стек технологий. Есть два варианта, которыми можно решить эту проблему:
Вариант 1: Переписать весь код на том языке, с которым работают инженеры-разработчики. Звучит в какой-то степени логично, однако необходимо большое количество сил и времени, чтобы тиражировать разработанные модели. По итогу это получается просто тратой времени. Большинство языков, как например JavaScript, не имеют удобных библиотек для работы с ML. Поэтому будет достаточно рациональным решением этот вариант не использовать.
Вариант 2: Использовать API. Сетевые API решили проблему работы с приложениями на разных языках. Если фронт-энд разработчику необходимо использовать вашу модель машинного обучения, чтобы на ее основе создать веб-приложение, им нужно всего лишь получить URL конечного сервера, обсуживающего API.
Что такое API?
Если говорить простыми словами, то API (Application Programming Interface) – это своеобразный договор между двумя программами, говорящий, что если пользовательская программа предоставляет входные данные в определенном формате, то программа разработчика (API) пропускает их через себя и выдает необходимые пользователю выходные данные.
Вы сможете самостоятельно прочитать пару статей, в которых хорошо описано, почему API – это достаточно популярный выбор среди разработчиков.
Большинство провайдеров крупных облачных сервисов и меньших по размеру компаний, занимающихся целенаправленно машинным обучением, предоставляют готовые к использованию API. Они удовлетворяют нуждам разработчиков, которые не разбираются в машинном обучении, но хотят внедрить эту технологию в свои решения.
Например, одним из таких поставщиков API является Google со своим Google Vision API.
Все, что необходимо сделать разработчику, это просто вызвать REST (Representational State Transfer) API с помощью SDK, предоставляемой Google. Посмотрите, что можно сделать используя Google Vision API.
Звучит замечательно, не так ли? В этой статье мы разберемся, как создать свое собственное API с использованием Flask, фреймворка на Python.
Внимание: Flask — это не единственный сетевой фреймворк для этих целей. Есть еще Django, Falcon, Hug и множество других, о которых в данной статье не говорится. Например, для R есть пакет, который называется plumber
Установка среды для Python и базовые сведения о Flask.
1) Создание виртуальной среды с использованием Anaconda. Если вам необходимо создать свою виртуальную среду для Python и сохранить необходимое состояние зависимостей, то Anaconda предлагает для этого хорошие решения. Дальше будет вестись работа с командной строкой.
- Здесь вы найдете установщик miniconda для Python;
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.shbash Miniconda3-latest-Linux-x86_64.sh- Следуйте последовательности вопросов.
source .bashrc- Если вы введете:
conda, то сможете увидеть список доступных команд и помощь. - Чтобы создать новую среду, введите:
conda create --name <environment-name> python=3.6 - Следуйте шагам, которые вам будет предложено сделать и в конце введите:
source activate <environment-name> - Установите необходимые пакеты Python. Самые важные это flask и gunicorn.
2) Мы попробуем создать свое простое «Hello world» приложение на Flask с использованием gunicorn.
- Откройте свой любимый текстовый редактор и создайте в папке файл
hello-world.py - Напишите следующий код:
"""Filename: hello-world.py """ from flask import Flask app = Flask(__name__) @app.route('/users/<string:username>') def hello_world(username=None): return("Hello {}!".format(username))
- Сохраните файл и вернитесь к терминалу.
- Для запуска API выполните в терминале:
gunicorn --bind 0.0.0.0:8000 hello-world:app - Если получите следующее, то вы на правильном пути:

- В браузере введите следующее:
https://localhost:8000/users/any-name

Ура! Вы написали свою первую программу на Flask! Поскольку у вас уже есть некоторый опыт в выполнении этих простых шагов, мы сможем создать сетевые конечные точки, которые могут быть доступны локально.
Используя Flask мы можем оборачивать наши модели и использовать их в качестве Web API. Если мы хотим создавать более сложные сетевые приложения (например, на JavaScript), то нам нужно добавить некоторые изменения.
Создание модели машинного обучения.
- Для начала займемся соревнованием по машинному обучению Loan Prediction Competition. Основная цель состоит в том, чтобы настроить предобработку пайплайна (pre-processing pipeline) и создать ML модели для облегчения задачи прогнозирования во время развертывания.
import os import json import numpy as np import pandas as pd from sklearn.externals import joblib from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.base import BaseEstimator, TransformerMixin from sklearn.ensemble import RandomForestClassifier from sklearn.pipeline import make_pipeline import warnings warnings.filterwarnings("ignore")
- Сохраняем датасет в папке:
!ls /home/pratos/Side-Project/av_articles/flask_api/data/
test.csv training.csv
data = pd.read_csv('../data/training.csv')
list(data.columns)
['Loan_ID', 'Gender', 'Married', 'Dependents', 'Education', 'Self_Employed', 'ApplicantIncome', 'CoapplicantIncome', 'LoanAmount', 'Loan_Amount_Term', 'Credit_History', 'Property_Area', 'Loan_Status']
data.shape
ul>(614, 13)
Находим null/Nan значения в столбцах:
for _ in data.columns: print("The number of null values in:{} == {}".format(_, data[_].isnull().sum()))
The number of null values in:Loan_ID == 0 The number of null values in:Gender == 13 The number of null values in:Married == 3 The number of null values in:Dependents == 15 The number of null values in:Education == 0 The number of null values in:Self_Employed == 32 The number of null values in:ApplicantIncome == 0 The number of null values in:CoapplicantIncome == 0 The number of null values in:LoanAmount == 22 The number of null values in:Loan_Amount_Term == 14 The number of null values in:Credit_History == 50 The number of null values in:Property_Area == 0 The number of null values in:Loan_Status == 0
- Следующим шагом создаем датасеты для обучения и тестирования:
red_var = ['Gender','Married','Dependents','Education','Self_Employed','ApplicantIncome','CoapplicantIncome',\ 'LoanAmount','Loan_Amount_Term','Credit_History','Property_Area'] X_train, X_test, y_train, y_test = train_test_split(data[pred_var], data['Loan_Status'], \ test_size=0.25, random_state=42)
- Чтобы убедиться, что все шаги предобработки (pre-processing) выполнены верно даже после того как мы провели эксперименты, и мы не упустили ничего во время прогнозирования, мы создадим собственный оценщик на Scikit-learn для предобработки (pre-processing Scikit-learn estimator).
Чтобы понять как мы его создали, прочитайте следующее.
from sklearn.base import BaseEstimator, TransformerMixin class PreProcessing(BaseEstimator, TransformerMixin): """Custom Pre-Processing estimator for our use-case """ def __init__(self): pass def transform(self, df): """Regular transform() that is a help for training, validation & testing datasets (NOTE: The operations performed here are the ones that we did prior to this cell) """ pred_var = ['Gender','Married','Dependents','Education','Self_Employed','ApplicantIncome',\ 'CoapplicantIncome','LoanAmount','Loan_Amount_Term','Credit_History','Property_Area'] df = df[pred_var] df['Dependents'] = df['Dependents'].fillna(0) df['Self_Employed'] = df['Self_Employed'].fillna('No') df['Loan_Amount_Term'] = df['Loan_Amount_Term'].fillna(self.term_mean_) df['Credit_History'] = df['Credit_History'].fillna(1) df['Married'] = df['Married'].fillna('No') df['Gender'] = df['Gender'].fillna('Male') df['LoanAmount'] = df['LoanAmount'].fillna(self.amt_mean_) gender_values = {'Female' : 0, 'Male' : 1} married_values = {'No' : 0, 'Yes' : 1} education_values = {'Graduate' : 0, 'Not Graduate' : 1} employed_values = {'No' : 0, 'Yes' : 1} property_values = {'Rural' : 0, 'Urban' : 1, 'Semiurban' : 2} dependent_values = {'3+': 3, '0': 0, '2': 2, '1': 1} df.replace({'Gender': gender_values, 'Married': married_values, 'Education': education_values, \ 'Self_Employed': employed_values, 'Property_Area': property_values, \ 'Dependents': dependent_values}, inplace=True) return df.as_matrix() def fit(self, df, y=None, **fit_params): """Fitting the Training dataset & calculating the required values from train e.g: We will need the mean of X_train['Loan_Amount_Term'] that will be used in transformation of X_test """ self.term_mean_ = df['Loan_Amount_Term'].mean() self.amt_mean_ = df['LoanAmount'].mean() return self
- Конвертируем
y_trainиy_testвnp.array:
y_train = y_train.replace({'Y':1, 'N':0}).as_matrix() y_test = y_test.replace({'Y':1, 'N':0}).as_matrix()
Создадим пайплайн чтобы убедиться, что все шаги предобработки, которые мы делаем это работа оценщика scikit-learn.
pipe = make_pipeline(PreProcessing(), RandomForestClassifier())
pipe
Pipeline(memory=None, steps=[('preprocessing', PreProcessing()), ('randomforestclassifier', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini', max_depth=None, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1, oob_score=False, random_state=None, verbose=0, warm_start=False))])
Для поиска подходящих гипер-параметров (степень для полиномиальных объектов и альфа для ребра) сделаем поиск по сетке (Grid Search):
- Определяем param_grid:
param_grid = {"randomforestclassifier__n_estimators" : [10, 20, 30], "randomforestclassifier__max_depth" : [None, 6, 8, 10], "randomforestclassifier__max_leaf_nodes": [None, 5, 10, 20], "randomforestclassifier__min_impurity_split": [0.1, 0.2, 0.3]}
- Запускам поиск по сетке:
grid = GridSearchCV(pipe, param_grid=param_grid, cv=3)
- Подгоняем обучающие данные для оценщика пайплайна (pipeline estimator):
grid.fit(X_train, y_train)
GridSearchCV(cv=3, error_score='raise', estimator=Pipeline(memory=None, steps=[('preprocessing', PreProcessing()), ('randomforestclassifier', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini', max_depth=None, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impu..._jobs=1, oob_score=False, random_state=None, verbose=0, warm_start=False))]), fit_params=None, iid=True, n_jobs=1, param_grid={'randomforestclassifier__n_estimators': [10, 20, 30], 'randomforestclassifier__max_leaf_nodes': [None, 5, 10, 20], 'randomforestclassifier__min_impurity_split': [0.1, 0.2, 0.3], 'randomforestclassifier__max_depth': [None, 6, 8, 10]}, pre_dispatch='2*n_jobs', refit=True, return_train_score=True, scoring=None, verbose=0)
- Посмотрим, какой параметр выбрал поиск по сетке:
print("Best parameters: {}".format(grid.best_params_))
Best parameters: {'randomforestclassifier__n_estimators': 30, 'randomforestclassifier__max_leaf_nodes': 20, 'randomforestclassifier__min_impurity_split': 0.2, 'randomforestclassifier__max_depth': 8}
- Подсчитаем:
print("Validation set score: {:.2f}".format(grid.score(X_test, y_test)))
Validation set score: 0.79
- Загрузим тестовый набор:
test_df = pd.read_csv('../data/test.csv', encoding="utf-8-sig") test_df = test_df.head()
grid.predict(test_df)
array([1, 1, 1, 1, 1])
Наш пайплайн выглядит достаточно хорошо, чтобы перейти к следующему важному шагу: Сериализации модели машинного обучения.
Сохранение модели машинного обучения: Сериализация и Десериализация.
«В computer science, в контексте хранение данных, сериализация – это процесс перевода структур данных или состояний объекта в хранимый формат (например, файл или буфер памяти) и воссоздания позже в этой же или другой среде компьютера.»
В Python консервация (pickling) – это стандартный способ хранение объектов и позже получения их в исходном состоянии. Чтобы звучало понятнее, приведу простой пример:
list_to_pickle = [1, 'here', 123, 'walker'] #Pickling the list import pickle list_pickle = pickle.dumps(list_to_pickle)
list_pickle
b'\x80\x03]q\x00(K\x01X\x04\x00\x00\x00hereq\x01K{X\x06\x00\x00\x00walkerq\x02e.'
Затем мы снова выгрузим законсервированный объект:
loaded_pickle = pickle.loads(list_pickle)
loaded_pickle
[1, 'here', 123, 'walker']
Мы можем сохранять законсервированные объекты в файл и использовать их. Этот метод похож на создание
.rda файлов, как в программировании на R, например.Заметка: Некоторым может не понравиться такой способ консервации для сериализации. Альтернативой может стать
h5py. У нас имеется пользовательский класс (Class), который нам нужно импортировать пока идет обучение (training), поэтому мы будем использовать модуль
dill для упаковки оценщика класса (Class) с объектом сетки.Желательно создать отдельный файл
training.py, содержащий весь код для обучния модели. (Пример можно посмотреть здесь).- Устанавливаем
dill
!pip install dill
Requirement already satisfied: dill in /home/pratos/miniconda3/envs/ordermanagement/lib/python3.5/site-packages
import dill as pickle filename = 'model_v1.pk'
with open('../flask_api/models/'+filename, 'wb') as file: pickle.dump(grid, file)
Модель сохранится в выбранной выше директории. Как только модель законсервирована, ее можно обернуть в Flask wrapper. Однако перед этим нужно убедиться, что законсервированный файл работает. Давайте загрузим его обратно и сделаем прогноз:
with open('../flask_api/models/'+filename ,'rb') as f: loaded_model = pickle.load(f)
loaded_model.predict(test_df)
array([1, 1, 1, 1, 1])
Поскольку мы выполнили шаги предобрабоки для того, чтобы вновь поступившие данные были частью пайплайна, нам просто нужно запустить predict(). Используя библиотеку scikit-learn достаточно просто работать с пайплайнами. Оценщики и пайплайны берегут ваше время и нервы, даже если первоначальная реализация кажется дикой.
Создание API с использованием Flask
Давайте сохраним структуру папок максимально простой:

В создании wrapper функции
apicall() есть три важные части:- Получение
requestданных (для которых будет делаться прогноз); - Загрузка законсервированного оценщика;
- Перевод наших прогнозов в формат JSON и получение ответа
status code: 200;
HTTP сообщения создаются из заголовка и тела. В общем случае основное содержимое тела передается в формате JSON. Мы будем отправлять (
POST url-endpoint/) поступающие данные как пакет для получения прогнозов. Заметка: Вы можете отправлять обычный текст, XML, cvs или картинку напрямую для взаимозаменяемости формата, однако предпочтительнее в нашем случае использовать именно JSON.
"""Filename: server.py """ import os import pandas as pd from sklearn.externals import joblib from flask import Flask, jsonify, request app = Flask(__name__) @app.route('/predict', methods=['POST']) def apicall(): """API Call Pandas dataframe (sent as a payload) from API Call """ try: test_json = request.get_json() test = pd.read_json(test_json, orient='records') #To resolve the issue of TypeError: Cannot compare types 'ndarray(dtype=int64)' and 'str' test['Dependents'] = [str(x) for x in list(test['Dependents'])] #Getting the Loan_IDs separated out loan_ids = test['Loan_ID'] except Exception as e: raise e clf = 'model_v1.pk' if test.empty: return(bad_request()) else: #Load the saved model print("Loading the model...") loaded_model = None with open('./models/'+clf,'rb') as f: loaded_model = pickle.load(f) print("The model has been loaded...doing predictions now...") predictions = loaded_model.predict(test) """Add the predictions as Series to a new pandas dataframe OR Depending on the use-case, the entire test data appended with the new files """ prediction_series = list(pd.Series(predictions)) final_predictions = pd.DataFrame(list(zip(loan_ids, prediction_series))) """We can be as creative in sending the responses. But we need to send the response codes as well. """ responses = jsonify(predictions=final_predictions.to_json(orient="records")) responses.status_code = 200 return (responses)
После выполнения, введите:
gunicorn --bind 0.0.0.0:8000 server:appДавайте сгенерируем данные для прогнозирования и очередь для локального запуска API по адресу
https:0.0.0.0:8000/predictimport json import requests
"""Setting the headers to send and accept json responses """ header = {'Content-Type': 'application/json', \ 'Accept': 'application/json'} """Reading test batch """ df = pd.read_csv('../data/test.csv', encoding="utf-8-sig") df = df.head() """Converting Pandas Dataframe to json """ data = df.to_json(orient='records')
data
'[{"Loan_ID":"LP001015","Gender":"Male","Married":"Yes","Dependents":"0","Education":"Graduate","Self_Employed":"No","ApplicantIncome":5720,"CoapplicantIncome":0,"LoanAmount":110.0,"Loan_Amount_Term":360.0,"Credit_History":1.0,"Property_Area":"Urban"},{"Loan_ID":"LP001022","Gender":"Male","Married":"Yes","Dependents":"1","Education":"Graduate","Self_Employed":"No","ApplicantIncome":3076,"CoapplicantIncome":1500,"LoanAmount":126.0,"Loan_Amount_Term":360.0,"Credit_History":1.0,"Property_Area":"Urban"},{"Loan_ID":"LP001031","Gender":"Male","Married":"Yes","Dependents":"2","Education":"Graduate","Self_Employed":"No","ApplicantIncome":5000,"CoapplicantIncome":1800,"LoanAmount":208.0,"Loan_Amount_Term":360.0,"Credit_History":1.0,"Property_Area":"Urban"},{"Loan_ID":"LP001035","Gender":"Male","Married":"Yes","Dependents":"2","Education":"Graduate","Self_Employed":"No","ApplicantIncome":2340,"CoapplicantIncome":2546,"LoanAmount":100.0,"Loan_Amount_Term":360.0,"Credit_History":null,"Property_Area":"Urban"},{"Loan_ID":"LP001051","Gender":"Male","Married":"No","Dependents":"0","Education":"Not Graduate","Self_Employed":"No","ApplicantIncome":3276,"CoapplicantIncome":0,"LoanAmount":78.0,"Loan_Amount_Term":360.0,"Credit_History":1.0,"Property_Area":"Urban"}]'
"""POST <url>/predict """ resp = requests.post("http://0.0.0.0:8000/predict", \ data = json.dumps(data),\ headers= header)
resp.status_code
200
"""The final response we get is as follows: """ resp.json()
{'predictions': '[{"0":"LP001015","1":1},{...
Заключение
В этой статье мы прошли лишь половину пути, создав рабочее API, которое выдает прогнозы, и стали на шаг ближе к интеграции ML решений непосредственно в разрабатываемые приложения. Мы создали достаточно простое API, которое поможет в прототипировании продукта и сделает его действительно функциональным, но чтобы отправить его в продакшн, необходимо внести несколько корректив, которые уже не входят в сферу изучения машинного обучения.
Есть несколько вещей, о которых нельзя забывать, в процессе создания API:
- Создание качественного API из спагетти-кода вещь почти невозможная, поэтому применяйте свои знания в области машинного обучения, чтобы создать полезное и удобное API.
- Попробуйте использовать контроль версий для моделей и кода API. Помните о том, что Flask не обеспечивает поддержку средств контроля версий. Сохранение и отслеживание ML моделей – это сложная задача, найдите удобный для себя способ. Здесь есть статья, которая рассказывает о том, как это делать.
- В связи со спецификой scikit-learn моделей, необходимо удостовериться что оценщик и код для обучения лежат рядом (в случае использования пользовательского оценщика для предобработки или иной подобной задачи). Таким образом законсервированная модель будет иметь рядом с собой оценщик класса.
Следующим логическим шагом будет создание механики для развертывания такого API на маленькой виртуальной машине. Есть разные способы сделать это, однако их мы рассмотрим в следующей статье.
Код и пояснения для этой статьи
Полезные источники:
[1] Don’t Pickle your data.
[2] Building Scikit Learn compatible transformers.
[3] Using jsonify in Flask.
[4] Flask-QuickStart.
Вот такой получился материал. Подписывайтесь на нас, если понравилась публикация, а также записывайтесь на бесплатный открытый вебинар по теме: «Метрические алгоритмы классификации», который уже 12 марта проведет разработчик и data scientist с 5-летним опытом — Александр Никитин.
