Перейти к содержанию

Быстрый старт

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

mmf-meta

Для начала работы вам необходимо установить библиотеку mmf-meta:

pip install mmf-meta

mmf

Импортируем библиотеку mmf_meta, для простоты присвоим ей более короткое название - mmf

import mmf_meta as mmf
import pandas as pd
import pickle

with open('model', 'br') as f:
    model = pickle.load(f) # (1) 

  1. Модель может загружаться как угодно, в этом примере используется pickle

artifact

Чтобы сообщить mmf, что файл model - это артефакт, его нужно отметить специальным образом. В таком случае в MMF появится возможность управления артефактами: загрузка, хранение, контроль версий.

Есть два способа работы с артефактами:

Если артефакт относительно небольшой, его можно разместить "рядом" с исходным кодом. Под небольшим мы понимаем файл размером до 10мб. Большие размеры будут замедлять загрузку информации о модели, поэтому нужно использовать второй способ.

mmf.artifact('model') # (1)

with open('model', 'br') as f:
    model = pickle.load(f)
  1. Помечаем файл 'model' как артефакт

Альтернативный способ (на одну строку меньше, смысл не меняется)

with mmf.artifact('model', 'br') as f: # (1)
    model = pickle.load(f)

  1. with mmf.artifact полностью заменяет with open без потери функционала.

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

@mmf.artifact('model') # (1)
def model(): # (2)
    with open('model', 'br') as f:
        return pickle.load(f) # (3) 
  1. Декоратор, помечающий функцию как загрузчик модели
  2. Функция, которая отвечает за загрузку модели
  3. Важно, модель теперь не записывается в переменную, а возвращается как результат работы функции model()

Внимание!

mmf.artifact проверит размер файла и если он превысит установленный лимит (10мб), поднимется ошибка и модель не будет загружена. В таком случае нужно использовать второй вариант - хранение артефакта в хранилище.

target

Далее нам предстоит оформить "target" - это функция, которую мы хотим предоставить внешним пользователям.

MMF поддерживает работу с табличными данными. Автоматически преобразует поддерживаемые типы в DataFrame.

@mmf.target(returns=mmf.DataFrame(format=mmf.XLSX)) # (1)
def score(
    data = mmf.DataFrame(description='Данные для модели') # (2)
):
    return model.predict(data) # (3)
  1. Декоратор, помечающий функцию как target. Если функция возвращает какой-то результат, тип результата нужно пометить с помощью параметра returns, в данном примере модель возвращает DataFrame, при этом MMF преобразует его в формат .XLSX перед отправкой пользователю.
  2. Дескриптор, помогающий MMF понять, какие данные ожидаются от пользователя. Подробнее про дескрипторы
  3. Вызов модели. Независимо от того, как был оформлен артефакт model, для таргета - это всегда один и тот же объект, те в нашем примере - результат работы pickle.load

Работа с данными в формате объектов (python dict). MMF может принимать от пользователя json, xml, protobuf и автоматически преобразовывать их в dict.

@mmf.target(returns=mmf.Dict(format=mmf.JSON)) # (1)
def score(
    data = mmf.Dict(description='Данные для модели в формате JSON') # (2)
):
    return model.predict(data)
  1. В данном случае мы сообщаем MMF, что модель возвращает данные как dict и просим MMF по-умолчанию конвертировать его в JSON.
  2. Дескриптор, указывающий на использование данных в формате dict. MMF автоматически распакует json-совместимый объект, полученный от клиента. Для распаковки используется высокопроизводительная библиотека orjson

MMF способен работать с любыми данными, в том числе смешивать разные типы. На примере работы с изображением:

@mmf.target(returns=mmf.String()) # (1)
def score(
    img = mmf.Img( # (2)
        format='rgb', 
        description='Файл изображения, совместимый с opencv'
    ), 
    model_id = mmf.String( # (3)
        description='ID модели, которую нужно использовать для классификации'
    ),
):
    return model[model_id].predict(data) # (4)
  1. Сообщаем, что модель возвращает строку
  2. На вход ожидаем изображение. При этом MMF автоматически преобразует его в numpy-массив, в данном случае в формате rgb.
  3. Дополнительный параметр - id модели, в этом вымышленном сценарии у нас есть несколько моделей, которые могут классифицировать изображение
  4. Модель возвращает рассчитанный класс как текст.

Модель может содержать любое кол-во таргетов, входные/выходные параметры можно комбинировать как угодно, в любом порядке/количестве и с любыми поддерживаемыми типами

Внимание!

Все аргументы таргета в обязательном порядке должны содержать дескрипторы, в противном случае модель не будет загружена с ошибкой DescriptorError

результат

В результате мы получим примерно такой файл с описанием модели, назовем его main.py:

import mmf_meta as mmf
import pandas as pd
import pickle

with mmf.artifact('model', 'br') as f:
    model = pickle.load(f)

@mmf.target(returns=mmf.DataFrame(format=mmf.XLSX))
def score(
    data = mmf.DataFrame(description='Данные для модели')
):
    return model.predict(data)

Другой пример на github

requirements.txt

Для указания зависимостей проекта используется pip-совместимый файл requirements. Общая рекомендация к этому файлу - указание списка основных зависимостей со строгим указанием версий. Рекомендуется фиксировать все установленные во время разработки зависимости, чтобы поведение модели воспроизводилось гарантированно без ошибок и отклонений.

pandas==1.2.0
scikit-learn==0.23.1

poetry - современенный, набирающий популярность, инструмент для управления зависимостями python. Основное "удобство" от использования poetry - это фиксация версий основных зависимостей и так же связанных ними непосредственно в моменте установки.

C poetry привычная установка pip install pandas заменяется на poetry add pandas, что в последствии дает строгую фиксацию всех зависимостей в файле poetry.lock

Для конвертации в requirements.txt в poetry есть встроенный функционал:

poetry export -f requirements.txt

Если вы пользуетесь pip для установки пакетов, pip-tools может помочь зафиксировать все установленные версии зависимостей.

Для этого нужно сначала заполнить файл requirements.in без указания версий

pandas
scikit-learn
И далее запустить встроенную функцию для компиляции в requirements.txt:
pip-compile requirements.in > requirements.txt

test

Перед деплоем рекомендуется протестировать проект, чтобы убедиться, что все сделано правильно. Для этого можно воспользоваться встроенным скриптом:

mmfmeta test main.py # (1)

  1. main.py - файл, в котором описан проект

Указанный скрипт создаст виртуальное окружение, установит в него mmf-meta, и все зависимости, указанные в requirements.txt и запустит команду mmfmeta get-meta main, которая создаст файл mmf.json с подробным описанием проекта. После чего виртуальное окружение будет удалено.

deploy

И теперь настало время развернуть модель в MMF. Для этого вам нужно сначала разместить исходный код в любой привычной git-системе, например на github. Если этот процесс вызывает какие-то трудности, есть так же опция - упаковать все в архив.

Далее перейти в интерфейс вашего кластера MMF, либо на демо-кластер. Нажать кнопку новый проект и следовать дальнейшим инструкциям.