Распределённое обучение TensorFlow
Распределённое обучение в TensorFlow — это метод, использующий несколько машин или несколько вычислительных устройств (таких как GPU/TPU) для совместной работы над выполнением задач обучения модели. Благодаря распределённому обучению мы можем:
- Ускорить процесс обучения модели
- Обрабатывать сверхбольшие наборы данных
- Обучать сложные модели с огромным числом параметров
Основные концепции
1. Стратегия распределения
TensorFlow предоставляет несколько стратегий распределения:
Пример
# Общие стратегии распределения
strategy = tf.distribute.MirroredStrategy() # Одна машина, несколько GPU
strategy = tf.distribute.MultiWorkerMirroredStrategy() # Несколько машин, несколько GPU
strategy = tf.distribute.TPUStrategy() # Кластер TPU
strategy = tf.distribute.ParameterServerStrategy() # Архитектура сервера параметров
strategy = tf.distribute.MirroredStrategy() # Одна машина, несколько GPU
strategy = tf.distribute.MultiWorkerMirroredStrategy() # Несколько машин, несколько GPU
strategy = tf.distribute.TPUStrategy() # Кластер TPU
strategy = tf.distribute.ParameterServerStrategy() # Архитектура сервера параметров
2. Параллелизм по данным vs параллелизм по модели
| Type | Параллелизм данных | Параллелизм по модели |
|---|---|---|
| Принцип | Каждое устройство обрабатывает разные пакеты данных | Модель разделяется между разными устройствами |
| Преимущества | Просто реализовать, подходит для большинства сценариев | Подходит для очень больших моделей |
| Недостатки | Требует синхронизации градиентов | Сложно реализовать |
3. Синхронное обновление vs асинхронное обновление
- Синхронное обновление:Все устройства совместно обновляют модель после завершения своих вычислений
- Асинхронное обновление:Устройства вычисляют и обновляются независимо, не дожидаясь других
Шаги реализации
1. Настройка распределённой среды
Пример
import tensorflow as tf
# Инициализация стратегии распределения
strategy = tf.distribute.MirroredStrategy()
# Проверить количество доступных устройств
print(f"Количество устройств: {strategy.num_replicas_in_sync}")
# Инициализация стратегии распределения
strategy = tf.distribute.MirroredStrategy()
# Проверить количество доступных устройств
print(f"Количество устройств: {strategy.num_replicas_in_sync}")
2. Построение модели в области стратегии
Пример
with strategy.scope():
# Все переменные, определённые в этой области, будут зеркалированы на все устройства
model = tf.keras.Sequential([
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10)
])
model.compile(
optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy']
)
# Все переменные, определённые в этой области, будут зеркалированы на все устройства
model = tf.keras.Sequential([
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10)
])
model.compile(
optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy']
)
3. Подготовка распределённого набора данных
Пример
# Загрузка набора данных
dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
# Пакетирование и шардирование
batch_size = 64 * strategy.num_replicas_in_sync # Скорректировать размер пакета в зависимости от количества устройств
dataset = dataset.shuffle(buffer_size=10000).batch(batch_size)
dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
# Пакетирование и шардирование
batch_size = 64 * strategy.num_replicas_in_sync # Скорректировать размер пакета в зависимости от количества устройств
dataset = dataset.shuffle(buffer_size=10000).batch(batch_size)
4. Обучение модели
Пример
# Традиционный метод обучения
model.fit(dataset, epochs=10)
model.fit(dataset, epochs=10)
Расширенная конфигурация
1. Конфигурация для нескольких машин
Пример
# Установите переменную окружения TF_CONFIG на каждом рабочем узле
import json
import os
os.environ['TF_CONFIG'] = json.dumps({
'cluster': {
'worker': ["worker1.example.com:12345", "worker2.example.com:23456"]
},
'task': {'type': 'worker', 'index': 0} # У каждого рабочего узла свой индекс
})
import json
import os
os.environ['TF_CONFIG'] = json.dumps({
'cluster': {
'worker': ["worker1.example.com:12345", "worker2.example.com:23456"]
},
'task': {'type': 'worker', 'index': 0} # У каждого рабочего узла свой индекс
})
2. Пользовательский цикл обучения
Пример
@tf.function
def train_step(inputs):
x, y = inputs
with tf.GradientTape() as tape:
predictions = model(x, training=True)
loss = loss_object(y, predictions)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return loss
# Шаги распределённого обучения
@tf.function
def distributed_train_step(dataset_inputs):
per_replica_losses = strategy.run(train_step, args=(dataset_inputs,))
return strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses, axis=None)
def train_step(inputs):
x, y = inputs
with tf.GradientTape() as tape:
predictions = model(x, training=True)
loss = loss_object(y, predictions)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return loss
# Шаги распределённого обучения
@tf.function
def distributed_train_step(dataset_inputs):
per_replica_losses = strategy.run(train_step, args=(dataset_inputs,))
return strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses, axis=None)
Советы по оптимизации производительности
- Корректировка размера пакета:Общий размер пакета = размер пакета на одном устройстве × количество устройств
- Предобработка данных:Используйте
dataset.prefetch()иdataset.cache()для повышения эффективности загрузки данных - Сжатие градиентов:Для связи между устройствами рассмотрите возможность использования сжатия градиентов, чтобы снизить требования к пропускной способности
- Обучение со смешанной точностью:комбинируйте
tf.keras.mixed_precisionчтобы повысить скорость обучения
Пример
# Пример смешанной точности
policy = tf.keras.mixed_precision.Policy('mixed_float16')
tf.keras.mixed_precision.set_global_policy(policy)
policy = tf.keras.mixed_precision.Policy('mixed_float16')
tf.keras.mixed_precision.set_global_policy(policy)
Устранение неполадок
1. Нехватка памяти
- Уменьшите размер батча на одно устройство
- Используйте методы накопления градиентов
- Включите опцию роста памяти
Пример
gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
2. Узкое место при обмене данными между устройствами
- Используйте
NCCLкак реализация обмена данными между устройствами - Рассмотрите возможность уменьшения частоты синхронизации (с соответствующим увеличением размера шага обновления)
Пример
# Настройте реализацию связи
os.environ['TF_GPU_ALLOCATOR'] = 'cuda_malloc_async'
os.environ['TF_FORCE_GPU_ALLOW_GROWTH'] = 'true'
os.environ['TF_GPU_ALLOCATOR'] = 'cuda_malloc_async'
os.environ['TF_FORCE_GPU_ALLOW_GROWTH'] = 'true'
Практические упражнения
Упражнение 1: обучение на одной машине с несколькими GPU
- Подготовьте простую модель CNN
- Используйте
MirroredStrategyдля обучения на наборе данных CIFAR-10 на локальных конфигурациях с несколькими GPU - Сравните разницу в скорости обучения между одним GPU и несколькими GPU
Упражнение 2: имитация конфигурации с несколькими машинами
- Используйте
MultiWorkerMirroredStrategy - чтобы смоделировать среду с несколькими рабочими процессами на одной машине (через разные порты)
- Наблюдайте за логами, чтобы понять процесс координации между рабочими процессами