[Перевод] Развёртывание XGBoost-моделей с помощью Ray Serve
XGBoost — это оптимизированная библиотека, реализующая алгоритм градиентного бустинга. Эта библиотека спроектирована с прицелом на высокую продуктивность и гибкость, в ней используется параллельная работа с древовидными структурами, что позволяет быстро и эффективно решать различные задачи из сфер Data Science и Machine Learning. В предыдущем материале мы исследовали три подхода к ускорению обучения XGBoost-моделей.
Библиотека XGBoost, после появления, быстро стала эталонным инструментом, который направлен на решение задач, предусматривающих обработку структурированных данных. Причина этого, в основном, кроется в высокой скорости её работы и в её исключительной производительности. Она быстрее, чем другие реализации ансамблей классификаторов, её базовый алгоритм поддаётся распараллеливанию, то есть — её можно использовать в средах со множеством CPU и GPU.
Публиковать XGBoost-модели можно в облачных средах. Среди них — Amazon SageMaker, KubeFlow, Google Cloud AI Platform, Microsoft Azure ML SDK. Это — мощные платформы, поддерживаемые крупнейшими игроками рынка облачных услуг. Но плата за их использование может быть очень высока. Кроме того, они работают только в рамках собственных экосистем.
Самостоятельно довести модель машинного обучения от уровня концептуальной идеи до уровня продакшна — это, обычно, сложно и долго. Для облегчения решения этой задачи созданы несколько фреймворков. Они нацелены на развёртывание XGBoost-моделей в продакшне.
В этом материале мы расскажем о том, как развёртывать XGBoost-модели с помощью двух фреймворков — Flask и Ray Serve. Мы, кроме того, сравнивая характеристики работы моделей в продакшне, рассмотрим преимущества Ray Serve перед другими подобными решениями.
Развёртывание XGBoost-моделей с помощью Flask
Flask — это самый распространённый Python-микрофреймворк, используемый для развёртывания XGBoost-моделей. Дело в том, что он не имеет зависимостей от внешних библиотек. Flask считается исключительно удачным фреймворком для развёртывания XGBoost-моделей по нескольким причинам: его очень легко настраивать, он эффективен и поддерживает конечные точки REST. Кроме того, Flask, в отличие от XGBoost Server, не привязан ни к какому определённому фреймворку. Он поддерживает механизмы обработки HTTP-запросов. Flask, к тому же, ещё и бесплатен, что выгодно отличает его от SageMaker и других облачных решений. Выше перечислены лишь немногие возможности Flask, делающие этот фреймворк оптимальным решением для развёртывания XGBoost-моделей в продакшне.
В этом разделе мы обучим и протестируем XGBoost-модель, а потом развернём её с помощью Flask. Эта модель будет прогнозировать возникновение диабета с использованием набора данных pima-indians-diabetes
с сайта UCI Machine Learning Repository. Этот небольшой набор данных содержит числовые медицинские показатели, связанные с диабетом, представленные восемью признаками. Тут имеется и одна целевая переменная, определяющая результат — Outcome
. В результате мы воспользуемся XGBoost для моделирования и решения простой задачи прогнозирования.
Создание XGBoost-модели
Для начала, помимо данных, загрузим кое-какие зависимости. Потом запустим обучение:
from numpy import loadtxt
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# загрузка данных
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=",")
# разбиение набора данных на X и Y
X = dataset[:,0:8]
Y = dataset[:,8]
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.33, random_state=7)
Теперь создадим XGBoost-модель и обучим её на имеющихся числовых данных:
model = XGBClassifier()
model.fit(X_train, y_train)
После того, как модель обучится, протестируем её с использованием тестового набора данных. Далее — вычислим показатели, используемые для оценки качества модели:
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
Развёртывание XGBoost-модели с помощью Flask
Этот этап нашей работы состоит из нескольких шагов, представленных в следующих подразделах.
Сериализация модели с помощью модуля pickle
После того, как модель обучена и протестирована, её можно сохранить с помощью модуля pickle
, применяемого для сериализации моделей. Это позволит загрузить её тогда, когда она понадобится, и, передав ей входные данные, получить прогноз.
import pickle
# сохранение модели
with open('model.pkl','wb') as f:
pickle.dump(model, f)
# загрузка модели
with open("model.pkl", "rb") as f:
model = pickle.load(f)
Создание Flask-приложения, которое будет обслуживать модель
Для развёртывания XGBoost-модели мы воспользуемся фреймворком Flask. Чтобы создать Flask-приложение, которое может прогнозировать возникновение диабета, нам нужен будет соответствующий маршрут, обращение к которому позволит получить прогноз модели.
import pickle
import numpy as np
from flask import Flask, request, jsonify, render_template
app = Flask(__name__)
with open("model.pk", "rb") as f:
model = pickle.load(f)
@app.route("/predict", methods=["POST"])
def predict():
data = request.get_json(force=True)
prediction = model.predict([np.array(list(data.values()))])
output = prediction[0]
return jsonify(output)
if __name__ == "__main__":
app.run(debug=True)
Обращение к API predict с помощью запроса
На этом шаге мы создаём файл request.py
. Код этого файла выводит спрогнозированное значение, обращаясь к API, определённым в файле app.py
.
import requests
url = "http://localhost:5000/predict"
r = requests.post(
url,
json={
"Pregnancies": 6,
"Glucose": 148,
"BloodPressure": 72,
"SkinThickness": 35,
"Insulin": 0,
"BMI": 33.6,
"DiabetesPedigree": 0.625,
"Age": 50,
"Outcome": 1,
},
)
print(r.json())
Развёртывание XGBoost-модели с помощью Ray Serve
Несмотря на то, что Flask — это отличный, полезный инструмент для развёртывания ML-моделей, у него есть и минусы. Например, он не подходит для больших моделей, ему не хватает возможностей, позволяющих организовать вход в систему и аутентификацию пользователей.
Но, помимо этих минусов, главным недостатком Flask в деле обслуживания ML-моделей являются те сложности, которые встают перед тем, кому нужно масштабировать Flask-приложение. При использовании Flask масштабирование каждого из компонентов означает необходимость запуска множества параллельных экземпляров приложения. При этом разработчик сам должен принять решение о том, как именно это сделать. Может — эта задача будет решена с помощью виртуальных машин, а может — с помощью обычных серверов или посредством кластера Kubernetes. В любом случае разработчик будет заниматься запуском экземпляров приложения и балансировкой нагрузки. А вот развёртывание XGBoost-моделей с помощью Ray Serve позволяет сразу решить все эти проблемы. Дело в том, что эта система даёт разработчику простой веб-сервер, который берёт на себя решение сложных задач маршрутизации, масштабирования, тестирования моделей. То есть — всего того, что нужно для развёртывания моделей в продакшне.
С помощью Ray Serve можно без труда масштабировать модель в кластере Ray, состоящем из нескольких узлов. Это так благодаря возможности динамического обновления работающих экземпляров приложения. Ray Server, кроме того, это система, не привязанная к какому-то конкретному фреймворку. Поэтому с её помощью можно обеспечивать работу моделей, подготовленных с помощью различных фреймворков. Например — таких, как TensorFlow, PyTorch и Scikit-learn. В целом можно сказать, что Ray Serve — это система, которая позволяет организовывать высокоэффективную и высокопроизводительную работу моделей в продакшне.
Возьмём XGBoost-модель, которую мы создали выше, и развернём её с помощью Ray Serve.
Сначала установим Ray Serve:
pip install "ray[serve]"
Теперь запустим экземпляр Ray Serve, работающий поверх нескольких кластеров Ray.
ray start --head
Далее — запустим следующий Python-скрипт, в котором Ray Serve импортируется, инициализируется и запускается, а так же — подключается к локальному кластеру Ray:
import ray
from ray import serve
ray.init(address='auto', namespace="serve") # Подключение к локальному кластеру Ray.
serve.start(detached=True) # Запуск процессов Ray Serve в кластере Ray.
Обратите внимание на то, что тут метод serve.start
применяется для запуска нескольких агентов Ray, которые используются Ray Serve для маршрутизации HTTP-запросов к подходящим моделям.
Кроме того, анализируя этот пример, учитывайте то, что мы запускаем Ray всего лишь в локальном окружении, делая это для тестирования кода. Но и это уже даёт нам преимущество перед Flask. Дело в том, что Ray задействует все доступные CPU-ядра компьютера, в то время как Flask-приложение, созданное ранее, использует только одно ядро. И это — лишь малая часть полезных возможностей Flask. Так, не сложнее, чем в локальном окружении, модель можно развернуть на Ray-кластере, содержащем десятки или даже сотни узлов. Это позволяет масштабировать вычислительные ресурсы, выделяемые модели, не внося совершенно никаких изменений в код приложения.
Теперь, когда система Ray Serve готова к работе, пришло время создать модель и развернуть её. Так как наша XGBoost-модель уже создана и обучена, нам нужно лишь загрузить её и представить в виде класса. После этого можно начинать процесс её развёртывания с помощью Ray Serve. Этим и займёмся:
import pickle
import json
import ray
from ray import serve
@serve.deployment(num_replicas=2, route_prefix="/regressor")
class XGB:
def __init__(self):
with open("model.pkl", "rb") as f:
self.model = pickle.load(f)
async def __call__(self, starlette_request):
payload = await starlette_request.json()
print("Worker: received starlette request with data", payload)
input_vector = [
payload["Pregnancies"],
payload["Glucose"],
payload["Blood Pressure"],
payload["Skin Thickness"],
payload["Insulin"],
payload["BMI"],
payload["DiabetesPedigree"],
payload["Age"],
]
prediction = self.model.predict([input_vector])[0]
return {"result": prediction}
А теперь начинается настоящее волшебство. Следующие несколько строк кода развернут XGBoost-модель на работающем инстансе Ray Serve. Делается это посредством обращений к API Ray Serve в Python-фреймворке.
# Теперь инициализируем экземпляр Ray Serve или подключаемся к существующему экземпляру.
serve.start(detached=True)
# Развёртываем модель.
XGB.deploy()
Готово! XGBoost-модель успешно развёрнута в Ray Serve. Сделано это очень просто — путём вызова метода deploy
ранее объявленного класса. На самом деле, тут имеются две копии модели, работающие в одно и то же время и обрабатывающие ответы. Нашу систему легко масштабировать. Для этого достаточно настроить параметр num_replicas
.
Теперь мы можем обращаться к конечной точке развёрнутой модели, отправляя ей запросы. Обратите внимание на то, что HTTP-сервер, по умолчанию, работает на localhost:8000
.
import requests
sample_request_input = {
"Pregnancies": 6,
"Glucose": 148,
"BloodPressure": 72,
"SkinThickness": 35,
"Insulin": 0,
"BMI": 33.6,
"DiabetesPedigree": 0.625,
"Age": 50,
}
response = requests.get("http://localhost:8000/regressor", json=sample_request_input)
print(response.text)
# Ответ:
# "result": "1"
Как видно, если модель выдаёт результат 1 — это означает, что возникновение диабета «возможно» или «ожидается в скором времени». Если модель выдаёт 0 — это означает, что возникновение диабета не ожидается.
Итоги
Мы рассказали вам всё, что собирались! Теперь вы знаете о том, как развёртывать XGBoost-модели с использованием Flask, и о том, как без труда их масштабировать с помощью Ray Serve.
Для того чтобы больше узнать о Ray Serve — лучше всего начать с официальной документации. А именно — сначала можно освоить основы, а потом углубиться в детали обслуживания ML-моделей.
О, а приходите к нам работать?