# Docker для Data Scientist'a ![](https://i.imgur.com/aGPnIzx.png) ## Введение Часто у начинающих Data Scientists возникает вопрос, как демонстрировать работу своих моделей другим людям. Банальный пример - прикрепить ссылку на гитхаб репозиторий в отклике на вакансию или показать свое "детище" знакомым со словами "смотрите, что умею". Проще говоря, мы хотим задеплоить нашу модель, превратить ее в демо нашего исследования. Проблема в том, что для этого нужно скачивать репозиторий, установливать нужную версию python и всех необходимых библиотек, а также разбираться, как запускать приложение. Слишком много сложностей для человека, который хочет использовать или просто посмотреть вашу работу. То есть вопрос в том, как передать продукт клиенту. В статье я расскажу простыми словами, что такое Docker и как его можно использовать для реализации своих решений в Machine Learning. ## Что такое контейнеризация? ![](https://i.imgur.com/Mfit16L.png) Одна из болей Data Scientist'a — клиенты, которые "запутались в установке", у которых "непонятно написано" или "все сломалось". Контейнеризация позволяет решить эту проблему. Контейнер — отдельная операционная система, настроенная заранее. Она выполняет указания, которые даются при сборке образа этой системы. Контейнер использует процессорные ядра и оперативную память хост-машины. Другими словами, внутри нашей операционки мы запускаем другую с заранее подготовленной последовательностью действий. ## Docker ![](https://i.imgur.com/Z6o0rtS.jpg) Прежде чем начинать работу, необходимо установить [docker](https://hub.docker.com/) на компьютер или сервер. #### Создание образа Сначала нужно создать образ сервера, который называется `docker image`. Это можно сделать несколькими способами, но самый простой и понятный - создать файл с названием `Dockerfile`. Это будет скрипт, содержащий последовательность действий для сборки образа. В Docker образы могут наследоваться друг от друга, поэтому обычно в первой строчке за основу берут готовый образ: ``` FROM python:3.8-slim-buster ``` Готовые образы вы можете найти на [docker hub](https://hub.docker.com/search?q=&type=image) Теперь следует описать логику инициализации контейнера. Для этого существует много директив, например `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 репозиторий проекта](https://github.com/pavelkochkin1/simpsons-classification) Суть проекта в том, что пользователь загружает картинку с персонажем из "Симпсонов" и получает предположение сети о том, кто на ней изображен. ![](https://i.imgur.com/QF8C2ep.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 1. Загрузить репозиторий 2. Собрать образ (docker image) 3. Создать и запустить контейнер ## Что дальше? В статье я расскрыл лишь одну проблему, которую может решить Docker, - доставка приложения до клиента. Вы можете попробовать задеплоить свою модель, даже если она просто классифицирует ирис. ![](https://i.imgur.com/HvrwMCn.png) Таким образом, вы лучше поймете, как работать с Docker, и в дальнейшем сможете применять его в своих проектах. ## Полезные ссылки — [Docker Documentation](https://docs.docker.com/) — [Flask Documentation](https://flask.palletsprojects.com/en/2.0.x/) — [Подробнее про Docker](https://habr.com/ru/post/253877/) — [FastAPI Documentation](https://fastapi.tiangolo.com/) - бэкенд. Преимущество в том, что фрондэндер может легко получить все доступные методы через `/docs` Ключевые слова: machinelearning docker deep learning машинное обучение контейнеризация продукт Хабы: Машинное обучение Искусственный интеллект Big Data