DiLoCo без синхронизации: как обучать ИИ на разбросанных узлах
Метод DiLoCo снижает частоту обмена данными между узлами обучения в сотни раз. Его развязанная версия убирает жёсткую синхронизацию, позволяя тренировать большие модели на нестабильном интернете и разнородном железе.

Классическое распределённое обучение больших моделей построено на одном допущении: узлы соединены толстым и стабильным каналом, а после каждого шага градиенты синхронизируются целиком. Это работает внутри одного дата-центра, где сеть даёт сотни гигабит и микросекундные задержки. Как только узлы расползаются по разным городам или облакам, синхронизация каждого шага превращается в бутылочное горлышко: обмен terabyte-масштабов на каждой итерации через обычный интернет убивает скорость. DiLoCo (Distributed Low-Communication) снижает частоту обмена в сотни раз, а его развязанный (decoupled) вариант убирает и требование синхронного шага. Дальше — что это меняет для инженера, который собирает обучение не в идеальном кластере.
Что такое DiLoCo и почему обмен данными — главная проблема
При обычном data-parallel обучении каждый воркер держит копию модели, считает градиенты на своей порции данных и обменивается ими со всеми остальными на каждом шаге (алгоритм all-reduce1). Для модели на миллиарды параметров это сотни мегабайт или гигабайты трафика в секунду на каждый узел. Внутри дата-центра InfiniBand это переваривает. Между площадками, через публичную сеть с задержкой в десятки миллисекунд, — нет.
DiLoCo меняет ритм. Каждый воркер обучается локально H шагов (обычно десятки или сотни) своим внутренним оптимизатором, чаще всего AdamW. И только раз в H шагов узлы обмениваются не сырыми градиентами, а накопленной разницей весов — псевдоградиентом. Этот псевдоградиент прогоняется через внешний оптимизатор (в оригинальной работе Google DeepMind — Nesterov momentum SGD), и обновлённые веса рассылаются обратно.
Обмен раз в сотню шагов вместо каждого шага — это не оптимизация на проценты. Это разница между «нужен дата-центр» и «хватит нескольких машин на разных континентах».
Эффект: частота коммуникации падает в H раз, а объём каждого обмена остаётся тем же. При H = 500 суммарный сетевой трафик за обучение сокращается примерно в те же 500 раз. При этом качество модели, по данным оригинального исследования DiLoCo, остаётся сопоставимым с синхронным baseline.
Внутренний и внешний оптимизаторы
Ключ к пониманию — две петли обучения:
- Внутренняя петля — локальные шаги на узле, свой оптимизатор, свои данные. Здесь никакой сети, узел работает автономно.
- Внешняя петля — редкая синхронизация псевдоградиентов между узлами и обновление глобальных весов внешним оптимизатором.
Такое разделение и открывает дверь к развязке: если внешняя петля редкая, её можно перестать делать синхронной.
Развязка: убираем барьер синхронизации
В базовом DiLoCo остаётся один слабый момент. Раз в H шагов все узлы всё равно должны остановиться и дождаться друг друга — это барьер. Если один узел медленнее (слабее GPU, хуже канал, соседний процесс отъел ресурсы), остальные простаивают. В разнородной среде — а именно ради неё всё и затевалось — это возвращает часть потерянной эффективности.
Развязанный DiLoCo (decoupled) разрывает эту связь. Идея в том, чтобы обмен весами шёл асинхронно и в фоне, пока узлы продолжают считать. Обновление глобального состояния перестаёт быть моментом, когда всё замирает, и становится потоком, который накатывается на веса по мере готовности. Инженерно это ближе к схемам с parameter server и отложенными обновлениями, но с сохранением редкой коммуникации DiLoCo.
Что даёт развязка на практике
- Устойчивость к отстающим узлам — медленный воркер больше не тормозит быстрых. Он вливает свой вклад тогда, когда готов.
- Терпимость к обрывам — если узел временно выпал из сети, обучение не встаёт колом: остальные продолжают, отвалившийся догоняет позже.
- Разнородное железо — можно смешивать GPU разных поколений и разной пропускной способности, не выравнивая всех по самому слабому.
Цена — усложнение сходимости. Асинхронные обновления привносят «протухшие» (stale) псевдоградиенты: узел присылает разницу весов, посчитанную от уже устаревшего глобального состояния. Чем больше рассинхрон, тем сильнее это мешает. Практические реализации борются с этим взвешиванием вклада по свежести и ограничением допустимого отставания.
Где это уже применимо
| Сценарий | Синхронный data-parallel | DiLoCo | Decoupled DiLoCo |
|---|---|---|---|
| Один дата-центр, InfiniBand | Оптимален | Избыточен | Избыточен |
| Несколько облаков через интернет | Практически невозможен | Работает | Работает лучше |
| Разнородные GPU, разная скорость | Тормозит по слабейшему | Барьер мешает | Целевой сценарий |
| Нестабильный канал, обрывы | Падает | Простои на барьерах | Терпит обрывы |
Псевдокод внешней петли развязанной схемы упрощённо выглядит так — обмен идёт в фоне, локальный расчёт не блокируется:
while not converged:
# внутренняя петля: H локальных шагов без сети
for step in range(H):
grads = compute_gradients(local_batch)
inner_optimizer.step(grads)
# псевдоградиент = дрейф весов за H шагов
pseudo_grad = last_synced_weights - local_weights
# отправляем асинхронно, НЕ ждём остальных
async_send(pseudo_grad)
# применяем то, что уже пришло от других узлов
for incoming in poll_ready_updates():
weight = staleness_factor(incoming.age)
outer_optimizer.step(incoming.pseudo_grad, weight)
last_synced_weights = local_weights.clone()
Это иллюстрация логики, а не готовая библиотека: реальные реализации решают вопросы согласованности версий весов, дедупликации обновлений и защиты от слишком старых псевдоградиентов. Конкретные API смотрите в репозиториях и публикациях команд, которые ведут эти эксперименты, — детали алгоритма и рекомендованные значения H и коэффициентов старения меняются от работы к работе.
Чего это не отменяет
Развязанный DiLoCo снижает требования к сети, но не к вычислениям. Каждый узел по-прежнему должен помещать модель (или её шард) в память и считать полноценные шаги. Для по-настоящему больших моделей это по-прежнему сочетается с внутренним параллелизмом — тензорным и конвейерным — внутри каждого узла. DiLoCo решает проблему связи между площадками, а не проблему влезания модели в одну карту.
Кому это интересно прямо сейчас
- Командам, у которых вычислительные ресурсы разбросаны по нескольким регионам или провайдерам и нет бюджета на выделенный кластер.
- Проектам федеративного и совместного обучения, где данные не покидают своих узлов, а обмен по сети дорог или ограничен.
- Исследователям устойчивого обучения — тем, кому важно, чтобы прогон на сотни часов пережил выпадение узлов без рестарта с нуля.
Практический вывод: если вы упирались в стоимость и стабильность межузлового канала, а не в память отдельной карты, семейство DiLoCo — то направление, которое стоит проверить на своём пайплайне. Начните с базового синхронного DiLoCo на двух-трёх узлах, замерьте выигрыш по трафику и только потом переходите к развязанной схеме, где сложнее отлаживать сходимость.
1 All-reduce — коллективная операция, при которой все узлы обмениваются значениями (например, градиентами) и каждый получает их сумму или среднее. Основной примитив синхронного распределённого обучения; его стоимость растёт с числом узлов и объёмом данных.
Prompt-инженер: Идеальные запросы для Midjourney, ChatGPT и других моделей.
Спросить за 15 ₽Источники: DiLoCo: Distributed Low-Communication Training of Language Models (Google DeepMind, arXiv)
Частые вопросы
Чем DiLoCo отличается от обычного data-parallel обучения?
Что именно даёт развязка (decoupling) поверх базового DiLoCo?
Не портится ли качество модели из-за редкой синхронизации?
DiLoCo позволяет обучать модели, которые не влезают в одну GPU?
Можно ли смешивать GPU разных поколений?
Что такое «протухший» (stale) псевдоградиент и чем он опасен?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.