---
# System prepended metadata

title: Docker для Data Scientist'a

---

# 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

