Разработка, развёртывание и поддержка моделей машинного обучения в продакшене может быть сложной и трудоёмкой задачей. Именно здесь на помощь приходит Machine Learning Operations (MLOps). MLOps — это набор практик, который автоматизирует управление ML-процессами и упрощает развёртывание моделей.

В этой статье я расскажу о некоторых основных практиках и инструментах MLOps на примере реализации проекта от начала до конца. Это поможет вам эффективнее управлять ML-проектами, начиная с разработки и заканчивая мониторингом в продакшене.

Прочитав эту статью, вы узнаете:

  • Как использовать DVC для версионирования данных.

  • Как отслеживать логи, артефакты и регистрировать версии моделей с помощью MLflow.

  • Как развернуть модель с помощью FastAPI, Docker и AWS ECS.

  • Как отслеживать модель в продакшене с помощью Evidently AI.

Весь исходный код, использованный в этой статье, доступен на GitHub.

Оглавление:

  1. Что такое MLOps?

  2. Настройка проекта

  3. Обучение модели

  4. Data Version Control (DVC)

  5. MLflow

  6. Makefile

  7. Config.yml

  8. FastAPI

  9. Docker

  10. AWS ECS

  11. Evidently AI

  12. Заключение и ссылки


Что такое MLOps?

MLOps — это набор методов и практик, направленных на упрощение и автоматизацию жизненного цикла систем машинного обучения. Цель MLOps — повысить эффективность и надёжность развёртывания ML-моделей в продакшене. MLOps устраняет разрыв между разработкой ML-моделей и их эксплуатацией, обеспечивая возможность их устойчивого и эффективного внедрения, управления и мониторинга в реальных условиях. Этот подход снижает риски ошибок при проектировании системы, способствуя более устойчивым и точным предсказаниям в реальной среде.

Изображение создано автором
Изображение создано автором

Зачем нам нужен MLOps?

Обычно любой ML-проект начинается с определения бизнес-задачи. После того, как задача определена, выполняются этапы извлечения данных, подготовки данных, создания признаков и обучения модели. Завершённая модель сохраняется в хранилище или системе управления версиями, чтобы инженерные и операционные команды могли её развернуть в продакшен-среде.

Что не так с этим подходом?

Такой подход создаёт разрыв между этапами разработки и развёртывания, что приводит к неэффективности и потенциальным ошибкам. Отсутствие тесного сотрудничества между дата-сайентистами и инженерами может привести к разработке моделей, которые недостаточно оптимизированы для продакшена, что в свою очередь может вызвать проблемы — такие как снижение производительности, трудности с масштабируемостью и поддержкой.

MLOps решает эти проблемы, создавая единый рабочий процесс, который объединяет разработку и эксплуатацию. Это гарантирует, что модели будут надёжными, масштабируемыми и проще в поддержке. Такой подход снижает риск ошибок, ускоряет развёртывание и поддерживает эффективность моделей за счёт непрерывного мониторинга их работы в продакшене.

Теперь, когда у нас есть базовое понимание MLOps, перейдём к части реализации.

Настройка проекта

Проект по машинному обучению требует стандартной структуры, чтобы его можно было легко поддерживать и модифицировать. Хорошо организованная структура проекта позволяет участникам команды сотрудничать эффективно и просто.

В данном проекте мы используем базовую структуру, которая поможет управлять всем жизненным циклом ML-проекта, включая сбор данных, предобработку, обучение модели, её оценку, развёртывание и мониторинг.

Для начала клонируйте репозиторий mlops-project с GitHub и следуйте инструкциям.

# клонируем репозиторий с GitHub
git clone https://github.com/prsdm/mlops-project.git

После клонирования структура проекта будет выглядеть примерно так:

.
├── .github                         # Метаданные и конфигурация DVC
│   └── workflows                   # GitHub Actions Workflows для CI/CD
│       └── docs.yml                
├── data                            # Директория для хранения файлов данных
│   ├── train.csv                   
│   └── test.csv                                  
├── docs                            # Документация проекта
│   └── index.md                    
├── models                          # Хранение обученных моделей 
├── mlruns                          # Директория для логов запусков и артефактов MLflow
├── steps                           # Исходный код для обработки данных и обучения модели
│   ├── __init__.py                
│   ├── ingest.py                   
│   ├── clean.py                    
│   ├── train.py                    
│   └── predict.py                  
├── tests                           # Директория для хранения тестов
│   ├── __init__.py                 
│   ├── test_ingest.py              
│   └── test_clean.py               
├── .gitignore                      # Игнорировать файлы, которые не нужно коммитить в Git
├── app.py                          # Файл приложения FastAPI
├── config.yml                      # Конфигурационный файл
├── data.dvc                        # Для отслеживания файлов данных и их версий
├── dataset.py                      # Скрипт для загрузки или генерации данных
├── dockerfile                      # Dockerfile для контейнеризации FastAPI
├── LICENSE                         # Лицензия на проект
├── main.py                         # Автоматизация обучения модели
├── Makefile                        # Хранение полезных команд, например make train или make test 
├── mkdocs.yml                      # Конфигурационный файл для MkDocs
├── README.md                       # Описание проекта
├── requirements.txt                # Файл зависимостей для воспроизведения окружения
├── samples.json                    # Пример данных для тестирования

'''Дополнительные файлы для мониторинга'''
├── data                           
│   └──production.csv               # Данные для мониторинга
├── monitor.ipynb                   # Ноутбук для мониторинга модели 
├── test_data.html                  # Результаты мониторинга для тестовых данных  
└── production_data.html            # Результаты мониторинга для данных в продакшене

Разбор структуры:

  • data: Хранит файлы данных, используемые для обучения и оценки модели.

  • docs: Содержит документацию проекта.

  • models: Хранит обученные ML-модели.

  • mlruns: Содержит логи и артефакты, созданные MLflow.

  • steps: Включает исходный код для загрузки данных, их очистки и обучения модели.

  • tests: Включает юнит-тесты для проверки работоспособности кода.

  • app.py: Содержит код FastAPI приложения для развёртывания модели.

  • config.yml: Конфигурационный файл для хранения параметров проекта и путей к ресурсам.

  • data.dvc: Отслеживает версии файлов данных с помощью DVC (Data Version Control, система управления версиями данных).

  • dataset.py: Скрипт для скачивания или генерации данных.

  • dockerfile: Используется для сборки Docker-образа для контейнеризации FastAPI приложения.

  • main.py: Автоматизирует процесс обучения модели.

  • Makefile: Содержит команды для автоматизации задач, таких как обучение или тестирование.

  • mkdocs.yml: Конфигурационный файл для MkDocs, который используется для генерации документации проекта.

  • requirements.txt: Содержит все необходимые пакеты для проекта.

  • samples.json: Содержит пример данных для тестирования.

  • monitor.ipynb: Jupyter Notebook для мониторинга производительности модели.

  • production_data.html и test_data.html: Хранят результаты мониторинга для тестовых и продуктивных данных.

Эта структура проекта предназначена для организации всего процесса работы с ML-проектом — от разработки до мониторинга.

Теперь давайте создадим виртуальное окружение и активируем его, используя следующие команды:

Для bash:

# создать виртуальное окружение
python3 -m venv venv
# активировать
source venv/bin/activate

Для cmd:

# создать виртуальное окружение
python -m venv venv
# активировать
.\venv\Scripts\activate

Затем установим все необходимые пакеты с помощью файла requirements.txt.

# установить все зависимости
pip install -r requirements.txt

Пример:

Пример настройки проекта. Полную версию GIF можно посмотреть по ссылке
Пример настройки проекта. Полную версию GIF можно посмотреть по ссылке

После настройки окружения и установки зависимостей можно переходить к этапу обучения модели.

Обучение модели

На первом этапе обучения модели необходимо получить данные из источника, который может находиться как в локальном хранилище, так и в удалённом. Для этого запустите файл dataset.py.

# для получения данных из источника# для получения данных из источника
python3 dataset.py

Этот скрипт извлекает данные из источника, разделяет их на обучающий и тестовый датасеты, а затем сохраняет их в директорию data/.

Пример:

Пример извлечения данных
Пример извлечения данных

После того как данные будут сохранены в директорию data, следующие шаги включают их очистку, обработку и обучение модели. Папка steps/ содержит модули для каждого из этих этапов.

# часть обучения модели из структуры проекта

├── steps/                     
│   ├── ingest.py              
│   ├── clean.py 
│   ├── train.py            
│   └── predict.py
├── main.py                    
├── models/model.pkl

Рассмотрим, что делает каждый файл:

  • ingestion.py — обрабатывает начальное извлечение данных, гарантируя, что данные правильно загружены и доступны для последующих этапов обработки.

  • clean.py — выполняет базовые задачи очистки и предобработки данных, такие как обработка пропущенных значений, удаление дублей и улучшение качества данных.

  • train.py — обучает модель на очищенных данных и сохраняет её как model.pkl в директории models/ для дальнейшего использования.

  • predict.py — используется для оценки производительности модели на тестовых данных с использованием обученной модели.

Примечание: Эти файлы могут быть изменены или удалены в зависимости от требований проекта.

Чтобы выполнить все эти шаги последовательно, запустите файл main.py:

# для обучения модели
python3 main.py

Вот как выглядит файл main.py в этом проекте:

import logging
from steps.ingest import Ingestion
from steps.clean import Cleaner
from steps.train import Trainer
from steps.predict import Predictor

# Настройка логирования
logging.basicConfig(level=logging.INFO,format='%(asctime)s:%(levelname)s:%(message)s')

def main():
    # Загрузка данных
    ingestion = Ingestion()
    train, test = ingestion.load_data()
    logging.info("Загрузка данных завершена успешно")

    # Очистка данных
    cleaner = Cleaner()
    train_data = cleaner.clean_data(train)
    test_data = cleaner.clean_data(test)
    logging.info("Очистка данных завершена успешно")

    # Подготовка и обучение модели
    trainer = Trainer()
    X_train, y_train = trainer.feature_target_separator(train_data)
    trainer.train_model(X_train, y_train)
    trainer.save_model()
    logging.info("Обучение модели завершено успешно")

    # Оценка модели
    predictor = Predictor()
    X_test, y_test = predictor.feature_target_separator(test_data)
    accuracy, class_report, roc_auc_score = predictor.evaluate_model(X_test, y_test)
    logging.info("Оценка модели завершена успешно")
    
    # Вывод результатов оценки
    print("\n============= Результаты оценки модели ==============")
    print(f"Модель: {trainer.model_name}")
    print(f"Точность: {accuracy:.4f}, ROC AUC: {roc_auc_score:.4f}")
    print(f"\n{class_report}")
    print("=====================================================\n")

if __name__ == "__main__":
    main()

Пример:

Пример обучения модели
Пример обучения модели

Теперь давайте рассмотрим, как можно улучшить этот проект с помощью таких инструментов, как DVC и MLflow.

Data Version Control (DVC)

Начнём с Data Version Control (DVC) — бесплатного инструмента с открытым исходным кодом, предназначенного для управления большими датасетами, автоматизации ML-пайплайнов и обработки экспериментов. Этот инструмент помогает DS и ML командам более эффективно управлять данными, обеспечивать воспроизводимость и улучшать совместную работу.

Почему стоит выбрать DVC, а не GitHub?

Git отлично подходит для версионирования исходного кода и текстовых файлов, но имеет ограничения при работе с большими бинарными файлами, такими как наборы данных. Git сохраняет новые версии бинарных файлов как отдельные копии, не показывая подробные различия между ними, что затрудняет отслеживание изменений с течением времени. Кроме того, хранение больших датасетов или конфиденциальной информации в GitHub не всегда оптимально, так как это может привести к разрастанию репозитория и потенциальным рискам безопасности.

DVC решает эти проблемы, управляя большими файлами через метаданные и внешние хранилища (например, S3, Google Cloud Storage или Azure Blob Storage), при этом отслеживая изменения данных и историю версий. DVC использует человекочитаемые метафайлы, которые хранятся в Git и содержат информацию о состоянии данных, что позволяет версионировать и передавать данные без добавления самих файлов в репозиторий. Кроме того, DVC обеспечивает безопасную совместную работу, обеспечивая контроль доступа к компонентам проекта и предоставляя возможность делиться ими с конкретными командами и пользователями.

Чтобы начать работу с DVC, сначала установите его (если он еще не установлен):

# установка DVC через pip
pip install dvc

Затем инициализируйте DVC:

# инициализировать DVC
dvc init

Это создаст необходимые конфигурационные файлы DVC.

Теперь добавьте файлы данных в DVC:

# добавляем данные
dvc add data

Это позволит отслеживать файлы данных с помощью DVC, при этом сами данные будут храниться во внешнем хранилище.

Настройка удалённого хранилища:

# добавить конфигурацию удалённого хранилища
dvc remote add -d <remote_name> <remote_storage_path>

Замените <remote_name> на название удалённого хранилища, а <remote_storage_path> на путь к удалённому хранилищу (например, s3://mybucket/mydata).

Загрузка данных в удалённое хранилище:

# зафиксировать изменения конфигурации DVC в Git
git commit .dvc/config -m 'config dvc store'
# загрузить данные в настроенное удалённое хранилище
dvc push

Эта команда загружает данные в настроенное удалённое хранилище.

Отправка всех зафиксированных изменений в git:

# отправить все зафиксированные изменения в Git-репозиторий
git push origin main

Пример:

Пример DVC push. Полную версию GIF можно посмотреть по ссылке.
Пример DVC push. Полную версию GIF можно посмотреть по ссылке.

Чтобы загрузить последнюю версию данных из удалённого хранилища в локальную директорию, используйте следующую команду:

# получить последнюю версию данных
dvc pull

Пример:

Пример DVC pull. Полную версию GIF можно посмотреть по ссылке
Пример DVC pull. Полную версию GIF можно посмотреть по ссылке

С помощью интеграции DVC можно эффективно управлять большими наборами данных, разгружая Git-репозиторий и сосредоточив его на исходном коде проекта.

Примечание: DVC можно использовать для версионирования моделей так же, как и для данных.

MLflow

После версионирования данных с помощью DVC крайне важно организовать чёткий учёт всех этапов обучения моделей, изменений версий и параметров, даже если вы не проводите активные эксперименты с разными моделями. 

Без системного отслеживания могут возникнуть следующие проблемы:

  • Потеря деталей версий: Без учёта параметров и изменений кода для каждой версии модели становится сложно воспроизвести прошлые результаты или продолжить работу с предыдущих версий. Это может замедлить прогресс и привести к повторению ошибок.

  • Трудности с сравнением версий: Регулярная фиксация результатов каждой модели помогает сравнивать разные версии. Без этого трудно понять, улучшается ли модель или нет.

  • Проблемы с командной работой: В команде отсутствие ясного управления версиями моделей может привести к путанице и случайным перезаписям, что усложняет совместную работу.

Здесь на помощь приходит MLflow. Этот инструмент полезен не только для экспериментов, но и играет ключевую роль в отслеживании жизненного цикла ML-моделей. MLflow ведёт логи метрик, артефактов и параметров, документируя и облегчая доступ к каждой версии модели. С его помощью можно мониторить каждое выполнение и сравнивать версии моделей, чтобы всегда была возможность выбрать самую эффективную модель для развертывания.

Чтобы интегрировать MLflow, сначала установите MLflow (если он ещё не установлен):

# установить mlflow
pip install mlflow

Затем обновите файл main.py, чтобы добавить логирование параметров, метрик и моделей. Код будет выглядеть примерно так:

import logging
import yaml
import mlflow
import mlflow.sklearn
from steps.ingest import Ingestion
from steps.clean import Cleaner
from steps.train import Trainer
from steps.predict import Predictor
from sklearn.metrics import classification_report

# Настройка логирования
logging.basicConfig(level=logging.INFO,format='%(asctime)s:%(levelname)s:%(message)s')

def main():

    with open('config.yml', 'r') as file:
        config = yaml.safe_load(file)

    mlflow.set_experiment("Model Training Experiment")
    
    with mlflow.start_run() as run:
        # Загрузка данных
        ingestion = Ingestion()
        train, test = ingestion.load_data()
        logging.info("Загрузка данных завершена успешно")

        # Очистка данных
        cleaner = Cleaner()
        train_data = cleaner.clean_data(train)
        test_data = cleaner.clean_data(test)
        logging.info("Очистка данных завершена успешно")

        # Подготовка и обучение модели
        trainer = Trainer()
        X_train, y_train = trainer.feature_target_separator(train_data)
        trainer.train_model(X_train, y_train)
        trainer.save_model()
        logging.info("Обучение модели завершено успешно")
        
        # Оценка модели
        predictor = Predictor()
        X_test, y_test = predictor.feature_target_separator(test_data)
        accuracy, class_report, roc_auc_score = predictor.evaluate_model(X_test, y_test)
        report = classification_report(y_test, trainer.pipeline.predict(X_test), output_dict=True)
        logging.info("Оценка модели завершена успешно")
        
        # Теги 
        mlflow.set_tag('Model developer', 'prsdm')
        mlflow.set_tag('preprocessing', 'OneHotEncoder, Standard Scaler, and MinMax Scaler')
        
        # Логирование метрик
        model_params = config['model']['params']
        mlflow.log_params(model_params)
        mlflow.log_metric("accuracy", accuracy)
        mlflow.log_metric("roc", roc_auc_score)
        mlflow.log_metric('precision', report['weighted avg']['precision'])
        mlflow.log_metric('recall', report['weighted avg']['recall'])
        mlflow.sklearn.log_model(trainer.pipeline, "model")
                
        # Регистрация модели
        model_name = "insurance_model" 
        model_uri = f"runs:/{run.info.run_id}/model"
        mlflow.register_model(model_uri, model_name)

        logging.info("Отслеживание в MLflow завершено успешно")

        # Вывод результатов оценки
        print("\n============= Результаты оценки модели ==============")
        print(f"Модель: {trainer.model_name}")
        print(f"Точность: {accuracy:.4f}, ROC AUC: {roc_auc_score:.4f}")
        print(f"\n{class_report}")
        print("=====================================================\n")
        
if __name__ == "__main__":
    main()

После этого запустите скрипт main.py и просмотрите детали эксперимента, используя следующую команду:

# запуск MLflow UI
mlflow ui

Откройте URL http://127.0.0.1:5000 в браузере, чтобы изучить и сравнить залогированные параметры, метрики и модели.

Пример:

Пример отслеживания MLflow
Пример отслеживания MLflow
Пример сравнения моделей в MLflow
Пример сравнения моделей в MLflow

С помощью MLflow можно легко отслеживать версии моделей и управлять изменениями, обеспечивая воспроизводимость и возможность выбора наиболее эффективной модели для развёртывания.

Прежде чем перейти к этапу развёртывания, давайте взглянем на файлы Makefile и config.yml, которые есть в проекте. Эти файлы помогают упростить рабочий процесс и гарантируют согласованность в настройке и конфигурации проекта.

Makefile

Использование Makefile в Python-проектах может значительно упростить управление задачами. Многие дата-сайентисты и ML-инженеры не осознают, что make позволяет автоматизировать рутинные операции, такие как настройка окружения, установка зависимостей, обучение модели, запуск тестов и очистка файлов. Это экономит время и снижает вероятность ошибок. Makefile широко используется в разработке ПО, потому что помогает управлять длинными и сложными командами, которые сложно запомнить.

Makefile в этом проекте выглядит примерно так:

bash:

python = venv/bin/python
pip = venv/bin/pip

setup:
 python3 -m venv venv
 $(python) -m pip install --upgrade pip
 $(pip) install -r requirements.txt

run:
 $(python) main.py

mlflow:
 venv/bin/mlflow ui

test:
 $(python) -m pytest
  
clean:
 rm -rf steps/__pycache__
 rm -rf __pycache__
 rm -rf .pytest_cache
 rm -rf tests/__pycache__

remove:
 rm -rf venv

Для Windows (cmd) файл необходимо немного изменить.

python = venv/Scripts/python
pip = venv/Scripts/pip

setup:
 python -m venv venv
 $(python) -m pip install --upgrade pip
 $(pip) install -r requirements.txt

run:
 $(python) main.py

mlflow:
 venv/Scripts/mlflow ui

test:
 $(python) -m pytest
  
clean:
 @if exist steps\__pycache__ (rmdir /s /q steps\__pycache__)
 @if exist __pycache__ (rmdir /s /q __pycache__)
 @if exist .pytest_cache (rmdir /s /q .pytest_cache)
 @if exist tests\__pycache__ (rmdir /s /q tests\__pycache__)

remove:
 @if exist venv (rmdir /s /q venv)

Разбор каждой части:

  • make setup: Создаёт виртуальное окружение (venv), обновляет pip и устанавливает необходимые пакеты из файла requirements.txt, обеспечивая совместимость всех зависимостей в разных средах.

  • make run: Запускает скрипт main.py с помощью интерпретатора Python из виртуального окружения.

  • make mlflow: Запускает mlflow ui для отслеживания экспериментов и метрик моделей.

  • make test: Выполняет все тесты, определённые в проекте, с использованием pytest.

  • make clean: Удаляет временные файлы, такие как __pycache__, .pytest_cache и другие, чтобы поддерживать чистоту директории.

  • make remove: Полностью удаляет виртуальное окружение (venv) из проекта.

Пример команд для запуска Makefile:

# Например, для настройки окружения
make setup

# ИЛИ для запуска основного скрипта
make run

# ИЛИ для запуска тестов
make test

# и так далее...

Пример:

Пример использования команд Make
Пример использования команд Make

С помощью Makefile можно автоматизировать и оптимизировать выполнение различных задач, что способствует согласованности и снижает количество ошибок при работе в разных средах.

Config.yml

Файлы YAML — удобный способ хранения и управления конфигурационными настройками для ML-моделей. Они позволяют централизованно управлять путями к данным и моделям, параметрами моделей и другими конфигурациями, что упрощает эксперименты с различными настройками и обеспечивает переиспользуемость кода.

Файл Config.yml выглядит примерно так:

data: 
  train_path: data/train.csv
  test_path: data/test.csv

train:
  test_size: 0.2
  random_state: 42
  shuffle: true

model:
  name: DecisionTreeClassifier
  params:
    criterion: entropy
    max_depth: null
  store_path: models/

  # name: GradientBoostingClassifier
  # params:
  #   max_depth: null
  #   n_estimators: 10
  # store_path: models/

  # name: RandomForestClassifier
  # params:
  #   n_estimators: 50
  #   max_depth: 10
  #   random_state: 42
  # store_path: models/

Вот что делает каждая часть:

  • data: Указывает пути к обучающим, тестовым и продуктивным (последним) датасетам. Это позволяет централизованно управлять расположением данных и легко обновлять их.

  • train: Содержит параметры для разделения данных на обучающие и тестовые наборы, такие как test_size (размер тестового набора), random_state (начальное значение для генерации случайных чисел) и параметр shuffle (перемешивание данных). Эти настройки помогают поддерживать согласованность при разделении данных и обеспечивают воспроизводимость.

  • model: Определяет имя модели, её параметры и путь для сохранения обученной модели. Такая конфигурация позволяет легко переключаться между разными моделями, обеспечивая гибкость в выборе моделей.

Использование файла config.yml упрощает управление параметрами модели и путями к данным, позволяя экспериментировать с разными конфигурациями и моделями. Это улучшает воспроизводимость за счёт единых настроек параметров и поддерживает чистоту кода, отделяя конфигурацию от логики.

Пример:

В следующем примере модель изменена на ‘GradientBoostingClassifier’ на основе настроек, указанных в файле config.yml.

Пример файла config.yml
Пример файла config.yml

Теперь перейдём к этапу развёртывания, где будут использованы FastAPI, Docker и AWS ECS. Эта настройка поможет создать масштабируемое и легко управляемое приложение для обслуживания ML-модели.

FastAPI

FastAPI — это современный фреймворк для создания API с использованием Python, который отлично подходит для обслуживания ML-моделей благодаря своей скорости и простоте.

Для начала установите FastAPI и Uvicorn (если они ещё не установлены):

# установка fastapi и uvicorn
pip install fastapi uvicorn

Определите приложение FastAPI и конечные точки для обслуживания модели в файле app.py.

from fastapi import FastAPI
from pydantic import BaseModel
import pandas as pd
import joblib

app = FastAPI()

class InputData(BaseModel):
    Gender: str
    Age: int
    HasDrivingLicense: int
    RegionID: float
    Switch: int
    PastAccident: str
    AnnualPremium: float

model = joblib.load('models/model.pkl')

@app.get("/")
async def read_root():
    return {"health_check": "OK", "model_version": 1}

@app.post("/predict")
async def predict(input_data: InputData):
    
        df = pd.DataFrame([input_data.model_dump().values()], 
                          columns=input_data.model_dump().keys())
        pred = model.predict(df)
        return {"predicted_class": int(pred[0])}

Затем протестируйте сервер FastAPI локально, открыв http://127.0.0.1:8000/docsusing и выполнив следующую команду:

# запустить приложение FastAPI
uvicorn app:app --reload

Пример:

Пример FastAPI
Пример FastAPI

Теперь давайте контейнеризуем этот API с использованием Docker.

Docker

Docker — это платформа с открытым исходным кодом, которая упрощает развёртывание программных приложений, помещая их в контейнеры. Эти контейнеры — лёгкие и портативные единицы, содержащие всё необходимое для запуска приложения в различных средах.

Зачем использовать контейнеры?

Контейнеры обеспечивают удобную изоляцию приложений и позволяют развёртывать их так, чтобы они работали одинаково в разных средах, будь то ноутбук разработчика или облако. Такая изоляция повышает переносимость и эффективность использования ресурсов, делая Docker важным инструментом в современном процессе разработки ПО.

Для установки Docker следуйте инструкциям на официальном сайте Docker.

Теперь создайте файл Dockerfile в директории проекта для сборки Docker-образа:

# официальный образ Python 3.10
FROM python:3.10

# задать рабочую директорию
WORKDIR /app

# добавить app.py и директорию models
COPY app.py .
COPY models/ ./models/

# добавить файл зависимостей
COPY requirements.txt .

# установить библиотеки Python
RUN pip install --no-cache-dir -r requirements.txt

# указать команды по умолчанию
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "80"]

Теперь создайте образ Docker с помощью следующей команды:

# Для сборки Docker-образа
docker build -t <image_name> <path_to_dockerfile>

Пример:

Пример сборки докера
Пример сборки докера

Наконец, запустите контейнер Docker для тестирования API по адресу http://localhost:80/predict:

# Для запуска Docker-контейнера
docker run -d -p 80:80 <image_name>

Пример:

Пример запуска docker
Пример запуска docker

Чтобы остановить запущенный контейнер Docker, найдите идентификатор или имя запущенного контейнера с помощью следующей команды:

# Показать запущенные контейнеры
docker ps

После определения идентификатора или имени контейнера его можно остановить с помощью следующей команды:

# Остановить контейнер
docker stop <container_id_or_name>

Пример:

Пример остановки запущенного контейнера
Пример остановки запущенного контейнера

Теперь, чтобы загрузить образ Docker в Docker Hub, выполните следующие шаги:

  1. Выведите список всех Docker-образов в системе с их тегами, чтобы найти нужный образ для загрузки:

# Вывести список изображений по имени и тегу
docker image ls

2. Присвойте образу тег, указав нужный репозиторий и имя:

# Задать тег изображению
docker tag <image_name> <dockerhub_username>/<docker-repo-name>

3. Загрузите образ с тегом в Docker Hub с помощью следующей команды:

# Загрузить Docker-образ
docker push <dockerhub_username>/<docker-repo-name>:latest

Эта команда загрузит образ в указанный репозиторий на Docker Hub.

Пример:

Пример команд Docker Push. Полную версию GIF можно посмотреть по ссылке
Пример команд Docker Push. Полную версию GIF можно посмотреть по ссылке
Пример репозитория Docker Hub
Пример репозитория Docker Hub

Теперь, когда образ Docker загружен в Docker Hub, он доступен для развёртывания в AWS Elastic Container Service (ECS).

AWS ECS

AWS ECS — это полностью управляемый сервис для оркестрации контейнеров, который позволяет легко запускать и масштабировать Docker-контейнеры на AWS. Он поддерживает запуск как на EC2, так и на Fargate. Вот пошаговое руководство:

  1. Для начала создайте кластер ECS:

  • Шаг 1: Войдите в свою учётную запись AWS, перейдите в сервис ECS и выберите «Создать кластер» (Create Cluster).

  • Шаг 2: Дайте кластеру имя, выберите тип запуска AWS Fargate (без серверов) и нажмите «Создать» (Create). Это займёт несколько минут.

Пример кластера AWS
Пример кластера AWS

Затем определите Task Definition (определение задачи):

  1. Шаг 1: В консоли ECS перейдите в раздел «Task Definitions» и создайте новое определение задачи.

  2. Шаг 2: Присвойте задаче имя и настройте такие параметры, как требования к памяти и процессору.

  3. Шаг 3: В разделе «Container Definitions» укажите URL-адрес образа Docker из Docker Hub и оставьте настройки маппинга портов контейнера по умолчанию. Нажмите «Create» (создать).

Пример Task Definition
Пример Task Definition

После этого добавьте Security Group (группу безопасности):

  1. Шаг 1: Перейдите в EC2, в разделе «Networks and Security» (Сети и безопасность) выберите «Security Groups» (Группы безопасности) и нажмите «Create Security Group» (Создать группу безопасности). Присвойте ей имя и описание.

  2. Шаг 2: В разделе «Inbound Rules» (Входящие правила) выберите тип HTTP и источник Anywhere-IPv4 Затем добавьте аналогичное правило для Anywhere-IPv6. Нажмите «Create Security Group» (Создать группу безопасности).

Пример AWS security Group
Пример AWS security Group

Затем создайте Service (службу):

  1. Шаг 1: Перейдите к созданному кластеру ECS и добавьте новую службу.

  2. Шаг 2: Выберите параметры вычислений типа запуска и тип запуска Fargate. Затем выберите ранее созданное определение задачи (Task definition) и укажите имя службы в настройках развёртывания.

  3. Шаг 3: Наконец, выберите созданную ранее группу безопасности в разделе «Networking» (сетевые настройки) и нажмите «Create» (создать). Процесс создания службы займет примерно 5–8 минут.

Пример сервисов
Пример сервисов

И наконец, доступ к запущенной службе: 

После развёртывания службы откройте вкладку Services в вашем кластере ECS. Найдите нужную службу, перейдите во вкладку Tasks (Задачи) и выберите активную задачу. Используйте публичный IP-адрес задачи для подключения к приложению FastAPI. Это будет выглядеть примерно так:

Пример публичного IP
Пример публичного IP
Пример развёрнутой службы
Пример развёрнутой службы

Следуя этим шагам, вы развернёте приложение FastAPI в Docker-контейнере на AWS ECS. Это обеспечивает масштабируемую и управляемую среду для обслуживания ML-модели.

Примечание: По необходимости можно добавить Elastic Load Balancing (ELB) для распределения нагрузки.

После успешного развертывания модели следующим шагом будет постоянный мониторинг её работы в продуктивной среде, чтобы убедиться, что она справляется с данными на продакшене. Мониторинг модели включает оценку различных факторов, таких как метрики сервера (например, использование CPU, потребление памяти, задержка), качество данных, data drift (смещение данных), target drift (смещение целевой переменной), concept drift (изменение концепции), производственные метрики и т.д.

Для простоты сосредоточимся на нескольких методах мониторинга, таких как data drift, target drift и качество данных, с использованием инструмента Evidently AI.

Evidently AI

Evidently AI — это отличный инструмент для мониторинга производительности моделей, обнаружения смещений данных (data drift) и оценки качества данных с течением времени. Он помогает гарантировать, что модель остаётся точной и надёжной при поступлении новых данных. Evidently AI предоставляет подробные отчёты о том, как меняется производительность модели, и выявляет значительные сдвиги в распределении данных, что критически важно для поддержания точности модели в продакшене.

Для установки Evidently AI используйте следующую команду:

# для установки
pip install evidently

# или
pip install evidently @ git+https://github.com/evidentlyai/evidently.git

Затем запустите файл monitor.ipynb, чтобы обнаружить возможные проблемы с качеством данных, а также смещения данных (data drift) и целевых переменных (target drift). Файл выглядит примерно так:

# Если этот .py файл не работает, используйте ноутбук для его запуска.
import joblib
import pandas as pd
from steps.clean import Cleaner
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset, DataQualityPreset, TargetDriftPreset
from evidently import ColumnMapping
import warnings
warnings.filterwarnings("ignore")


# # импортировать версию модели 1 из mlflow
# import mlflow
# logged_model = 'runs:/47b6b506fd2849429ee13576aef4a852/model'
# model = mlflow.pyfunc.load_model(logged_model)

# # ИЛИ импортировать из models/
model = joblib.load('models/model.pkl')


# Загрузка данных
reference = pd.read_csv("data/train.csv")
current = pd.read_csv("data/test.csv")
production = pd.read_csv("data/production.csv")


# Очистка данных
cleaner = Cleaner()
reference = cleaner.clean_data(reference)
reference['prediction'] = model.predict(reference.iloc[:, :-1])

current = cleaner.clean_data(current)
current['prediction'] = model.predict(current.iloc[:, :-1])

production = cleaner.clean_data(production)
production['prediction'] = model.predict(production.iloc[:, :-1])


# Применить отображение столбцов
target = 'Result'
prediction = 'prediction'
numerical_features = ['Age', 'AnnualPremium', 'HasDrivingLicense', 'RegionID', 'Switch']
categorical_features = ['Gender','PastAccident']
column_mapping = ColumnMapping()

column_mapping.target = target
column_mapping.prediction = prediction
column_mapping.numerical_features = numerical_features
column_mapping.categorical_features = categorical_features



# Часть обнаружения дрейфа данных
data_drift_report = Report(metrics=[
    DataDriftPreset(),
    DataQualityPreset(),
    TargetDriftPreset()
])
data_drift_report.run(reference_data=reference, current_data=current, column_mapping=column_mapping)
data_drift_report
# data_drift_report.json()
data_drift_report.save_html("test_drift.html")

Пример тестовых данных:

Пример обнаружения качества и смещения тестовых данных
Пример обнаружения качества и смещения тестовых данных

Пример продуктивных данных:

Пример обнаружения качества и смещения продуктивных данных
Пример обнаружения качества и смещения продуктивных данных

Запускайте скрипт мониторинга регулярно на поступающих данных, чтобы генерировать отчёты о смещениях данных и производительности модели. Эти отчёты помогут вовремя повторно обучить модель и гарантировать её точность и надёжность в долгосрочной перспективе.

С этим шагом мы успешно завершили реализацию проекта MLOps.

Заключение

В этой статье мы рассмотрели основные практики и инструменты MLOps через практический проект. Мы версионировали данные с помощью DVC, отслеживали и регистрировали модели с использованием MLflow, а также развернули модель с помощью FastAPI, Docker и AWS ECS. Кроме того, мы настроили мониторинг модели (качество данных, смещение данных и целевых переменных) с помощью Evidently AI. Эти шаги создают прочную основу для управления ML-проектами с использованием инструментов и практик MLOps — от разработки до продакшена. По мере накопления опыта с этими инструментами и методами можно исследовать более продвинутые методы автоматизации и оркестрации для улучшения рабочих процессов MLOps.

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

  1. Операции машинного обучения (MLOps): Обзор, определение и архитектура

  2. Система управления версиями данных (DVC)

  3. MLflow

  4. FastAPI

  5. Docker

  6. Evidently AI

Все актуальные методы и инструменты DS и ML можно освоить на онлайн-курсах OTUS: список всех программ можно посмотреть в каталоге.

Также приглашаем всех желающих на открытые уроки по ML:

— 6 ноября: «Облачная инфраструктура для ML инженера на базе Yandex Cloud». Узнать подробнее
— 7 ноября: «Структура и построение ML команды». Узнать подробнее

Комментарии (1)


  1. virrus
    01.11.2024 04:08

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

    А DVC разве умеет показывать diff для хранимых в нём файлов?