# LR3 Создание сервиса предсказаний ## Цель Создать микросервис предсказаний моделью ML, создать его docker-образ и запустить сервис в контейнере. ## Задание 1. Активировать виртуальное окружение. Установить библиотеки `fastapi`, `uvicorn`, не забыв обновить `requirements.txt`. 2. Запустить mlflow, убедиться, что доступны экспериметы, прогоны и модели, сделанные в ЛР2. 3. Создать директорию `./services`, в ней еще одну директорию `ml_service`, и в ней основной файл `main.py`. ``` my_proj |_____ .venv_my_proj |_____ .git |_____ data | |___ ... | |_____ eda | |___ ... | |_____ research | |___ ... | |_____ services | |___ ml_service | |___main.py | |_____ .gitignore |_____ README.md |_____ requirements.txt ``` 4. В созданном файле создать экземпляр `FastAPI-приложения`, сделать обработку GET-запросов к корню приложения `/`, выдавая в ответ на запрос словарь `{"Hello": "World"}` > В ходе работы с файлами `.py` будут создаваться директории `__pycache__`, в которых хранятся скомпилированные байт-код модули `.pyc`. Эти папки коммитить не нужно. Добавьте правило в `.gitignore`. 5. Запустить сервер `uvicorn` и убедиться, что сервис обрабатывает запросы к корню, пройдя на страницу `http://localhost:8000/docs` и выполнив тестовый запрос. 6. Создать endpoint `/api/prediction` выдачи предсказания для объекта. Endpoint будет обрабатывает POST-запросы, принимая в качестве URL-параметра идентификатор объекта `item_id`, а в теле запроса (body) все признаки объекта, необходимые для подачи на вход модели и выдачи предсказания. Возвращать будет словарь из двух объектов - `item_id` - тот же идентификатор объекта, и `predict` - предсказанное значение. 7. Запустить сервер `uvicorn` и убедиться, что сервис обрабатывает запросы к `/api/prediction`, пройдя на страницу `http://localhost:8000/docs` и выполнив тестовый запрос к этому endpoint-у. Если сервис работает правильно, то вы должны увидеть ответ такой структуры: ``` Response body { "item_id": 123, "price": 0.7637315626006276 } ``` 8. В директории `./services` создать директорию `models`, в которой будет храниться обученная модель, а также скрипт по ее получению из mlflow. Создать скрипт `get_model.py` ``` my_proj |_____ .venv_my_proj |_____ .git |_____ data | |___ ... | |_____ eda | |___ ... | |_____ research | |___ ... | |_____ services | |___ ml_service | | |___main.py | |___models | |___get_model.py | |___model.pkl # Появится после выполнения следующего пункта | |_____ .gitignore |_____ README.md |_____ requirements.txt ``` 9. Сформировать скрипт `get_model.py`, который должен подключаться к mlflow, выгружать модель по её run_id и сохранять ее в файл `model.pkl`. 10. В GUI MLFlow скопировать run_id production-модели, указать его в скрипте. Запустить скрипт и убедиться, что в директории `./services/models` появился файл `model.pkl`. 11. В директории `ml_service` создать файл `api_handler.py` и в нем описать класс-обработчик запросов к API `FastAPIHandler`. Класс должен иметь метод `__init__` в котором загружается модель из файла `/model.pkl`, и метод `predict`, возвращающий предсказание. 12. Доработать основной модуль сервиса и класс-обработчик таким образом, чтобы сервис предсказывал значения для любого произвольного объекта, параметры которого передаются в теле запроса. Убедиться в корректности работы. Остановить сервис. 13. В папке `ml_service` создать файл `requirements.txt`, в который записать те зависимости, которые необходимы для работы сервиса. > Данный файл - не то же самое, что `requirements.txt` в корневой директории проекта. Данный файл будет использоваться для сборки образа, поэтому должен содержать только необходимые зависимости и их версии. Виртуальное окружение на хостовой машине по-прежнему нужно устанавливать из файла в корневой директории. > Проще всего заполнить этот `requirements.txt`, пройдясь по файлам в папке и выписав все импорты. Абсолютно точно на этом этапе в зависимости нужно добавить `fastapi`, `uvicorn`, `pandas`, `pickle4`. ``` my_proj |_____ .venv_my_proj ... | |_____ services | |___ ml_service | | |___main.py | | |___api_handler.py | | |___Dockerfile | | |___requirements.txt # новый файл, созданный на этом шаге | |___models | |___get_model.py | |___model.pkl | |_____ .gitignore |_____ README.md |_____ requirements.txt # старый файл, созданный в ЛР1 ``` 14. В папке `ml_service` cформировать `Dockerfile` Образ должен собираться Из базового образа `python:3.11-slim` по следующим шагам: * Скопировать содержимое текущей директории в директорию `/ml_service` в контейнере * Сделать директорию `/models` доступной снаружи контейнера * Сделать `/ml_service` рабочей директорией * Выполнить установку всех зависимостей из файла `requirements.txt` * Указать, что порт 8000 должен быть доступен снаружи контейнера * Финальная команда - запуск сервера. Необходимо явно указать адрес хоста `"0.0.0.0"` и порта `"8000"`, на которых будет запускаться сервер. Состав директорий проекта на данном шаге должен выглядеть следуюшим образом: ``` my_proj |_____ .venv_my_proj |_____ .git |_____ data | |___ ... | |_____ eda | |___ ... | |_____ research | |___ ... | |_____ services | |___ ml_service | | |___main.py | | |___api_handler.py | | |___Dockerfile | | |___requirements.txt | |___models | |___get_model.py | |___model.pkl | |_____ .gitignore |_____ README.md |_____ requirements.txt ``` 15. Собрать образ, дать ему понятное название и указав что это первая версия образа. Команду по сборке образа записать в конец `Dockerfile`, добавив значок комментария `#`. > В рамках это ЛР мы будем создавать первую версию нашего сервиса. Даже если вы несколько раз пересобираете образ, что-то меняя или добавляя в него, в этой ЛР все равно указывайте первую версию. > Версия указывается через двоеточие после названия образа. Например, для указания 3й версии образа: `my_super_image:3` 16. Запустить контейнер из образа. Команду по запуску контейнера записать в конец `Dockerfile`, добавив значок комментария `#`. > При запуске не забыть указать, какой хостовый порт должен быть связанным с портом 8000 внутри контейнера. > Указать, что хостовая директория ../models должна быть связана с одноименной директорией в контейнере. Поскольку мы собираем образ из директории `ml_service`, а интересующая директория с моделью `models` находится на уровень выше, то путь до нее можно указать так: `$(pwd)/../models`. Здесь `$(pwd)` (print working directory) - утилита командной строки, которая выводит полный путь до текущей директории. Через двоеточие от хостовой директории нужно указать соответствующий volume внутри контейнера. Полный агрумент будет выглядеть так: `$(pwd)/../models:/models` 17. Убедиться, что контейнер работает, отправив запрос в сервис. Добиться работоспособности сервиса. 18. Актуализировать файл README: * добавить описание разработанного сервиса: краткое описание файлов в папке ml_service, models. * Указать команды для создания образа и запуска контейнера. * Указать, как можно проверить работоспособность сервиса, включив пример тела запроса.