documentation/pages/complex-pipeline.md

313 lines
21 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Сложный пайплайн (mldev)
[MLDev](https://gitlab.com/mlrep/mldev) - программное обеспечение, упрощающее запуск воспроизводимых вычислительных экспериментов.
С помощью MLDev можно создавать более сложные вычислительные эксперименты (пайплайны) для использования на фреймворке, а также более удобно работать с обычными пайплайнами.
Принцип работы с фреймворком при помощи MLDev:
1. Разработчик создаёт манифест эксперимента, аналогичный манифесту пайплайна.
2. На основе манифеста эксперимента с помощью mldev автоматически генерируется манифест пайплайна и собираются docker-образы.
3. Разработчик добавляет сгенерированный манифест пайплайна и docker-образы к модулю как при обычном создании пайплайна.
- [Подготовка элементов mldev](#подготовка-элементов-mldev)
- [config.yaml](#configyaml)
- [stages.py](#stagespy)
- [experiment-unip-pipeline.yaml](#experiment-unip-pipelineyaml)
- [unip-pipeline.yaml](#unip-pipelineyaml)
- [UnipPipeline](#unippipeline)
- [ContainerStage](#containerstage)
- [build](#build)
- [code](#code)
- [BasicStage](#basicstage)
- [MLOps-модули](#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`:
```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`:
```python
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`
```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/.mldev`
- `MLDEV_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` со следующей структурой:
```yaml
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`.
```yaml
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` имеет структуру
```yaml
build_params: &build
root: .
output: build/containers
```
Это означает, что корнем сборки Docker-контейнера выступает корень репозитория, а сгенерированные скрипты сборки и Dockerfile-ы появятся в папке `build/containers` в репозитории.
#### code
Объект `StageCode` имеет структуру
```yaml
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` определяет входные, выходные данные этапа пайплайна, а также точку входа.
```yaml
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` - аналогично `inputs`
- `script` - точка входа в этап эксперимента.
- При этом точкой входа в контейнер будет команда MLDev `mldev run stage_prepare -f /unip/experiments/unip-pipeline.yaml`, а уже запущенный ей процесс выполнит команду из поля `script`.
# Сборка пайплайна
## Запуск сборки
Чтобы запустить сборку пайплайна нужно выполнить следующие условия:
1. В `PATH` доступна команда `mldev`. Например, в используемой виртуальной среде установлен пакет Python `mldev`.
2. В переменной окружения `PIP_EXTRA_INDEX_URL` указаны ссылки на используемые реестры пакетов Python фреймворка с указанием рекизитов.
Дополнительные индексы пакетов Python указываются в формате
```sh
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 может быть примерно такой:
```sh
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` поддерживает последовательный запуск нескольких пайплайнов - [подробнее здесь](./split-pipeline.md).
Во время сборки эксперимента через MLDev этапы с разными объектами `StageCode` считаются достаточно сильно отличными друг от друга. Такие этапы разделяются в отдельные объекты `ExperimentPipeline` и связываются через `continueWith`.
# MLOps-модули
MLOps-модули фреймворка и некоторые другие дополнительные возможности работают за счёт замены стандартных классов `ContainerStage`, `BasicStage` и `StageVar` на свои варианты.
Например:
- `CharismaStage` вместо `ContainerStage` позволяет отправить вычислительную задачу на суперкомпьютер cHARISMa.
- `StageSrc` вместо `StageVar` позволяет использовать данные из модуля данных.
- `Report` вместо `BasicStage` позволяет сгенерировать отчёт о проведённом вычислительном эксперименте.