Запустить процесс обучения

Модели можно обучать следующими способами:

  • Напрямую из Jupyter Server на выделенных GPU.

  • С помощью функции client_lib, отправляя задачи на исполнение в регион.

  • С помощью public API.

  • С помощью пайплайнов.

В этой инструкции описано, как подготовиться к обучению (шаг 1), и подробно рассмотрено два из перечисленных выше способа обучения: из Jupyter Server и при помощи функции client_lib (шаг 2).

Особенности обучения из Jupyter Server и с помощью client_lib

Особенность

Обучение из Jupyter Server на выделенных GPU

Обучение через client_lib

Количество GPU

Максимальное количество выделенных GPU — 16 (для Christofari.V100), 8 (для Christofari.A100 и Cloud.Region.A100 (GPU Tesla A100)). Подробнее см. Характеристики регионов.

Можно задействовать несколько GPU. Подробнее см. Обучение моделей на большом количестве GPU.

Реализация обучения

Не нужно использовать команды client_lib и реализовывать распределенные вычисления в коде. Вместо этого исполнение можно исполнять каждую ячейку Jupyter Notebook по отдельности.

Необходимо реализовать распределенные вычисления при помощи библиотек Horovod/dask/blink/PyTorch.distributed.

Тарификация

Оплата взимается с момента создания Jupyter Server до его удаления, даже если он не используется.

Оплата происходит за фактическое время исполнения задачи: от старта до окончания обучения.

Шаг 1. Выполните подготовку к обучению

  1. Создайте Jupyter Server или подключитесь к уже существующему.

  2. Выберите среду для обучения модели: Jupyter Notebook или JupyterLab.

    JupyterLab существенно обогащает возможности классического Jupyter Notebook, поскольку поддерживает работу одновременно с несколькими ноутбуками, текстовыми файлами, датасетами, терминалами и позволяет упорядочить документы в рабочей области.

  3. Перенесите данные и скрипты для обучения из объектного хранилища S3 в локальное хранилище NFS требуемого региона. См. Переместить данные между S3 и NFS.

Шаг 2. Обучите модель одним из способов

Способ 1. Обучение из Jupyter Server с GPU

  1. Перейдите в созданную на шаге 1 среду для обучения.

  2. Установите необходимые библиотеки, если в базовых образах нет нужных вам зависимостей.

    Если для работы необходимо установить дополнительные модули Python или обновить существующие, выполните следующий код:

    pip install --user <package_name> == <version>
    

    Где:

    • package_name — наименование модуля, который предполагается установить;

    • version — версия устанавливаемого модуля.

    Подробнее об использовании pipв документации менеджера пакетов.

    Подсказка

    Если необходимы более новые версии Python и CUDA, создайте нужное окружение с помощью CLI-утилиты ML Space.

  3. Запустите обучение модели.

    Для запуска используйте образ, в котором версия tensorflow выше 2.0.0, например jupyter-cuda11.0-tf2.4.0-pt1.7.1-gpu:0.0.82-1.

    Пример обучения модели из Jupyter Server c GPU приведен ниже.

    from __future__ import absolute_import, division, print_function
    
    import tensorflow as tf
    from tensorflow.keras import Model, layers
    import numpy as np
    
    tf.compat.v1.enable_eager_execution()
    
    num_classes = 10
    num_features = 784
    
    learning_rate = 0.1
    training_steps = 2000
    batch_size = 256
    display_step = 100
    
    n_hidden_1 = 128
    n_hidden_2 = 256
    
    from tensorflow.keras.datasets import mnist
    (x_train, y_train), (x_test, y_test) = mnist.load_data()
    x_train, x_test = np.array(x_train, np.float32), np.array(x_test, np.float32)
    x_train, x_test = x_train.reshape([-1, num_features]), x_test.reshape([-1, num_features])
    x_train, x_test = x_train / 255., x_test / 255.
    
    train_data = tf.data.Dataset.from_tensor_slices((x_train, y_train))
    train_data = train_data.repeat().shuffle(5000).batch(batch_size).prefetch(1)
    
    class NeuralNet(Model):
       def __init__(self):
          super(NeuralNet, self).__init__()
          self.fc1 = layers.Dense(n_hidden_1, activation=tf.nn.relu)
          self.fc2 = layers.Dense(n_hidden_2, activation=tf.nn.relu)
          self.out = layers.Dense(num_classes)
    
       def call(self, x, is_training=False):
          x = self.fc1(x)
          x = self.fc2(x)
          x = self.out(x)
          if not is_training:
                x = tf.nn.softmax(x)
          return x
    
    neural_net = NeuralNet()
    
    def cross_entropy_loss(x, y):
       y = tf.cast(y, tf.int64)
       loss = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=x)
       return tf.reduce_mean(loss)
    
    def accuracy(y_pred, y_true):
       correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.cast(y_true, tf.int64))
       return tf.reduce_mean(tf.cast(correct_prediction, tf.float32), axis=-1)
    
    optimizer = tf.keras.optimizers.SGD(learning_rate)
    
    def run_optimization(x, y):
       with tf.GradientTape() as g:
          pred = neural_net(x, is_training=True)
          loss = cross_entropy_loss(pred, y)
       trainable_variables = neural_net.trainable_variables
       gradients = g.gradient(loss, trainable_variables)
       optimizer.apply_gradients(zip(gradients, trainable_variables))
    
    for step, (batch_x, batch_y) in enumerate(train_data.take(training_steps), 1):
       run_optimization(batch_x, batch_y)
    
       if step % display_step == 0:
          pred = neural_net(batch_x, is_training=True)
          loss = cross_entropy_loss(pred, batch_y)
          acc = accuracy(pred, batch_y)
          print("step: %i, loss: %f, accuracy: %f" % (step, loss, acc))
    
    pred = neural_net(x_test, is_training=False)
    print("Test Accuracy: %f" % accuracy(pred, y_test))
    

    Другие примеры обучения моделей приведены на Github.

Способ 2. Обучение с помощью client_lib

  1. Соберите кастомный образ с необходимыми библиотеками с помощью функции client_lib. Используйте описание параметров ImageBuildJob.

    Ниже представлен пример, как дополнить базовый образ cr.ai.cloud.ru/aicloud-base-images/horovod-cuda10.0-tf1.15.0-pt1.3.0 нужными зависимостями. Обратите внимание на то, что путь к файлу с зависимостями указывается полностью.

    job = client_lib.ImageBuildJob(
                         from_image='cr.ai.cloud.ru/aicloud-base-images/horovod-cuda10.0-tf1.15.0-pt1.3.0',   # Base image
                         requirements_file='/home/jovyan/quick-start/job_launch/requirements.txt'    # File with dependencies for custom image
    )
    

    Файл requirements.txt должен находиться на NFS-хранилище Christofari.V100.

    Для запуска сборки кастомного образа выполните:

    job.submit()
    job.new_image     # id of the custom image
    

    Подсказка

    Посмотреть логи сборки образа в интерактивном режиме можно с помощью команды:

    job.logs()
    
  2. Создайте задачу обучения с помощью client_lib. Используйте описание параметров Job.

    Ниже приведено несколько примеров создания задач с помощью Job().

    Пример 1. Задача обучения модели с использованием базового образа

    В этом примере обязательный параметр base_image указывает на базовый образ или кастомный образ, загруженный в Docker registry, script — на скрипт, который запустится.

    Опциональный параметр job_desc позволяет задавать описание для задач обучения. Описание отображается в таблице со всеми Jupyter-серверами.

    Подсказка

    Для получения значения instance_type воспользуйтесь инструкцией.

    mnist_tf_run = client_lib.Job(base_image='cr.ai.cloud.ru/aicloud-base-images/horovod-cuda10.0-tf1.15.0-pt1.3.0:0.0.31',
                                  script='/home/jovyan/quick-start/job_launch/scripts/horovod/tensorflow_mnist_estimator.py',
                                  instance_type='your instance_type',
                                  job_desc='your_job_description')
    

    Дополнительный параметр processes_per_worker задает количество процессов на один рабочий узел региона, если не подходит количество процессов, равное количеству GPU.

    job = Job(base_image='cr.ai.cloud.ru/aicloud-base-images/horovod-cuda10.0-tf1.15.0-pt1.3.0',
             script='/home/jovyan/my-script.py',
             n_workers = 1,
             region = A100-MT,
             instance_type = a100.1gpu,      # 1 GPU Tesla A100 80GB, 16 CPU-cores, 243 GB RAM
             processes_per_worker = 1,    # Start one process
             type = 'horovod')
    

    Примечание

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

    Пример 2. Задача обучения модели с использованием базового образа и дополнительных библиотек

    mnist_tf_run = client_lib.Job(base_image=job.new_image,     # Built custom image
                                  script='/home/jovyan/quick-start/job_launch/scripts/horovod/tensorflow_mnist_estimator.py',
                                  instance_type='your instance_type',
                                  n_workers=2)
    

    Подсказка

    Внутри кода задачи обучения также можно сохранять метрики модели с помощью MLflow. См. подробнее в примере на GitHub.

    Пример 3. Задача кросс-компиляции с использованием образов ML Space

    Скомпилированные бинарные файлы можно собирать через openmpi с помощью функции client_lib. Для этого используется код, который позволяет запускать задачу:

    import client_lib
    
    binary_run = client_lib.Job(
    base_image="cr.ai.cloud.ru/aicloud-base-images/horovod-cuda10.1-tf2.2.0-pt1.5.0",
    script='/home/jovyan/NSC/mpi_omp_test',
    n_workers = 2,
    instance_type = v100.16gpu,
    type = 'binary'
    )
    
    binary_run.submit()
    
    binary_run.logs()
    
    binary_run.kill()
    

    Можно собрать бинарный файл mm из примера с GitHub. Для этого используется код:

    git clone https://github.com/hpc/MPI-Examples.git
    cd ~/MPI-Examples/matrix-multipy
    make linux
    ./test.sh
    
  3. Отправьте задачу обучения на исполнение в регион, вызвав команду submit():

    mnist_tf_run.submit()
    

    Вы увидите сообщение о том, что задача создана:

    Job 'lm-mpi-job-7a7aa4e0-8a8c-46a3-96fa-7116cc392336' created
    

Шаг 3. Проверьте логи задачи

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

Примечание

Логи отображаются для задач в статусе «Running» и «Completed».

Чтобы скачать логи задачи из интерфейса:

  1. На вкладке Задачи и окружения → Задачи нажмите Кнопка с тремя вертикальными точками рядом с нужной задачей.

  2. Выберите Скачать логи.

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

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

Остановить задачу обучения

При необходимости задачу обучения можно остановить в любой момент методом kill().

Внимание

Это действие приведет к потере всех несохраненных результатов обучения (см. Сохранить промежуточные результаты обучения (чекпоинты)).

mnist_tf_run.kill()

Или так:

client_lib.kill('lm-mpi-job-7a7aa4e0-8a8c-46a3-96fa-7116cc392336')      # For region V100
client_lib.kill(<job name>, region = 'A100')    # For region A100

Подсказка

Остановить задачу также можно из интерфейса, нажав Остановить на вкладке Задачи и окружения → Задачи.

Перезапустить задачу

Для перезапуска задачи вручную:

  1. Перейдите в Environments → Задачи и окружения.

  2. В строке с нужной задачей нажмите Кнопка для обновления пароля в Docker registry (Перезапустить).

    Другой способ — перейти в нужную задачу и нажать Кнопка для обновления пароля в Docker registry (Перезапустить).

  3. При необходимости предварительно скопируйте или скачайте параметры запуска задачи и нажмите Перезапустить.

    Примечание

    Если перезапускается уже запущенная задача, то сначала она будет остановлена. Затем создастся новая задача с такими же параметрами, как у родительской.

    Перезапуск может занять до 20 минут.

    Из появившегося окна вы можете перейти в родительскую или наследуемую задачу. Информация о них останется доступной внутри каждой перезапущенной задачи в разделах Родительская задача и Наследуемые задачи.

Обучение моделей на большом количестве GPU

Количество рабочих узлов определяется параметром n_workers. Максимальное количество GPU на одном рабочем узле — 16 (для Christofari.V100) и 8 (для Christofari.A100).

Если пользователь указал, что для обучения ему необходимы один рабочий узел региона на 16 GPU, под задачу аллоцируется один DGX. Чем больше GPU требуется пользователю для обучения модели, тем выше вероятность того, что вычислительных ресурсов может не хватить. На практике эта ситуация возникает, если задано количество GPU от 64 до 128. В результате планировщик (scheduler) ставит задачу в очередь исполнения, и она может достаточно долго находиться в статусе «pending».

Возможный обходной путь в этой ситуации — увеличить количество рабочих узлов региона, уменьшив при этом количество GPU.

Обратите внимание на то, что увеличение количества рабочих узлов региона может повлиять на скорость обмена данными, поскольку внутри одного DGX она выше, чем между несколькими DGX. Кроме того, может уменьшиться объем оперативной памяти. Подробнее см. в разделе Использование ресурсов.

Объем оперативной памяти может уменьшиться также из-за того, что исходные данные превысили ее лимит, который выделен на обучение. Например, датасет разбит на множество csv-файлов, метаинформация о которых содержится в одном файле верхнего уровня. Память заканчивается, когда вы пытаетесь «склеить» данные в один файл. Или еще одна ситуация, когда датасет включает несколько миллионов изображений, а пути к этим изображениям передаются как списки (list).

Для всех этих случаев есть общая рекомендация: постарайтесь обращаться к данным оптимально. Например, файлы можно читать частями, элементы списка можно заменить на массивы numpy.

Запустили Evolution free tier
для Dev & Test
Получить