MLOps - Cook book, chapter 1

MLOps - Cook book, chapter 1

Всім привіт! Я CV-розробник у КРОК. Вже 3 роки ми реалізуємо проекти у галузі CV. За цей час чого ми тільки не робили, наприклад: моніторили водіїв, щоб під час руху вони не пили, не курили, телефоном не розмовляли, дивилися на дорогу, а не сни чи хмари; фіксували любителів їздити виділеними смугами і займати кілька місць на парковці; стежили, щоб працівники носили каски, рукавички тощо; ідентифікували працівника, який хоче пройти на об'єкт; підраховували все, що тільки можна.

Я все це до чого?

У процесі реалізації проектів ми набили шишки, багато шишок, з частиною проблем ви або знайомі, або познайомитеся у майбутньому.

Моделюємо ситуацію

Уявимо, що ми влаштувалися молоду компанію “N”, діяльність якої пов'язані з ML. Працюємо ми над ML (DL, CV) проектом, потім з якихось причин перемикаємось на іншу роботу, загалом робимо перерву, і повертаємося до своєї чи чужої нейроночки.

  1. Настає момент істини, потрібно якось згадати на чому ти зупинився, які гіперпараметри пробував і, найголовніше, яких результатів вони привели. Може бути безліч варіантів, хто зберігав інформацію по всіх запусках: в голові, конфігах, блокноті, в робочому середовищі в хмарі. Мені довелося бачити варіант, коли гіперпараметри зберігалися як закоментованих рядків у коді, загалом політ фантазії. А тепер уявіть, що ви повернулися не до свого проекту, а до проекту людини, яка покинула компанію і у спадок вам дістався код та модель під назвою model_1.pb. Для повноти картини і передачі всього болю, уявимо, що ви ще й фахівець-початківець.
  2. Йдемо далі. Для запуску коду нам і всім, хто буде з ним працювати, необхідно створити оточення. Часто буває, що його нам у спадок також з якихось причин не залишили. Це також може стати нетривіальним завданням. На цей крок не хочеться витрачати час, чи не так?
  3. Тренуємо модель (наприклад, детектор автомобілів). Доходимо до моменту, коли вона стає дуже нічого - саме час зберегти результат. Назвемо її car_detection_v1.pb. Потім тренуємо ще одну – car_detection_v2.pb. Через деякий час наші колеги або ми самі навчаємо ще й ще, використовуючи різні архітектури. У результаті формується купа артефактів, інформацію про які потрібно ретельно збирати (але, робити ми це будемо пізніше, адже у нас поки є більш пріоритетні відносини).
  4. Ну от і все! Ми маємо модель! Ми можемо приступати до навчання наступної моделі, розробки архітектури для вирішення нового завдання або можемо піти попити чай? А деплоїти хто?

Виявляємо проблеми

Робота над проектом чи продуктом – це праця багатьох людей. А з часом люди йдуть і приходять, проектів стає більше, самі проекти стають складнішими. Так чи інакше, ситуації з описаного вище циклу (і не тільки) у тих чи інших комбінаціях зустрічатимуться від ітерації до ітерації. Все це виливається в марнування часу, плутанину, нерви, можливо — в невдоволення замовника, і, зрештою, — у втрачені гроші. Хоча всі ми зазвичай ходимо по старих граблях, але вважаю, що ніхто при цьому не хоче щоразу переживати ці моменти.

MLOps - Cook book, chapter 1

Отже, ми пройшли одним циклом розробки і бачимо, що є проблеми, які необхідно вирішити. Для цього потрібно:

  • зручно зберігати результати;
  • зробити простим процес залучення нових працівників;
  • спростити процес розгортання середовища розробки;
  • налаштувати процес версіонування моделей;
  • мати зручний спосіб валідації моделей;
  • знайти інструмент керування станом моделей;
  • знайти спосіб доставки моделей у production.

Мабуть, необхідно придумати workflow, який би дозволяв легко і зручно керувати цим життєвим циклом? Така практика має назву MLOps

MLOps, або DevOps для машинного навчання, дозволяє командам фахівців з обробки та аналізу даних та ІТ-фахівців співпрацювати, а також збільшувати темпи розробки та розгортання моделей за допомогою моніторингу, перевірки та системи керування для моделей машинного навчання.

можете почитати, Що про все це думають хлопці з Google. Зі статті зрозуміло, що MLOps, досить, об'ємна штука.

MLOps - Cook book, chapter 1

Далі у статті я опишу лише частину процесу. Для реалізації користуюся інструментом MLflow, т.к. це open-source проект, для підключення потрібна невелика кількість коду і є інтеграція з популярними ml-фреймворками. Ви можете пошукати на просторах інтернету інші інструменти, наприклад Kubeflow, SageMaker, Trains і т.д., і можливо підібрати той, який краще підходить під ваші потреби.

"Будуємо" MLOps на прикладі використання інструменту MLFlow

MLFlow – це платформа з відкритим вихідним кодом для керування життєвим циклом ml моделей (https://mlflow.org/).

MLflow включає чотири компоненти:

  • MLflow Tracking – закриває питання фіксації результатів та параметрів, які до цього результату привели;
  • MLflow Project - дозволяє упаковувати код та відтворити його на будь-якій платформі;
  • MLflow Models - відповідає за деплою моделей в прод;
  • MLflow Registry - дозволяє зберігати моделі та керувати їх станом у централізованому сховищі.

MLflow оперує двома сутностями:

  • запуск - це повний цикл навчання, параметри та метрики за якими ми хочемо реєструвати;
  • експеримент - це "тема" якої об'єднані запуски.

Усі кроки прикладу реалізовані операційною системою Ubuntu 18.04.

1. Розгортаємо сервер

Для того, щоб ми могли легко керувати нашим проектом та отримувати всю необхідну інформацію, розгорнемо сервер. MLflow tracking server має два основні компоненти:

  • backend store - відповідає за зберігання інформації про зареєстровані моделі (підтримує 4 СУБД: mysql, mssql, sqlite, and postgresql);
  • artifact store відповідає за зберігання артефактів (підтримує 7 варіантів зберігання: Amazon S3, Azure Blob Storage, Google Cloud Storage, FTP Server, SFTP Server, NFS, HDFS).

В якості магазин артефактів для простоти візьмемо сервер sftp.

  • створюємо групу
    $ sudo groupadd sftpg
  • додаємо користувача та встановлюємо йому пароль
    $ sudo useradd -g sftpg mlflowsftp
    $ sudo passwd mlflowsftp 
  • коригуємо пару налаштувань доступу
    $ sudo mkdir -p /data/mlflowsftp/upload
    $ sudo chown -R root.sftpg /data/mlflowsftp
    $ sudo chown -R mlflowsftp.sftpg /data/mlflowsftp/upload
  • додаємо кілька рядків у /etc/ssh/sshd_config
    Match Group sftpg
     ChrootDirectory /data/%u
     ForceCommand internal-sftp
  • перезапускаємо службу
    $ sudo systemctl restart sshd

В якості серверний магазин візьмемо postgresql.

$ sudo apt update
$ sudo apt-get install -y postgresql postgresql-contrib postgresql-server-dev-all
$ sudo apt install gcc
$ pip install psycopg2
$ sudo -u postgres -i
# Create new user: mlflow_user
[postgres@user_name~]$ createuser --interactive -P
Enter name of role to add: mlflow_user
Enter password for new role: mlflow
Enter it again: mlflow
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
# Create database mlflow_bd owned by mlflow_user
$ createdb -O mlflow_user mlflow_db

Для запуску сервера необхідно встановити такі python пакети (раджу створити окреме віртуальне оточення):

pip install mlflow
pip install pysftp

Запускаємо наш сервер

$ mlflow server  
                 --backend-store-uri postgresql://mlflow_user:mlflow@localhost/mlflow_db 
                 --default-artifact-root sftp://mlflowsftp:mlflow@sftp_host/upload  
                --host server_host 
                --port server_port

2. Додаємо трекінг

Для того щоб результати наших тренувань не зникли, майбутні покоління розробників розуміли, що взагалі відбувалося, а старші товариші і ви могли спокійно аналізувати процес навчання, нам необхідно додати трекінг. Під трекінгом мається на увазі збереження параметрів, метрик, артефактів та будь-якої додаткової інформації про запуск навчання, у нашому випадку, на сервері.

Для прикладу, я створив невеликий проект на github на Keras по сегментації всього, що є в COCO датасеті. Для додавання трекінгу створив файл mlflow_training.py.

Ось рядки, в яких відбувається найцікавіше:

def run(self, epochs, lr, experiment_name):
        # getting the id of the experiment, creating an experiment in its absence
        remote_experiment_id = self.remote_server.get_experiment_id(name=experiment_name)
        # creating a "run" and getting its id
        remote_run_id = self.remote_server.get_run_id(remote_experiment_id)

        # indicate that we want to save the results on a remote server
        mlflow.set_tracking_uri(self.tracking_uri)
        mlflow.set_experiment(experiment_name)

        with mlflow.start_run(run_id=remote_run_id, nested=False):
            mlflow.keras.autolog()
            self.train_pipeline.train(lr=lr, epochs=epochs)

        try:
            self.log_tags_and_params(remote_run_id)
        except mlflow.exceptions.RestException as e:
            print(e)

Тут self.remote_server – це невелика обв'язка над методами mlflow.tracking. MlflowClient (я зробив для зручності), за допомогою яких я створюю експеримент і запуск на сервері. Далі вказую, куди повинні зливатися результати запуску (mlflow.set_tracking_uri(self.tracking_uri)). Підключаю автоматичне логування mlflow.keras.autolog(). На даний момент MLflow Tracking підтримує автоматичне логування для TensorFlow, Keras, Gluon XGBoost, LightGBM, Spark. Якщо ви не знайшли свого фреймворку або бібліотеки, ви завжди можете логувати в явному вигляді. Запускаємо навчання. Реєструємо теги та вхідні параметри на віддаленому сервері.

Пара рядків і ви, як і всі бажаючі, маєте доступ до інформації про всі запуски. Круто?

3. Оформляємо проект

Тепер зробимо так, щоби запустити проект було простіше простого. Для цього додамо в корінь проекту файл MLproject та conda.yaml.
MLproject

name: flow_segmentation
conda_env: conda.yaml

entry_points:
  main:
    parameters:
        categories: {help: 'list of categories from coco dataset'}
        epochs: {type: int, help: 'number of epochs in training'}

        lr: {type: float, default: 0.001, help: 'learning rate'}
        batch_size: {type: int, default: 8}
        model_name: {type: str, default: 'Unet', help: 'Unet, PSPNet, Linknet, FPN'}
        backbone_name: {type: str, default: 'resnet18', help: 'exampe resnet18, resnet50, mobilenetv2 ...'}

        tracking_uri: {type: str, help: 'the server address'}
        experiment_name: {type: str, default: 'My_experiment', help: 'remote and local experiment name'}
    command: "python mlflow_training.py 
            --epochs={epochs}
            --categories={categories}
            --lr={lr}
            --tracking_uri={tracking_uri}
            --model_name={model_name}
            --backbone_name={backbone_name}
            --batch_size={batch_size}
            --experiment_name={experiment_name}"

MLflow Project має кілька властивостей:

  • Name – ім'я вашого проекту;
  • Environment - у моєму випадку conda_env вказує на те, що для запуску використовується Anaconda і опис залежностей знаходиться у файлі conda.yaml;
  • Entry Points — вказує, які файли і з якими параметрами ми можемо запустити (всі параметри при запуску навчання автоматично логуються)

conda.yaml

name: flow_segmentation
channels:
  - defaults
  - anaconda
dependencies:
  - python==3.7
  - pip:
    - mlflow==1.8.0
    - pysftp==0.2.9
    - Cython==0.29.19
    - numpy==1.18.4
    - pycocotools==2.0.0
    - requests==2.23.0
    - matplotlib==3.2.1
    - segmentation-models==1.0.1
    - Keras==2.3.1
    - imgaug==0.4.0
    - tqdm==4.46.0
    - tensorflow-gpu==1.14.0

Як середовище виконання ви можете використовувати docker, за більш детальною інформацією зверніться до документації.

4. Запускаємо навчання

Клонуємо проект і переходимо до директорії проекту:

git clone https://github.com/simbakot/mlflow_example.git
cd mlflow_example/

Для запуску необхідно встановити бібліотеки

pip install mlflow
pip install pysftp

Т.к. в прикладі я використовую conda_env на вашому комп'ютері повинна бути встановлена ​​Anaconda (але і це можна обійти встановивши всі необхідні пакети самостійно і погравшись з параметрами запуску).

Всі підготовчі кроки закінчені і ми можемо розпочати запуск навчання. З кореня проекту:

$ mlflow run -P epochs=10 -P categories=cat,dog -P tracking_uri=http://server_host:server_port .

Після введення команди автоматично створиться оточення conda і запуститься тренування.
У прикладі вище я передав кількість епох для навчання, категорії на які хочемо сегментувати (повний список можна подивитися тут) та адресу нашого віддаленого сервера.
Повний список можливих параметрів можна переглянути у файлі MLproject.

5. Оцінюємо результати навчання

Після закінчення навчання ми можемо перейти у браузері на адресу нашого сервера http://server_host:server_port

MLOps - Cook book, chapter 1

Тут ми бачимо список всіх експериментів (зліва вгорі), а також інформацію щодо запусків (посередині). Ми можемо переглянути докладнішу інформацію (параметри, метрики, артефакти та якусь додаткову інформацію) по кожному запуску.

MLOps - Cook book, chapter 1

За кожною метрикою ми можемо спостерігати історію зміни

MLOps - Cook book, chapter 1

Тобто. на даний момент ми можемо аналізувати результати в "ручному" режимі, також можна налаштувати і автоматичну валідацію за допомогою MLflow API.

6. Реєструємо модель

Після того, як ми проаналізували нашу модель і вирішили, що вона готова до бою, приступаємо до її реєстрації для цього, вибираємо потрібний нам запуск (як показано в попередньому пункті) і йдемо вниз.

MLOps - Cook book, chapter 1

Після того як ми назвали нашу модель, у неї з'являється версія. При збереженні іншої моделі з цим же ім'ям версія автоматично підвищиться.

MLOps - Cook book, chapter 1

Для кожної моделі ми можемо додати опис і вибрати один із трьох станів (Staging, Production, Archived), згодом ми за допомогою api можемо звертатися до цих станів, що поруч із версіонуванням дає додаткову гнучкість.

MLOps - Cook book, chapter 1

У нас також є зручний доступ до всіх моделей

MLOps - Cook book, chapter 1

та їх версіям

MLOps - Cook book, chapter 1

Як і в попередньому пункті, всі операції можна зробити за допомогою API.

7. Деплоїмо модель

На даному етапі ми вже маємо натреновану (keras) модель. Приклад, як її використовувати:

class SegmentationModel:
    def __init__(self, tracking_uri, model_name):

        self.registry = RemoteRegistry(tracking_uri=tracking_uri)
        self.model_name = model_name
        self.model = self.build_model(model_name)

    def get_latest_model(self, model_name):
        registered_models = self.registry.get_registered_model(model_name)
        last_model = self.registry.get_last_model(registered_models)
        local_path = self.registry.download_artifact(last_model.run_id, 'model', './')
        return local_path

    def build_model(self, model_name):
        local_path = self.get_latest_model(model_name)

        return mlflow.keras.load_model(local_path)

    def predict(self, image):
        image = self.preprocess(image)
        result = self.model.predict(image)
        return self.postprocess(result)

    def preprocess(self, image):
        image = cv2.resize(image, (256, 256))
        image = image / 255.
        image = np.expand_dims(image, 0)
        return image

    def postprocess(self, result):
        return result

Тут self.registry знову невелика обв'язка над mlflow.tracking.MlflowClient, для зручності. Суть у тому, що я звертаюся до віддаленого сервера і шукаю там модель із зазначеним ім'ям, причому останню production версію. Далі скачу артефакт локально в папку ./model і збираю модель з цієї директорії mlflow.keras.load_model(local_path). Тепер ми можемо використовувати нашу модель. CV (ML) розробники можуть спокійно займатися покращенням моделі та публікувати нові версії.

На закінчення

Я представив систему, яка дозволяє:

  • централізовано зберігати інформацію про ML моделі, хід та результати навчання;
  • швидко розгортати середовище розробки;
  • стежити та аналізувати хід роботи над моделями;
  • зручно вести версіонування та керувати станом моделей;
  • легко деплоїти отримані моделі.

Даний приклад є іграшковим і служить точкою старту для вибудовування вашої власної системи, яка, можливо, буде включати автоматизацію оцінки результатів і реєстрації моделей (п.5 і п.6 відповідно) або ви додасте версіонування датасетів, або може ще щось ? Я намагався донести думку, що вам потрібен MLOps в цілому, MLflow лише засіб досягнення мети.

Напишіть, які проблеми, з якими ви стикалися, я не відобразив?
Що б ви додали до системи, щоб вона закривала ваші потреби?
Які інструменти та підходи ви використовуєте, щоб закрити всі або частину проблем?

PS Залишу пару посилань:
github проект - https://github.com/simbakot/mlflow_example
MLflow - https://mlflow.org/
Моя робоча пошта, для запитань [захищено електронною поштою]

У нас в компанії періодично проводяться різні заходи для ІТ-фахівців, наприклад: 8-го липня о 19:00 по МСК проходитиме мітап з CV в онлайн-форматі, якщо цікаво, то можете взяти участь, реєстрація тут .

Джерело: habr.com

Додати коментар або відгук