Когда нейросеть обучается слишком долго или выдает ошибку нехватки видеопамяти (CUDA Out of Memory), добавление одной, даже самой мощной видеокарты помогает лишь до определенного предела. Дальше приходится объединять несколько графических процессоров (GPU) или целых серверов в одну систему. Это и есть распределенное обучение. Процесс не работает автоматически: недостаточно просто арендовать сервер с восемью картами, нужно на уровне кода указать фреймворку, как именно делить нагрузку и данные.
| Какой вопрос закроем | Что это даст на практике |
| Как выбрать стратегию распределения | Перестанете ловить ошибки памяти и ускорите обучение пропорционально железу |
| Какие инструменты использовать | Сможете внедрить решение в стандартный код на PyTorch без написания костылей |
| Где возникают узкие места | Не будете переплачивать за аренду GPU, которые простаивают из-за медленной сети или диска |
Базовые стратегии: как разделить задачу между GPU
Есть два основных способа распределить вычисления. Выбор зависит исключительно от того, помещается ли ваша модель в видеопамять (VRAM) одной видеокарты.
Параллелизм данных (Data Parallelism)
Когда применять: Модель полностью помещается в память одной GPU, но данных слишком много, и на одной карте обучение займет недели.
Как работает: На каждую видеокарту загружается полная копия модели. Весь датасет (например, миллион изображений) делится на равные части. Каждая GPU прогоняет свою часть данных через свою копию модели и вычисляет ошибку (градиенты). Затем видеокарты обмениваются результатами, усредняют их и синхронно обновляют веса. Цикл повторяется.
Практический инструмент: В PyTorch это реализуется через модуль DistributedDataParallel (DDP).
Параллелизм моделей (Model Parallelism)
Когда применять: Модель настолько велика (например, языковая модель на десятки миллиардов параметров), что вообще не влезает в память одной видеокарты, даже при минимальном размере батча.
Как работает: Сама архитектура нейросети разрезается на части. Например, первые 10 слоев загружаются на первую GPU, следующие 10 – на вторую. Данные проходят через первую карту, результат передается по сети на вторую, и так далее.
Ограничение: В чистом виде этот метод заставляет видеокарты простаивать. Пока вторая GPU ждет данные от первой, она ничего не делает. Поэтому на практике используют конвейерный параллелизм (Pipeline Parallelism), когда данные подаются мелкими порциями (микробатчами) непрерывно.
Гибридный подход (FSDP / DeepSpeed)
Когда применять: При обучении современных LLM (Large Language Models), когда не хватает памяти ни на модель, ни на состояния оптимизатора.
Как работает: Полностью шардированный параллелизм данных (Fully Sharded Data Parallel). Модель режется на куски, но каждая GPU подгружает нужный кусок с других карт только в тот момент, когда он требуется для вычислений, а затем сразу удаляет из памяти. Это современный стандарт для обучения крупных сетей.
Как выбрать метод под вашу задачу
Для принятия решения используйте следующий алгоритм оценки.
- Если модель занимает до 15-20 ГБ, а у вас карты по 24-80 ГБ: Однозначно используйте Data Parallelism (PyTorch DDP). Это самый простой в настройке и самый линейно масштабируемый метод.
- Если модель требует 100 ГБ памяти, а у вас сервер с четырьмя картами по 40 ГБ (например, A100): Используйте FSDP от PyTorch или библиотеку DeepSpeed (Zero Stage 2 или 3). Это позволит размазать веса и градиенты по всем картам.
- Если вы обучаете сеть-гигант на нескольких серверах (кластере): Потребуется комбинация тензорного, конвейерного параллелизма и параллелизма данных. Обычно для этого берут готовые фреймворки вроде Megatron-LM, так как писать это с нуля нецелесообразно.
Частые ошибки и точки провала
При переходе от обучения на одной карте к распределенному, разработчики часто теряют деньги на аренде из-за неэффективной утилизации оборудования.
Ошибка 1: Использование устаревшего DataParallel (DP) вместо DDP
В чем ошибка: В PyTorch есть старый модуль torch.nn.DataParallel. Он требует всего одну строчку кода, поэтому новички выбирают его. Но он использует один процесс Python, который постоянно перекидывает данные между картами через центральный процессор.
К чему приводит: Огромные накладные расходы. Добавление второй карты может ускорить обучение не в 2 раза, а лишь на 20-30%.
Как избежать: Всегда используйте torch.nn.parallel.DistributedDataParallel (DDP). Он запускает отдельный процесс для каждой GPU. Данные не гоняются через процессор, карты общаются напрямую. Настройка сложнее (требует инициализации группы процессов), но эффективность масштабирования достигает 90-95%.
Ошибка 2: Узкое горлышко в хранилище данных
В чем ошибка: Вы арендовали сервер за 1500 рублей в час с топовыми картами, но оставили датасет на медленном сетевом диске или дешевом HDD.
К чему приводит: Утилизация GPU падает до 10-20%. Карты мгновенно обрабатывают батч и ждут, пока процессор прочитает следующие картинки с диска.
Как избежать: Данные для обучения всегда должны лежать на локальном NVMe SSD сервере, где идет обучение. Проверяйте метрику GPU Volatile Uncore Utilization (через nvidia-smi) – она должна стабильно держаться выше 80%.
Ошибка 3: Медленная сеть между серверами
В чем ошибка: Попытка объединить в кластер обычные серверы, соединенные стандартным Ethernet (10-25 Гбит/с).
К чему приводит: При Data Parallelism видеокарты должны передавать друг другу гигабайты градиентов на каждом шаге. Стандартная сеть не справляется, обучение останавливается в ожидании синхронизации.
Как избежать: Если вы выходите за пределы одного сервера (на 2 и более машин), серверы должны быть объединены сетью InfiniBand или RoCE (от 100 до 400 Гбит/с). Если такой сети нет, дешевле и быстрее обучать на одном максимально мощном сервере, чем на двух слабых.
Инфраструктура и российские реалии
Для распределенного обучения критически важна связность внутри сервера. Карты должны общаться друг с другом минуя центральный процессор через мосты NVLink.
В российских облаках (Yandex Cloud, Selectel, Cloud.ru) промышленные серверы для ML обычно комплектуются картами NVIDIA A100 или V100. Они изначально соединены через NVLink, что идеально для PyTorch DDP и FSDP.
Если вы собираете сервер самостоятельно на базе игровых видеокарт (например, RTX 3090 или 4090), учтите ограничение: в 4090 NVIDIA убрала поддержку NVLink. Карты будут обмениваться градиентами через шину PCIe материнской платы. В задачах компьютерного зрения это снизит скорость на 5-15%, а в обучении языковых моделей падение производительности может быть критичным. Для серьезного распределенного обучения LLM придется арендовать профессиональные дата-центровые карты.
Альтернатива: что делать, если бюджета на кластер нет
Если модель не влезает в память, а арендовать сервер с несколькими GPU слишком дорого, примените методы алгоритмической экономии памяти. Они замедлят обучение, но позволят запустить задачу на одной карте.
- Накопление градиентов (Gradient Accumulation): Вы делаете размер батча равным 1 (чтобы влезло в память), но не обновляете веса сразу. Сеть считает градиенты для нескольких батчей подряд, суммирует их, и только потом делает шаг оптимизатора. Математически это эквивалентно большому батчу.
- Gradient Checkpointing: Вместо хранения всех промежуточных вычислений в памяти (активаций), фреймворк удаляет их и пересчитывает заново во время обратного прохода. Экономит до 50% видеопамяти ценой увеличения времени обучения на 20-30%.
- Квантование и LoRA: Если вы не обучаете модель с нуля, а дообучаете (Fine-tuning), заморозьте основные веса, переведите их в 8-битный формат, и обучайте только небольшие адаптеры (LoRA). Модель на 7 миллиардов параметров можно дообучить на одной карте с 24 ГБ памяти (RTX 3090 / 4090) без сложного распределенного программирования.