mldev, харизма, связанные пайплайны
This commit is contained in:
parent
f873584c15
commit
8ccdaa87c3
3 changed files with 281 additions and 24 deletions
|
@ -90,17 +90,34 @@ my_container_stage: !ContainerStage &my_container_stage
|
||||||
<<: *build
|
<<: *build
|
||||||
code: *code
|
code: *code
|
||||||
resource_limits:
|
resource_limits:
|
||||||
time: 0-01:00:00 # ЧЧ:ММ:СС
|
time: 0-01:00:00 # Д-ЧЧ:ММ:СС
|
||||||
nodes: 1
|
nodes: 1
|
||||||
cpus: 4
|
cpus: 4
|
||||||
gpus: 1
|
gpus: 1
|
||||||
node_type: type_a # или type_b, type_c, ...
|
node_type: type_a # или type_b, type_c, ...
|
||||||
|
|
||||||
|
|
||||||
my_charisma_stage: !CharismaStage &charisma_stage_train
|
my_charisma_stage: !CharismaStage &my_charisma_stage
|
||||||
name: my-charisma-stage
|
name: my-charisma-stage
|
||||||
sif_input: charisma_sif
|
sif_input: charisma_sif
|
||||||
stage: *my_container_stage
|
stage: *my_container_stage
|
||||||
|
|
||||||
|
|
||||||
|
pipeline: !UnipPipeline
|
||||||
|
name: my-project
|
||||||
|
namespace: pu-username-pa-appname
|
||||||
|
variables:
|
||||||
|
- name: my_data
|
||||||
|
- name: my_result
|
||||||
|
- name: charisma_sif
|
||||||
|
runs:
|
||||||
|
- *my_charisma_stage
|
||||||
|
connected_boxes:
|
||||||
|
- name: user-box
|
||||||
|
path: /userdata/
|
||||||
|
default: true
|
||||||
|
mount_s3_box:
|
||||||
|
s3_box_name: users
|
||||||
```
|
```
|
||||||
|
|
||||||
## Сборка MLDev-пайплайна
|
## Сборка MLDev-пайплайна
|
||||||
|
@ -123,8 +140,24 @@ environ:
|
||||||
- Для доступа к пайплайну нужен соответствующий API-компонент. При создании API-компонента в пространстве имён приложения также создаются несколько объектов Secret с разными видами реквизитов. Их имена генерируются автоматически на основе имени API-компонента.
|
- Для доступа к пайплайну нужен соответствующий API-компонент. При создании API-компонента в пространстве имён приложения также создаются несколько объектов Secret с разными видами реквизитов. Их имена генерируются автоматически на основе имени API-компонента.
|
||||||
|
|
||||||
|
|
||||||
После этого сборку можно начать такой же командой, как для обычного MLDev эксперимента: `mldev run -f experiments/experiment-unip-pipeline.yaml`
|
После этого сборку можно начать такой же командой, как для обычного MLDev эксперимента: `mldev run -f experiments/experiment-unip-pipeline.yaml`. Сборка SIF-образа может занимать много вычислительных ресурсов и оперативной памяти.
|
||||||
|
|
||||||
Сборка SIF-образа может занимать много вычислительных ресурсов и оперативной памяти.
|
После завершения сборки в корневой папке проекта должна появиться следующая структура:
|
||||||
|
|
||||||
|
```
|
||||||
|
/build
|
||||||
|
├── containers
|
||||||
|
│ ├── my-charisma-stage.dockerfile
|
||||||
|
│ ├── my-charisma-stage.dockerignore
|
||||||
|
│ └── my-charisma-stage.sh
|
||||||
|
├── pipelines
|
||||||
|
│ └── my-project-qzv828.yaml
|
||||||
|
└── sif
|
||||||
|
└── platform-reg.stratpro.hse.ru_my_lab_my-stage_0d00739.sif
|
||||||
|
```
|
||||||
|
|
||||||
|
Как и для обычного MLDev-пайплайна, создаются наборы файлов сборки контейнеров для каждого этапа в `build/containers/` и сгенерированный манифест `ExperimentPipeline` в `build/pipelines/`.
|
||||||
|
|
||||||
|
Помимо этого, собранный SIF-контейнер помещается в `build/sif/`.
|
||||||
|
|
||||||
|
Если в пайплайне предполагается несколько этапов, например, "обучить модель на суперкомпьютере, а затем построить отчёт о результатах обучения на обычных вычислительных ресурсах фреймворка", пайплайн будет разбит на [несколько частей](./split-pipeline.md). Этап с `CharismaStage` будет выделен в одну часть, а остальные этапы - в другую.
|
||||||
|
|
|
@ -10,7 +10,21 @@
|
||||||
2. На основе манифеста эксперимента с помощью mldev автоматически генерируется манифест пайплайна и собираются docker-образы.
|
2. На основе манифеста эксперимента с помощью mldev автоматически генерируется манифест пайплайна и собираются docker-образы.
|
||||||
3. Разработчик добавляет сгенерированный манифест пайплайна и docker-образы к модулю как при обычном создании пайплайна.
|
3. Разработчик добавляет сгенерированный манифест пайплайна и docker-образы к модулю как при обычном создании пайплайна.
|
||||||
|
|
||||||
## Подготовка элементов mldev
|
|
||||||
|
- [Подготовка элементов 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.
|
В примере далее рассматривается следующая структура файлов, относящихся к MLDev.
|
||||||
|
|
||||||
|
@ -107,23 +121,6 @@ pipeline: !GenericPipeline
|
||||||
- `script` = команды, которые выполяются в текущем этапе `experiment`. В данном примере это создание папок `./build/containers` и `./build/pipelines`, удаление их содержимого и запуск сборки полноценного пайплайна.
|
- `script` = команды, которые выполяются в текущем этапе `experiment`. В данном примере это создание папок `./build/containers` и `./build/pipelines`, удаление их содержимого и запуск сборки полноценного пайплайна.
|
||||||
|
|
||||||
|
|
||||||
Подробнее про переменную окружения `PIP_EXTRA_INDEX_URL` и запуск сборки.
|
|
||||||
|
|
||||||
Дополнительные индексы пакетов 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## unip-pipeline.yaml
|
## unip-pipeline.yaml
|
||||||
|
|
||||||
Этот файл полностью описывает вычислительный эксперимент, аналогично компоненту `ExperimentPipeline`.
|
Этот файл полностью описывает вычислительный эксперимент, аналогично компоненту `ExperimentPipeline`.
|
||||||
|
@ -203,7 +200,7 @@ build_params: &build
|
||||||
|
|
||||||
#### code
|
#### code
|
||||||
|
|
||||||
Объект `code` имеет структуру
|
Объект `StageCode` имеет структуру
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
code: !StageCode &code
|
code: !StageCode &code
|
||||||
|
@ -249,7 +246,63 @@ stage_prepare: !BasicStage &stage_prepare
|
||||||
- `script` - точка входа в этап эксперимента.
|
- `script` - точка входа в этап эксперимента.
|
||||||
- При этом точкой входа в контейнер будет команда MLDev `mldev run stage_prepare -f /unip/experiments/unip-pipeline.yaml`, а уже запущенный ей процесс выполнит команду из поля `script`.
|
- При этом точкой входа в контейнер будет команда MLDev `mldev run stage_prepare -f /unip/experiments/unip-pipeline.yaml`, а уже запущенный ей процесс выполнит команду из поля `script`.
|
||||||
|
|
||||||
## MLOps-модули
|
# Сборка пайплайна
|
||||||
|
|
||||||
|
## Запуск сборки
|
||||||
|
|
||||||
|
Чтобы запустить сборку пайплайна нужно выполнить следующие условия:
|
||||||
|
|
||||||
|
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` на свои варианты.
|
MLOps-модули фреймворка и некоторые другие дополнительные возможности работают за счёт замены стандартных классов `ContainerStage`, `BasicStage` и `StageVar` на свои варианты.
|
||||||
|
|
||||||
|
|
171
pages/split-pipeline.md
Normal file
171
pages/split-pipeline.md
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
# Последовательный запуск пайплайнов
|
||||||
|
|
||||||
|
Несколько компонентов `ExperimentPipeline` возможно соединить друг с другом в последовательную серию запусков, где запуск первого пайплайна предполагает последовательный запуск второго.
|
||||||
|
|
||||||
|
Если два пайплайна связаны таким образом, у пользователя появляется два варианта запуска:
|
||||||
|
|
||||||
|
- Запустить цепочку из первого и второго пайплайна вместе
|
||||||
|
- Запустить только второй пайплайн
|
||||||
|
|
||||||
|
Для соединения двух пайплайнов необходимо:
|
||||||
|
|
||||||
|
1. Добавить в манифест `ExperimentPipeline` первого пайплайна пункт `continueWith`.
|
||||||
|
2. Создать совмещённый `APIComponent` запуска цепочки, который будет соответствовать запуску первого пайплайна.
|
||||||
|
|
||||||
|
При этом второй пайплайн создаётся обычным способом, и может запускаться отдельно от цепочки.
|
||||||
|
|
||||||
|
## Пример ExperimentPipeline
|
||||||
|
|
||||||
|
Например, в модуле есть два пайплайна. Пайплайн `part-1` содержит этап обучения модели машинного обучения. Пайплайн `part-2` содержит этап построения отчёта по обученной модели.
|
||||||
|
|
||||||
|
Первый пайплайн:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: "unified-platform.cs.hse.ru/v1"
|
||||||
|
kind: ExperimentPipeline
|
||||||
|
metadata:
|
||||||
|
name: part-1
|
||||||
|
namespace: pu-username-pa-appname
|
||||||
|
spec:
|
||||||
|
vars:
|
||||||
|
- name: data
|
||||||
|
- name: model
|
||||||
|
stages:
|
||||||
|
- name: train
|
||||||
|
image:
|
||||||
|
existingImageName: platform-reg.stratpro.hse.ru/my_org/myproject-train:718e2b0
|
||||||
|
inputs:
|
||||||
|
- name: data
|
||||||
|
outputs:
|
||||||
|
- name: model
|
||||||
|
entryPoint:
|
||||||
|
cmd:
|
||||||
|
- python
|
||||||
|
- main.py
|
||||||
|
resourceLimits:
|
||||||
|
cpu: "500m"
|
||||||
|
memory: "512M"
|
||||||
|
connectedBoxes:
|
||||||
|
- name: user-box
|
||||||
|
path: /userdata/
|
||||||
|
default: true
|
||||||
|
mountS3Box:
|
||||||
|
s3BoxName: users
|
||||||
|
continueWith:
|
||||||
|
name: part-2
|
||||||
|
```
|
||||||
|
|
||||||
|
Второй пайплайн:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: "unified-platform.cs.hse.ru/v1"
|
||||||
|
kind: ExperimentPipeline
|
||||||
|
metadata:
|
||||||
|
name: part-2
|
||||||
|
namespace: pu-username-pa-appname
|
||||||
|
spec:
|
||||||
|
vars:
|
||||||
|
- name: report_document
|
||||||
|
- name: trained_model
|
||||||
|
stages:
|
||||||
|
- name: report
|
||||||
|
image:
|
||||||
|
existingImageName: platform-reg.stratpro.hse.ru/my_org/myproject-report:718e2b0
|
||||||
|
inputs:
|
||||||
|
- name: trained_model
|
||||||
|
outputs:
|
||||||
|
- name: report_document
|
||||||
|
resourceLimits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: "2G"
|
||||||
|
connectedBoxes:
|
||||||
|
- name: user-box
|
||||||
|
path: /userdata/
|
||||||
|
default: true
|
||||||
|
mountS3Box:
|
||||||
|
s3BoxName: users
|
||||||
|
```
|
||||||
|
|
||||||
|
Пункт `continueWith` в первом пайплайне указывает, что после завершения работы первого пайплайна автоматически вызывается второй.
|
||||||
|
|
||||||
|
## Пример APIComponent
|
||||||
|
|
||||||
|
Для запуска пайплайна нужно передать все входные данные в запросе. Но если второй пайплайн вызывается сам автоматически, то нет запроса на его вызов. Поэтому все входные данные для всех пайплайнов цепочки должны быть переданы в изначальном запросе запуска первого пайплайна.
|
||||||
|
|
||||||
|
Сначала, пример `APIComponent` второго пайплайна:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: "unified-platform.cs.hse.ru/v1"
|
||||||
|
kind: APIComponent
|
||||||
|
metadata:
|
||||||
|
name: api-part-2
|
||||||
|
namespace: pu-username-pa-appname
|
||||||
|
spec:
|
||||||
|
published: true
|
||||||
|
experimentPipeline:
|
||||||
|
name: part-2
|
||||||
|
restfulApi:
|
||||||
|
auth:
|
||||||
|
basic:
|
||||||
|
credentials: appname-apis-cred
|
||||||
|
identityPassThrough: true
|
||||||
|
apiSpec:
|
||||||
|
inputs:
|
||||||
|
- name: trained_model
|
||||||
|
type:
|
||||||
|
datatypes: [ "FILE" ]
|
||||||
|
contentTypes: [ "pth" ]
|
||||||
|
outputs:
|
||||||
|
- name: report_document
|
||||||
|
type:
|
||||||
|
datatypes: [ "FILE" ]
|
||||||
|
contentTypes: [ "text/html" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
Для второго пайплайна `APIComponent` создаётся как для обычного независимого пайплайна и содержит данные, которые пользователь передаёт на вход и получает на выход.
|
||||||
|
|
||||||
|
`APIComponent` первого пайплайна содержит данные как для себя, так и для второго пайплайна:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: "unified-platform.cs.hse.ru/v1"
|
||||||
|
kind: APIComponent
|
||||||
|
metadata:
|
||||||
|
name: api-part-1
|
||||||
|
namespace: pu-username-pa-appname
|
||||||
|
spec:
|
||||||
|
published: true
|
||||||
|
experimentPipeline:
|
||||||
|
name: part-1
|
||||||
|
restfulApi:
|
||||||
|
auth:
|
||||||
|
basic:
|
||||||
|
credentials: appname-apis-cred
|
||||||
|
identityPassThrough: true
|
||||||
|
apiSpec:
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
- name: data
|
||||||
|
description: "Набор данных для обучения."
|
||||||
|
type:
|
||||||
|
datatypes: [ "FILE" ]
|
||||||
|
contentTypes: [ "text/csv" ]
|
||||||
|
- name: trained_model
|
||||||
|
description: "Готовая модель и её конфигурация."
|
||||||
|
type:
|
||||||
|
datatypes: [ "FILE" ]
|
||||||
|
contentTypes: [ "pth" ]
|
||||||
|
outputs:
|
||||||
|
- name: model
|
||||||
|
description: "Готовая модель и её конфигурация."
|
||||||
|
type:
|
||||||
|
datatypes: [ "FILE" ]
|
||||||
|
contentTypes: [ "pth" ]
|
||||||
|
- name: report_document
|
||||||
|
type:
|
||||||
|
datatypes: [ "FILE" ]
|
||||||
|
contentTypes: [ "text/html" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
Здесь `trained_model` и `report_document` - это переменные второго пайплайна, которые не входят в первый. При получении запроса на запуск, фреймворк анализирует, какую последовательность пайплайнов нужно запустить, и отделяет переменные из `APIComponent` второго пайплайна от общего списка переменных.
|
||||||
|
|
||||||
|
На практике, если нужно передать данные из первого пайплайна во второй, для этого нужно создать две переменные с разными именами, и в запросе на запуск передать в них один и тот же путь. Тогда первый пайплайн запишет по этому пути выходные данные, а второй сможет их прочитать. В примере выше такими переменными являются `model` и `trained_model`.
|
Loading…
Reference in a new issue