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

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

Прежде чем начинать работу, необходимо установить 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
Суть проекта в том, что пользователь загружает картинку с персонажем из "Симпсонов" и получает предположение сети о том, кто на ней изображен.

Сначала я описываю логику приложения, используя библиотеку 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.
Для моего приложения порядок установки выглядит так:
Install and run Docker
Build Docker image using
docker build . -t simp_serverRun Docker container using
docker run --rm -it -p 8888:8888 simp_serverGo to
http://localhost:8888/
Магия
Если вашей моделью захотят воспользоваться, для этого нужно будет:
Установить Docker
Загрузить репозиторий
Собрать образ (docker image)
Создать и запустить контейнер
Что дальше?
В статье я расскрыл лишь одну проблему, которую может решить Docker, - доставка приложения до клиента.
Вы можете попробовать задеплоить свою модель, даже если она просто классифицирует ирис.

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

Kopilov
24.07.2021 14:13Пользовались ли вы когда нибудь Docker? — Да
Считаете ли вы docker удобным для передачи продукта? — Да
Вы Data Scientist — Нет
(Фактически, плаваю где-то между бэкендером и инженером данных с навыками девопса, но не сайентист точно)

pavelkochkin1 Автор
24.07.2021 14:24Да, сейчас такое время, что границы ds очень размыты :) я думаю так можно сказать не только про сферу данных

AmberSP
06.08.2021 22:02Если надо заказчику ирисы показать, проще stremlit использовать с его хостингом

pavelkochkin1 Автор
07.08.2021 21:28Посмотрел библиотеку, выглядит интересно, большое спасибо за совет!
DaryaTsvetkova
Спасибо за статью!