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
|
||||
code: *code
|
||||
resource_limits:
|
||||
time: 0-01:00:00 # ЧЧ:ММ:СС
|
||||
time: 0-01:00:00 # Д-ЧЧ:ММ:СС
|
||||
nodes: 1
|
||||
cpus: 4
|
||||
gpus: 1
|
||||
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
|
||||
sif_input: charisma_sif
|
||||
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-пайплайна
|
||||
|
@ -123,8 +140,24 @@ environ:
|
|||
- Для доступа к пайплайну нужен соответствующий 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-образы.
|
||||
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.
|
||||
|
||||
|
@ -107,23 +121,6 @@ pipeline: !GenericPipeline
|
|||
- `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
|
||||
|
||||
Этот файл полностью описывает вычислительный эксперимент, аналогично компоненту `ExperimentPipeline`.
|
||||
|
@ -203,7 +200,7 @@ build_params: &build
|
|||
|
||||
#### code
|
||||
|
||||
Объект `code` имеет структуру
|
||||
Объект `StageCode` имеет структуру
|
||||
|
||||
```yaml
|
||||
code: !StageCode &code
|
||||
|
@ -249,7 +246,63 @@ stage_prepare: !BasicStage &stage_prepare
|
|||
- `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` на свои варианты.
|
||||
|
||||
|
|
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