21 KiB
Сложный пайплайн (mldev)
MLDev - программное обеспечение, упрощающее запуск воспроизводимых вычислительных экспериментов.
С помощью MLDev можно создавать более сложные вычислительные эксперименты (пайплайны) для использования на фреймворке, а также более удобно работать с обычными пайплайнами.
Принцип работы с фреймворком при помощи MLDev:
- Разработчик создаёт манифест эксперимента, аналогичный манифесту пайплайна.
- На основе манифеста эксперимента с помощью mldev автоматически генерируется манифест пайплайна и собираются docker-образы.
- Разработчик добавляет сгенерированный манифест пайплайна и docker-образы к модулю как при обычном создании пайплайна.
- Подготовка элементов mldev
- config.yaml
- stages.py
- experiment-unip-pipeline.yaml
- unip-pipeline.yaml
- MLOps-модули
Подготовка элементов mldev
В примере далее рассматривается следующая структура файлов, относящихся к MLDev.
experiments
├── .mldev
│ ├── config.yaml
│ └── stages.py
├── experiment-unip-pipeline.yaml
└── unip-pipeline.yaml
config.yaml- настройки MLDev, такие как параметры запуска, уровень логирования и шаблон названия docker-образов.stages.py- загрузка используемых компонентов MLDev с помощью выраженияimport.experiment-unip-pipeline.yaml- mldev-пайплайн сборки эксперимента, запускаемый разработчиком.unip-pipeline.yaml- основной пайплайн, используется пайплайном сборки для построения вычислительного эксперимента.
config.yaml
Пример содержимого config.yaml:
logger:
level: DEBUG
extras:
base: mldev.experiment_objects
containers: mldev_containers.containers
environ:
IMAGE_TAG_TEMPLATE: 'platform-reg.stratpro.hse.ru/myproject/${name}:${revision}'
UNIP_MLDEV_PIPELINE_OUTPUT: ./build/pipelines
EXPERIMENT_FILE: ./experiments/unip-pipeline.yaml
FORCE_RUN: True
logger.level- уровень логирования,DEBUG,INFOилиERROR.extras- дополнительные модули MLDev, необходимые для взаимодействия с фреймворком.environ- переменные окруженияIMAGE_TAG_TEMPLATE- шаблон названия образа Docker.${name}будет автоматически заменено на название этапа из файла эксперимента, а${revision}- на короткий хэш последнего коммита в репозитории проектаUNIP_MLDEV_PIPELINE_OUTPUT- путь, куда будет сохранён сгенерированный манифест пайплайна для фреймворкаEXPERIMENT_FILE- файл с вычислительным экспериментомFORCE_RUN- параметр, заставляющий MLDev собирать эксперимент заново, даже если не найдено изменений с прошлой сборки
stages.py
Пример файла stages.py:
from mldev_containers import ContainerStage, StageCode, StageVar
from unip.mldev_pipeline.unip_pipeline import UnipPipeline
from unip.mldev_pipeline.dataloader import StageSrc
UnipPipeline,StageCode,StageVar,ContainerStage- классы компонентов, необходимых для работы с пайплайнамиStageSrc- класс подключения модуля данных
Аналогично модулю данных в примере, для подключения других специализированных этапов, таких как подключение к суперкомпьютеру cHARISMa и автоматическая генерация отчёта об эксперименте, необходимо добавлять соответствующие классы в stages.py.
experiment-unip-pipeline.yaml
В этом файле определяется небольшой вычислительный эксперимент MLDev, в результате которого должен быть собран полноценный эксперимент из файла unip-pipeline.yaml.
Здесь определяются параметры запуска и переменные окружения полноценного эксперимента, а также добавляются вспомогательные команды.
Пример файла experiment-unip-pipeline.yaml
pipeline: !GenericPipeline
runs:
- !BasicStage
name: experiment
env:
PYTHONPATH: './experiments/.mldev'
MLDEV_CONFIG_PATH: './experiments/.mldev/config.yaml'
PIP_EXTRA_INDEX_URL: '${env.PIP_EXTRA_INDEX_URL}'
script:
- mkdir -p ./build/containers
- mkdir -p ./build/pipelines
- rm -rf ./build/containers/*
- rm -rf ./build/pipelines/*
- mldev run pipeline -f ./experiments/unip-pipeline.yaml
pipeline: !GenericPipeline- указывает, что это объект классаGenericPipeline- стандартный пайплайн библиотеки MLDev, не относящийся к фреймворку.runs- список этапов, которые будут выполнены в ходе выполнения пайплайна GenericPipeline!BasicStage- указывает, что текущий этап - это объект классаBasicStage, стандартного класса этапа пайплайна в MLDev.name: experiment- имя этапа. Не используется далееenv:- переменные окружения, с которыми запускается этап сборки полноценного пайплайна,PYTHONPATH- чтобы модули MLDev, импортированные в файлеstages.pyбыли загружены, нужно указать в PYTHONPATH путь к папке с этим файлом. В данном примере,./experiments/.mldevMLDEV_CONFIG_PATH- путь к используемому в полноценном эксперименте файлу настроек MLDev.PIP_EXTRA_INDEX_URL- дополнительные индексы для установки пакетов Python. Используются для установки пакетов фреймворка, которые не размещены в индексе PyPI. Значение'${env.PIP_EXTRA_INDEX_URL}'означает, что переменная окруженияPIP_EXTRA_INDEX_URLкопирует содержимое такой же переменной из среды, которая запускает эксперимент.
script= команды, которые выполяются в текущем этапеexperiment. В данном примере это создание папок./build/containersи./build/pipelines, удаление их содержимого и запуск сборки полноценного пайплайна.
unip-pipeline.yaml
Этот файл полностью описывает вычислительный эксперимент, аналогично компоненту ExperimentPipeline.
UnipPipeline
Основной объект вычислительного эксперимента, который должен быть определён в файле unip-pipeline.yaml - это объект pipeline:!UnipPipeline со следующей структурой:
pipeline: !UnipPipeline
name: my-project
namespace: pu-username-pa-appname
variables:
- name: preparation_data
- name: internal_state
- name: user_report
runs:
- *container_stage_prepare
- *container_stage_complete
connected_boxes:
- name: user-box
path: /userdata/
default: true
mount_s3_box:
s3_box_name: users
name: my-project- имя, которое будет использовано далее при генерации имени компонентаExperimentPipeline.namespace- пространство имён приложения, аналогично с остальными манифестами компонентов.variables- список переменных, которые используются во всех этапах, вместе взятых. АналогичноExperimentPipeline. Для каждой переменной помимо поляnameможно указать поляpath(точка монтирования в контейнере) иmountFrom(DataBox и точка монтирования в хранилище S3).runs- список этапов пайплайна. В примере - ссылки на отдельно определённые компоненты.connected_boxes- раздел, полностью аналогичный такому же разделу вExperimentPipeline- определение связанных компонентовDataBox, указание пути монтирования по умолчанию и внутреннего имени DataBox, которое используется в этом файле далее. В отличие отExperimentPipeline, где используется camelCase, здесь используется snake_case.
ContainerStage
Отдельный этап пайплайна UnipPipeline - это ContainerStage. Такой этап соответствует этапу ExperimentPipeline.
container_stage_prepare: !ContainerStage &container_stage_prepare
name: my-prepare
base_image: platform-reg.stratpro.hse.ru/my_org/myproject-prepare:718e2b0
stage: *stage_prepare
build:
<<: *build
code: *code
env:
MY_CUSTOM_FLAG: "True"
resource_limits:
cpu: "1"
memory: 500M
container_stage_prepare: !ContainerStage &container_stage_prepare:container_stage_prepare:- корень объекта этапа!ContainerStage- класс, на основе которого будет создан этап&container_stage_prepare- имя, по которому на этот этап можно ссылаться. Это имя используется вUnipPipeline
my-prepare- название этапа. Используется как название этапа вExperimentPipelineи в названии Docker-образаbase_image- образ Docker, на основе которого будет создан этап. Это может быть как стандартный образ видаpython:3.11.10-slim-bullseye, так и образ, загруженный в реестр фреймворка видаplatform-reg.stratpro.hse.ru/my_org/myproject-prepare:718e2b0.stage: *stage_prepare- объект видаBasicStage, в котором определяются входные, выходные данные и точка входа, запускающая вычисления.build- параметры сборки Docker-образа, здесь определяются отдельным объектом.code- объект типаStageCode, который определяет устанавливаемые черезrequirements.txtзависимости, а также файл с исходным кодом проекта, добавляемые в контейнер.env- набор произвольных переменных окружения, которые будут установлены при запуске контейнера.resource_limits- лимиты ресурсов в терминах Kubernetes, аналогичноExperimentPipeline.
build
В данном определении используется несколько ссылок на внешние объекты. Объект build имеет структуру
build_params: &build
root: .
output: build/containers
Это означает, что корнем сборки Docker-контейнера выступает корень репозитория, а сгенерированные скрипты сборки и Dockerfile-ы появятся в папке build/containers в репозитории.
code
Объект StageCode имеет структуру
code: !StageCode &code
requirements: ./requirements.txt
src:
- ./myproject/
- ./my_static_config.json
- ./.mldev/
- ./experiments/unip-pipeline-paper.yaml
- Это объект типа
StageCode, на который далее можно ссылаться по имениcode. requirements- файл с зависимостями, который будет скопировать в контейнер и использован для установки зависимостейsrc- список файлов или папок, которые будут скопированы в рабочую директорию контейнера. По умолчанию это/unip.
Объект StageCode предполагает единый проект, даже если в его рамках запускаются разные файлы. Если несколько контейнеров объединяются в один пайплайн с разными StageCode, то в результате сгенерируется несколько объектов ExperimentPipeline, составляющих цепочку запуска.
BasicStage
Объект BasicStage определяет входные, выходные данные этапа пайплайна, а также точку входа.
stage_prepare: !BasicStage &stage_prepare
name: stage_prepare
inputs:
- !StageVar
name: preparation_data
path: ./data/preparation
outputs:
- !StageVar
name: internal_state
script:
- python src/prepare.py
stage_prepare: !BasicStage &stage_prepare- аналогично предыдущим компонентам, объектstage_prepareклассаBasicStage, на который можно ссылаться какstage_prepare.name- название этапаinputs- список входных переменных!StageVar- переменная типаStageVar. Это обычный тип переменных по умолчанию, аналогичный переменнымExperimentPipeline.name- название переменной, используется далее в пайплайне и в контейнере.path- путь монтирования переменной внутри контейнера. Если передан относительный путь, он рассчитывается от рабочей директории контейнера -/unip.
outputs- аналогичноinputsscript- точка входа в этап эксперимента.- При этом точкой входа в контейнер будет команда MLDev
mldev run stage_prepare -f /unip/experiments/unip-pipeline.yaml, а уже запущенный ей процесс выполнит команду из поляscript.
- При этом точкой входа в контейнер будет команда MLDev
Сборка пайплайна
Запуск сборки
Чтобы запустить сборку пайплайна нужно выполнить следующие условия:
- В
PATHдоступна командаmldev. Например, в используемой виртуальной среде установлен пакет Pythonmldev. - В переменной окружения
PIP_EXTRA_INDEX_URLуказаны ссылки на используемые реестры пакетов Python фреймворка с указанием рекизитов.
Дополнительные индексы пакетов Python указываются в формате
export PIP_EXTRA_INDEX_URL="https://my_username:mypassword_or_token_abcdef1234@platform-forgejo.stratpro.hse.ru/api/packages/MY_ORG/pypi/simple https://my_username:mypassword_or_token_abcdef1234@platform-forgejo.stratpro.hse.ru/api/packages/ANOTHER_ORG/pypi/simple"
Общий набор команд для сборки эксперимента mldev может быть примерно такой:
cd /home/my_username/MLOPS/my_project/
export PIP_EXTRA_INDEX_URL="https://my_username:mypassword_or_token_abcdef1234@platform-forgejo.stratpro.hse.ru/api/packages/MY_ORG/pypi/simple https://my_username:mypassword_or_token_abcdef1234@platform-forgejo.stratpro.hse.ru/api/packages/ANOTHER_ORG/pypi/simple"
source venv/bin/activate
mldev run -f experiments/experiment-unip-pipeline-paper.yaml
После завершения сборки в корневой папке проекта должна появиться следующая структура:
/build
├── containers
│ ├── my-complete.dockerfile
│ ├── my-complete.dockerignore
│ ├── my-complete.sh
│ ├── my-prepare.dockerfile
│ ├── my-prepare.dockerignore
│ └── my-prepare.sh
└── pipelines
└── my-project-qzv828.yaml
Здесь в containers хранятся файлы, используемые для сборки контейнеров отдельных этапов, а в pipelines - сгенерированный манифест ExperimentPipeline. Сами собранные образы этапов должны быть доступны в Docker, например, видны в команде docker images.
Подключение к базовому модулю
Чтобы подключить сгенерированный манифест ExperimentPipeline к фреймворку, следует его переименовать, изменить в содержимом манифеста поле name на желаемое название пайплайна и поместить манифест в папку app в репозитории.
Компонент APIComponent не генерируется при сборке пайплайна MLDev, его нужно создать вручную.
Собранные образы Docker нужно загрузить в репозиторий образов в Harbor.
Разделение на несколько пайплайнов
ExperimentPipeline поддерживает последовательный запуск нескольких пайплайнов - подробнее здесь.
Во время сборки эксперимента через MLDev этапы с разными объектами StageCode считаются достаточно сильно отличными друг от друга. Такие этапы разделяются в отдельные объекты ExperimentPipeline и связываются через continueWith.
MLOps-модули
MLOps-модули фреймворка и некоторые другие дополнительные возможности работают за счёт замены стандартных классов ContainerStage, BasicStage и StageVar на свои варианты.
Например:
CharismaStageвместоContainerStageпозволяет отправить вычислительную задачу на суперкомпьютер cHARISMa.StageSrcвместоStageVarпозволяет использовать данные из модуля данных.ReportвместоBasicStageпозволяет сгенерировать отчёт о проведённом вычислительном эксперименте.