- tocdepth
2
Запустить процесс обучения
Модели можно обучать следующими способами:
Напрямую из 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. Выполните подготовку к обучению
Создайте Jupyter Server или подключитесь к уже существующему.
Выберите среду для обучения модели: Jupyter Notebook или JupyterLab.
JupyterLab существенно обогащает возможности классического Jupyter Notebook, поскольку поддерживает работу одновременно с несколькими ноутбуками, текстовыми файлами, датасетами, терминалами и позволяет упорядочить документы в рабочей области.
Перенесите данные и скрипты для обучения из объектного хранилища S3 в локальное хранилище NFS требуемого региона. См. Способ 1. Через интерфейс Обзора хранилища.
Шаг 2. Обучите модель одним из способов
Способ 1. Обучение из Jupyter Server с GPU
Перейдите в созданную на шаге 1 среду для обучения.
Установите необходимые библиотеки, если в базовых образах нет нужных вам зависимостей.
Если для работы необходимо установить дополнительные модули Python или обновить существующие, выполните следующий код:
pip install --user <package_name> == <version>
Где:
package_name
— наименование модуля, который предполагается установить;version
— версия устанавливаемого модуля.
Подробнее об использовании
pip
— в документации менеджера пакетов.Подсказка
Если необходимы более новые версии Python и CUDA, создайте нужное окружение с помощью CLI-утилиты ML Space.
Запустите обучение модели.
Для запуска используйте образ, в котором версия
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
Соберите кастомный образ с необходимыми библиотеками с помощью функции 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()
Создайте задачу обучения с помощью client_lib. Используйте описание параметров Job.
Ниже приведено несколько примеров создания задач с помощью Job().
Пример 1. Задача обучения модели с использованием базового образа
В этом примере обязательный параметр
base_image
указывает на базовый образ или кастомный образ, загруженный в Docker registry,script
— на скрипт, который запустится.Опциональный параметр
job_desc
позволяет задавать описание для задач обучения.Подсказка
Для получения значения
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
Отправьте задачу обучения на исполнение в регион, вызвав команду
submit()
:mnist_tf_run.submit()
Вы увидите сообщение о том, что задача создана:
Job 'lm-mpi-job-7a7aa4e0-8a8c-46a3-96fa-7116cc392336' created
Шаг 3. Проверьте логи задачи
После того как задача запустилась, вы можете посмотреть логи одним из способов.
Примечание
Логи отображаются для задач в статусе «Running» и «Completed».
Чтобы скачать логи задачи из интерфейса:
На вкладке
нажмите рядом с нужной задачей.Выберите Скачать логи.
Если при создании задачи использован параметр max_retry, то начиная со второго запуска вы сможете выбрать, какие логи скачать: по текущему запуску задачи, по всем запускам или по конкретному запуску.
Вызовите метод logs()
для задачи.
mnist_tf_run.logs() # View logs by task
Или используйте команду client_lib.logs(), передав в нее название задачи.
client_lib.logs("lm-mpi-job-7a7aa4e0-8a8c-46a3-96fa-7116cc392336") # View logs by task name
Уровень детализации логов управляется параметром verbose
.
Он позволяет исключить из лога информацию о выполнении служебных процессов.
Если вызвать logs()
после отправки задачи с помощью метода submit()
, логи могут не отобразиться сразу, поскольку региону нужно время на запуск.
В начале файла с логами выводится информация по процессу проверки доступности воркеров. В результате вы увидите сообщение о доступности всех воркеров или указание на проблему при старте задачи.
Отслеживать статус задачи обучения
Отслеживать статус задачи обучения можно:
Остановить задачу обучения
При необходимости задачу обучения можно остановить в любой момент методом 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
Подсказка
Остановить задачу также можно из интерфейса, нажав Остановить на вкладке .
Перезапустить задачу
Для перезапуска задачи вручную:
Перейдите в
.В строке с нужной задачей нажмите (Перезапустить).
Другой способ — перейти в нужную задачу и нажать (Перезапустить).
При необходимости предварительно скопируйте или скачайте параметры запуска задачи и нажмите Перезапустить.
Примечание
Если перезапускается уже запущенная задача, то сначала она будет остановлена. Затем создастся новая задача с такими же параметрами, как у родительской.
Перезапуск может занять до 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
.
для Dev & Test