Docker для Data Scientist'a

Kate

Administrator
Команда форума

Введение​

Часто у начинающих Data Scientists возникает вопрос, как демонстрировать работу своих моделей другим людям. Банальный пример - прикрепить ссылку на гитхаб репозиторий в отклике на вакансию или показать свое "детище" знакомым со словами "смотрите, что умею".
Проще говоря, мы хотим задеплоить нашу модель, превратить ее в демо нашего исследования.
Проблема в том, что для этого нужно скачивать репозиторий, установливать нужную версию python и всех необходимых библиотек, а также разбираться, как запускать приложение. Слишком много сложностей для человека, который хочет использовать или просто посмотреть вашу работу. То есть вопрос в том, как передать продукт клиенту.
В статье я расскажу простыми словами, что такое Docker и как его можно использовать для реализации своих решений в Machine Learning.

Что такое контейнеризация?​

21334dbf6ecca2460857d20c539c58aa.png

Одна из болей Data Scientist'a — клиенты, которые "запутались в установке", у которых "непонятно написано" или "все сломалось". Контейнеризация позволяет решить эту проблему.
Контейнер — отдельная операционная система, настроенная заранее. Она выполняет указания, которые даются при сборке образа этой системы. Контейнер использует процессорные ядра и оперативную память хост-машины. Другими словами, внутри нашей операционки мы запускаем другую с заранее подготовленной последовательностью действий.

Docker​

c218b311a5c742a07dc8706e575893b0.jpg

Прежде чем начинать работу, необходимо установить docker на компьютер или сервер.

Создание образа​

Сначала нужно создать образ сервера, который называется docker image. Это можно сделать несколькими способами, но самый простой и понятный - создать файл с названием Dockerfile. Это будет скрипт, содержащий последовательность действий для сборки образа.
В Docker образы могут наследоваться друг от друга, поэтому обычно в первой строчке за основу берут готовый образ:
FROM python:3.8-slim-buster
Готовые образы вы можете найти на docker hub
Теперь следует описать логику инициализации контейнера.
Для этого существует много директив, например RUN - для запуска какой-либо команды на сервере при сборке образа.
Ниже я опишу директивы, которые сам использовал для создания своего первого Docker-образа:
RUN mkdir /app
Команда, которая создает папку app внутри контейнера.
COPY . /app/
WORKDIR /app
Следующей командой мы копируем все файлы из локального диска (директории, где находится Dockerfile) в папку app. Затем мы объявляем app рабочей директорией.
RUN pip install -r requirements.txt
Я снова запускаю команду RUN для того, чтобы установить все зависимости внутри контейнера.
Еще раз уточню, что все пакеты с зависимостями находятся внутри контейнера и никак не пересекаются с версиями библиотек на локальном компьютере. То есть внутри контейнера своя виртуальная среда.
ENTRYPOINT ["python"]
CMD ["demo.py"]
Команда ENTRYPOINT позволяет объявить точку входа для сервера. Таким образом, при развертке сервера я запускаю Python в контейнере. Директива CMD говорит, что в командной строке/терминале я выполняю код внутри скобок.
Мы можем объединить две эти команды в одну:
CMD ["python", "demo.py"]

Создание контейнера​

После того, как вы сохранили данный файл, можно собирать образ. Делается это очень просто: достаточно прописать в командной строке
docker build . -t simp_server
Точка означает, что мы хотим собрать образ из Dockerfile, который находится в данной директории.
  • -t - тег для обозначения имени сервера
  • simp_server - любое имя сервера.
Итак, образ собран.
Для того, чтобы увидеть все образы на хост-машине, пропишем
docker images
Запускаем сервер следующей командой:
docker run --rm -it -p 8888:8888 simp_server
  • run создает контейнер.
  • --rm удаляет контейнер после завершения его работы.
  • -p 8888:8888 пробрасывает порты между хост-машиной и контейнером (порт на хост соответствует порту в контейнере).
  • simp_server определяет образ запускаемого сервера.

Пример деплоя модели c использованием Docker и flask​

github репозиторий проекта
Суть проекта в том, что пользователь загружает картинку с персонажем из "Симпсонов" и получает предположение сети о том, кто на ней изображен.
4e6539ef2689113f6180b1981b70c025.png

Сначала я описываю логику приложения, используя библиотеку flask в файле demo.py. В нем находится один метод, который запрашивает у пользователя картинку и возвращает предсказание.
Это тот код, который я прошу запустить docker сервер на старте.
import os

from flask import Flask
from flask import request
from flask import render_template

from model.model import MobNetSimpsons


app = Flask(__name__)
UPLOAD_FOLDER = "static/"

@app.route('/', methods=['GET', 'POST'])
def upload_predict():
if request.method == "POST":
image_file = request.files["image"]
image_location = os.path.join(
UPLOAD_FOLDER,
image_file.filename
)
if image_file:
image_file.save(image_location)
pred = model.predict(image_location)
return render_template(
"index.html",
prediction=pred[0],
proba=round(pred[1], 2),
image_loc=image_file.filename
)
return render_template("index.html", prediction=0, image_loc=None)

if __name__ == "__main__":
model = MobNetSimpsons()
app.run(port=8888, debug=True, host='0.0.0.0')

Также, мне понадобится класс, в котором инициализируется модель и объявляется метод для получения предсказания:
import pickle
import numpy as np

from torchvision import models
from torch import nn

from model.utils import *

DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'

class MobNetSimpsons():
def __init__(self):
print("Loading model...")
self.model = models.mobilenet_v3_large(pretrained=True)
num_features = 960
n_classes = 42
self.model.classifier = nn.Sequential(
nn.Linear(num_features, 1280, bias=True),
nn.Hardswish(),
nn.Dropout(p=0.2, inplace=True),
nn.Linear(1280, n_classes, bias=True)
)
print("Seting parameters...")
self.model.load_state_dict(torch.load('model/mobNetLarge.pth', map_location=DEVICE))
print("Seting on evaluation mode...")
self.model.eval()

self.label_encoder = pickle.loads(open('model/label_encoder.pkl', 'rb').read())
print("Model is ready!")

def predict(self, image_path):
img = prepare_img(image_path)

proba = predict_one_sample(self.model, img, device=DEVICE)
predicted_proba = np.max(proba)*100
y_pred = np.argmax(proba)

label = self.label_encoder.inverse_transform([y_pred])[0].split('_')
label = label_to_string(label)

return [label, predicted_proba]

Затем создаю Dockerfile и собираю образ:
docker build . -t simp_server
Далее создаю контейнер:
docker run --rm -it -p 8888:8888 simp_server

После этого перехожу по адресу http://localhost:8888/.
Если контейнер и приложение работают на вашем компьютере, то они будут работать и на другом компьютере, например, у вашего клиента.
Остается дать порядок команд для Docker'a.
Для моего приложения порядок установки выглядит так:
  1. Install and run Docker
  2. Build Docker image using docker build . -t simp_server
  3. Run Docker container using docker run --rm -it -p 8888:8888 simp_server
  4. Go to http://localhost:8888/

Магия​

Если вашей моделью захотят воспользоваться, для этого нужно будет:
  1. Установить Docker
  2. Загрузить репозиторий
  3. Собрать образ (docker image)
  4. Создать и запустить контейнер

Что дальше?​

В статье я расскрыл лишь одну проблему, которую может решить Docker, - доставка приложения до клиента.
Вы можете попробовать задеплоить свою модель, даже если она просто классифицирует ирис.
739ccfe0e2bdfbf9863e01c6ae264952.png

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

Полезные ссылки​

Подробнее про Docker
Docker Documentation
Flask Documentation


Источник статьи: https://habr.com/ru/post/569394/
 
Сверху