Хуки коммуникации DDP
Создано: 6 июня 2025 г. | Последнее обновление: 12 мая 2026 г.
Хук коммуникации DDP — это универсальный интерфейс для управления передачей градиентов между рабочими процессами, который позволяет переопределить стандартную операцию all-reduce в DistributedDataParallel. Предоставляется несколько встроенных хуков коммуникации, и пользователи могут легко применять любой из них для оптимизации коммуникации. Кроме того, интерфейс хуков поддерживает пользовательские стратегии коммуникации для более сложных сценариев использования.
Как использовать хук коммуникации?
Чтобы использовать хук коммуникации, пользователю достаточно зарегистрировать хук в модели DDP перед циклом обучения, как показано ниже.
torch.nn.parallel.DistributedDataParallel.register_comm_hook()
С чем работает хук коммуникации?
Хук коммуникации предоставляет гибкий способ выполнять all-reduce градиентов. Поэтому он работает главным образом с градиентами каждой реплики до операции all-reduce, которые распределяются по корзинам, чтобы увеличить перекрытие коммуникации и вычислений. В частности, torch.distributed.GradBucket представляет собой корзину тензоров градиентов для операции all-reduce.
-
class torch.distributed.GradBucket -
Этот класс передаёт в хук коммуникации DDP одномерный тензор градиентов (возвращаемый методом
buffer()). Этот тензор можно дополнительно разделить на список тензоров отдельных параметров в этой корзине (возвращаемый методомget_per_parameter_tensors()), чтобы применять поуровневые операции.
-
torch.distributed.GradBucket.index(self: torch._C._distributed_c10d.GradBucket) → int -
Предупреждение
Поскольку после первой итерации корзины перестраиваются, не следует полагаться на их индексы в начале обучения.
- Возвращает:
-
Индекс корзины, в которой хранятся градиенты нескольких смежных слоёв. Все градиенты распределяются по корзинам.
-
torch.distributed.GradBucket.buffer(self: torch._C._distributed_c10d.GradBucket) → torch.Tensor -
- Возвращает:
-
Одномерный сплющенный буфер
torch.Tensor, который можно дополнительно разделить на список тензоров отдельных параметров в этой корзине.
-
torch.distributed.GradBucket.gradients(self: torch._C._distributed_c10d.GradBucket) → list[torch.Tensor] -
- Возвращает:
-
Список
torch.Tensor. Каждый тензор в списке соответствует градиенту.
-
torch.distributed.GradBucket.is_last(self: torch._C._distributed_c10d.GradBucket) → bool -
- Возвращает:
-
Указывает, является ли эта корзина последней корзиной, для которой выполняется all-reduce в данной итерации. Это также означает, что эта корзина соответствует первым нескольким слоям прямого прохода.
-
torch.distributed.GradBucket.set_buffer(self: torch._C._distributed_c10d.GradBucket, buffer: torch.Tensor) → None -
Заменяет тензор в корзине входным буфером тензора.
-
torch.distributed.GradBucket.parameters(self: torch._C._distributed_c10d.GradBucket) → list[torch.Tensor] -
- Возвращает:
-
Список
torch.Tensor. Каждый тензор в списке соответствует параметру модели.
Регистрация хука коммуникации
-
torch.distributed.algorithms.ddp_comm_hooks.register_ddp_comm_hook(comm_hook_type, model, state=None)[исходный код] -
Регистрирует
ddp_comm_hooksв модели DDP.Регистрирует хуки
torch.distributed.algorithms.ddp_comm_hooksв модели DDP. Пользователь может указать тип хука в качестве типа перечисленияDDPCommHookTypeс помощью входного аргументаcomm_hook_type. Модели передаётся входное состояние. Используются реализации хуков коммуникации на Python.- Пример::
-
>>> register_ddp_comm_hook(DDPCommHookType.FP16_COMPRESS, model, state)
-
torch.distributed.algorithms.ddp_comm_hooks.post_localSGD_hook.post_localSGD_hook(state, bucket)[исходный код] -
Запускает алгоритм post-localSGD.
Этот хук коммуникации DDP используется для запуска алгоритма post-localSGD совместно с компонентом усреднения модели (например,
PeriodicModelAverager), который выполняется после шага оптимизатора.- Параметры:
-
-
state (PostLocalSGDState) – информация о состоянии для запуска post-localSGD. Пользователям в основном нужно настроить
start_localSGD_iter, чтобы определить, когда начинать локальный SGD. - bucket (dist.GradBucket) – корзина, в которой хранится одномерный сплющенный тензор градиентов, объединяющий несколько тензоров отдельных переменных. Обратите внимание: поскольку хук коммуникации DDP поддерживает только режим «один процесс — одно устройство», в этой корзине хранится ровно один тензор.
-
state (PostLocalSGDState) – информация о состоянии для запуска post-localSGD. Пользователям в основном нужно настроить
- Возвращает:
-
Обработчик Future для коммуникации, который обновляет градиенты на месте.
- Тип возвращаемого значения:
- Пример::
-
>>> state = PostLocalSGDState(process_group=process_group, subgroup=subgroup, start_localSGD_iter=10) >>> ddp_model.register_comm_hook(state, post_localSGD_hook) >>> # Also need to establish a model averaging module and run model averaging after ``optimizer.step()``. >>> # Please refer to the examples in ``torch.distributed.algorithms.model_averaging.averagers`` module.
-
torch.distributed.algorithms.ddp_comm_hooks.ddp_zero_hook.hook_with_zero_step(hook, ddp, zero, shard_buckets=False)[исходный код] -
Изменяет
hook, чтобы перекрыть шаг оптимизатораZeroRedundancyOptimizerс обратным проходомDistributedDataParallel.Этот подход перекрывает вычисления и коммуникацию оптимизатора с коммуникацией обратного прохода. В частности, вычисления обратного прохода выполняются последовательно, а затем начинаются вычисления оптимизатора, перекрываясь с ожидающей коммуникацией обратного прохода (то есть операциями all-reduce) и, возможно, с другой коммуникацией оптимизатора (то есть широковещательными рассылками). Вычисление шага оптимизатора начинается после завершения вычисления последней корзины градиентов.
Этот подход может быть предпочтительнее
hook_with_zero_step_interleaved(), если коммуникация относительно медленна по сравнению с вычислениями.- Параметры:
-
- hook (Callable[[Any, dist.GradBucket], torch.futures.Future]) – хук, который нужно изменить.
-
ddp (DistributedDataParallel) – экземпляр
DistributedDataParallelдля использования. -
zero (ZeroRedundancyOptimizer) – экземпляр
ZeroRedundancyOptimizerдля использования. -
shard_buckets (bool) – если
True, назначение каждой корзиныDistributedDataParallelразделяется между несколькими экземплярамиZeroRedundancyOptimizer(то есть несколькими рангами), чтобы добиться приблизительного равномерного распределения; еслиFalse, каждая корзина целиком назначается одному экземпляруZeroRedundancyOptimizer(то есть одному рангу).
- Возвращает:
-
Изменённый хук.
- Вызывает исключения:
-
-
ValueError – если
zeroсоздан с параметромoverlap_with_ddp=False. - RuntimeError – при использовании любого бэкенда, отличного от NCCL/HCCL, так как в настоящее время Gloo может зависнуть.
-
ValueError – если
- Тип возвращаемого значения:
-
Callable[[Any, GradBucket], Future[Tensor]]
Предупреждение
Из-за особенностей текущей реализации перекрытия
DistributedDataParallelсZeroRedundancyOptimizerв первые две или три итерации обучения не выполняются обновления параметров на шаге оптимизатора — в зависимости от того, используется лиstatic_graph=Falseилиstatic_graph=Trueсоответственно. Это связано с необходимостью получить информацию о стратегии распределения градиентов по корзинам, используемойDistributedDataParallel. Эта стратегия окончательно определяется только после второго прямого прохода, если используетсяstatic_graph=False, или после третьего прямого прохода, если используетсяstatic_graph=True.
-
torch.distributed.algorithms.ddp_comm_hooks.ddp_zero_hook.hook_with_zero_step_interleaved(hook, ddp, zero, shard_buckets=False)[исходный код] -
Изменяет
hook, чтобы перекрыть шаг оптимизатораZeroRedundancyOptimizerс обратным проходомDistributedDataParallelЭтот подход перекрывает вычисления и коммуникацию оптимизатора с вычислениями и коммуникацией обратного прохода. В частности, после вычисления градиентов корзины запускаются вычисления оптимизатора с использованием этих градиентов (хотя фактическое вычисление должно дождаться завершения операции all-reduce для этой корзины). В результате операции all-reduce и широковещательные рассылки чередуются в потоке коммуникации.
Этот подход может быть предпочтительнее
hook_with_zero_step(), если коммуникация относительно быстра по сравнению с вычислениями.- Параметры:
-
- hook (Any * dist.GradBucket -> torch.futures.Future) – хук, который нужно изменить.
-
ddp (DistributedDataParallel) – экземпляр
DistributedDataParallelдля использования. -
zero (ZeroRedundancyOptimizer) – экземпляр
ZeroRedundancyOptimizerдля использования. -
shard_buckets (bool) – если
True, назначение каждой корзиныDistributedDataParallelразделяется между несколькими экземплярамиZeroRedundancyOptimizer(то есть несколькими рангами), чтобы добиться приблизительного равномерного распределения; еслиFalse, каждая корзина целиком назначается одному экземпляруZeroRedundancyOptimizer(то есть одному рангу).
- Возвращает:
-
Изменённый хук.
- Вызывает исключения:
-
-
ValueError – если
zeroсоздан с параметромoverlap_with_ddp=False. - RuntimeError – при использовании любого бэкенда, отличного от NCCL, так как в настоящее время Gloo может зависнуть.
-
ValueError – если
- Тип возвращаемого значения:
-
Callable[[Any, GradBucket], Future[Tensor]]
Предупреждение
Из-за особенностей текущей реализации перекрытия
DistributedDataParallelсZeroRedundancyOptimizerв первые две или три итерации обучения не выполняются обновления параметров на шаге оптимизатора — в зависимости от того, используется лиstatic_graph=Falseилиstatic_graph=Trueсоответственно. Это связано с необходимостью получить информацию о стратегии распределения градиентов по корзинам, используемойDistributedDataParallel. Эта стратегия окончательно определяется только после второго прямого прохода, если используетсяstatic_graph=False, или после третьего прямого прохода, если используетсяstatic_graph=True.
-
torch.distributed.algorithms.ddp_comm_hooks.quantization_hooks.quantization_perchannel_hook(process_group, bucket, bucket_size=512)[исходный код] -
Применяет логику ``torch.quantize_per_channel`` к DDP с использованием протокола
allgather.По сравнению с поканальным квантованием, основная цель поканального квантования — обработка достаточно больших тензоров. Например, квантование тензора из 6 миллионов элементов по корзинам размером 512 (или 128) элементов может значительно повысить разрешение.
Сначала тензор
GradBucketразделяется на несколько частей (каналов) поbucket_sizeэлементов. Затем рабочие процессы выполняют all-gather масштабов и нулевых точек собственныхGradBucketперед квантованием. Когда эта информация есть у всех рабочих процессов, первый обратный вызовthen, называемыйquantize_and_allgather, квантирует собственный тензор градиентов рабочего процесса и используетallgatherдля передачи данных между всеми рабочими процессами. Последний обратный вызовthen, называемыйdequantize_and_aggregate, выполняет обратное квантование, сплющивание и локальную агрегацию каждого квантованного тензора градиентов и возвращает среднее значение.Предупреждение
Эта функция является экспериментальной и использует протокол
allgather, который значительно медленнее протоколаallreduce. Работает только со сплющенными градиентами.- Пример::
-
>>> ddp_model.register_comm_hook(process_group, quantization_perchannel_hook)
-
torch.distributed.algorithms.ddp_comm_hooks.quantization_hooks.quantization_pertensor_hook(process_group, bucket)[исходный код] -
Применяет логику
torch.quantize_per_tensorк DDP с использованием протоколаallgather.Перед квантованием рабочие процессы выполняют all-gather масштаба и нулевой точки собственных
GradBucket. Когда эта информация есть у всех рабочих процессов, первый обратный вызовthen, называемыйquantize_and_allgather, квантирует собственный тензор градиентов рабочего процесса и используетallgatherдля передачи данных между всеми рабочими процессами. Последний обратный вызовthen, называемыйdequantize_and_aggregate, выполняет обратное квантование и локальную агрегацию каждого квантованного тензора градиентов и возвращает среднее значение.Предупреждение
Эта функция является экспериментальной и использует протокол
allgather, который значительно медленнее протоколаallreduce. Работает только со сплющенными градиентами.- Пример::
-
>>> ddp_model.register_comm_hook(process_group, quantization_pertensor_hook)
Хуки коммуникации по умолчанию
Хуки коммуникации по умолчанию — это простые хуки без состояния, поэтому входное состояние в register_comm_hook — это либо группа процессов, либо None. Входной аргумент bucket представляет собой объект torch.distributed.GradBucket.
-
torch.distributed.algorithms.ddp_comm_hooks.default_hooks.allreduce_hook(process_group, bucket)[исходный код] -
Выполняет
allreduceс использованием тензоровGradBucket.После агрегации тензоров градиентов по всем рабочим процессам обратный вызов
thenвычисляет среднее значение и возвращает результат.Если пользователь регистрирует этот хук коммуникации DDP, ожидается, что результаты DDP будут такими же, как и без зарегистрированного хука. Поэтому поведение DDP не изменится, и пользователь может использовать этот хук в качестве примера или изменить его, чтобы регистрировать полезную информацию либо выполнять другие задачи, не влияя на поведение DDP.
- Пример::
-
>>> ddp_model.register_comm_hook(process_group, allreduce_hook)
-
torch.distributed.algorithms.ddp_comm_hooks.default_hooks.fp16_compress_hook(process_group, bucket)[исходный код] -
Сжимает тензор, приводя
GradBucketк типуtorch.float16и деля на размер группы процессов.Этот хук коммуникации DDP реализует простой способ сжатия градиентов: тензор
GradBucketприводится к формату чисел с плавающей запятой половинной точности (torch.float16), а затем делится на размер группы процессов. Выполняется all-reduce этих тензоров градиентовfloat16. После выполнения all-reduce сжатых тензоров градиентов связанный обратный вызовdecompressприводит их обратно к входному типу данных (например,float32).- Пример::
-
>>> ddp_model.register_comm_hook(process_group, fp16_compress_hook)
-
torch.distributed.algorithms.ddp_comm_hooks.default_hooks.bf16_compress_hook(process_group, bucket)[исходный код] -
Предупреждение: этот API является экспериментальным и требует версии NCCL новее 2.9.6.
Этот хук коммуникации DDP реализует простой способ сжатия градиентов: тензор
GradBucketприводится к формату чисел с плавающей запятой половинной точности Brain floating point (torch.bfloat16), а затем делится на размер группы процессов. Выполняется all-reduce этих тензоров градиентовbfloat16. После выполнения all-reduce сжатых тензоров градиентов связанный обратный вызовdecompressприводит их обратно к входному типу данных (например,float32).- Пример::
-
>>> ddp_model.register_comm_hook(process_group, bf16_compress_hook)
Кроме того, предоставлена оболочка хука коммуникации для поддержки fp16_compress_hook() или bf16_compress_hook() в качестве оболочки, которую можно комбинировать с другими хуками коммуникации.
-
torch.distributed.algorithms.ddp_comm_hooks.default_hooks.fp16_compress_wrapper(hook)[исходный код] -
Преобразует входной тензор в
torch.float16, а результат хука — обратно к входному типу данных.Эта оболочка преобразует входной тензор градиентов заданного хука коммуникации DDP в формат чисел с плавающей запятой половинной точности (
torch.float16), а результирующий тензор заданного хука преобразует обратно к входному типу данных, напримерfloat32. Таким образом,fp16_compress_hookэквивалентенfp16_compress_wrapper(allreduce_hook).- Пример::
-
>>> state = PowerSGDState(process_group=process_group, matrix_approximation_rank=1, start_powerSGD_iter=10) >>> ddp_model.register_comm_hook(state, fp16_compress_wrapper(powerSGD_hook))
- Тип возвращаемого значения:
-
Callable[[Any, GradBucket], Future[Tensor]]
-
torch.distributed.algorithms.ddp_comm_hooks.default_hooks.bf16_compress_wrapper(hook)[исходный код] -
Предупреждение: этот API является экспериментальным и требует версии NCCL новее 2.9.6.
Эта оболочка преобразует входной тензор градиентов заданного хука коммуникации DDP в формат чисел с плавающей запятой половинной точности Brain floating point (
torch.bfloat16), а результирующий тензор заданного хука преобразует обратно к входному типу данных, напримерfloat32.Таким образом,
bf16_compress_hookэквивалентенbf16_compress_wrapper(allreduce_hook).- Пример::
-
>>> state = PowerSGDState(process_group=process_group, matrix_approximation_rank=1, start_powerSGD_iter=10) >>> ddp_model.register_comm_hook(state, bf16_compress_wrapper(powerSGD_hook))
- Тип возвращаемого значения:
-
Callable[[Any, GradBucket], Future[Tensor]]
Коммуникационный хук PowerSGD
PowerSGD (Vogels et al., NeurIPS 2019) — это алгоритм сжатия градиентов, который обеспечивает очень высокую степень сжатия и ускоряет распределённое обучение, ограниченное пропускной способностью сети. Для работы этому алгоритму необходимо хранить гиперпараметры и внутреннее состояние. Поэтому коммуникационный хук PowerSGD — это хук с сохранением состояния, и пользователь должен предоставить объект состояния, определённый ниже.
Состояние PowerSGD
-
class torch.distributed.algorithms.ddp_comm_hooks.powerSGD_hook.PowerSGDState(process_group, matrix_approximation_rank=1, start_powerSGD_iter=1000, min_compression_rate=2, use_error_feedback=True, warm_start=True, orthogonalization_epsilon=0, random_seed=0, compression_stats_logging_frequency=10000, batch_tensors_with_same_shape=False)[исходный код] -
Хранит гиперпараметры алгоритма и внутреннее состояние для всех градиентов во время обучения.
В частности,
matrix_approximation_rankиstart_powerSGD_iter— основные гиперпараметры, которые следует настраивать пользователю. Для повышения производительности рекомендуется включить двоичные гиперпараметрыuse_error_feedbackиwarm_start.-
matrix_approximation_rankзадаёт размер сжатых тензоров низкого ранга, определяющий степень сжатия. Чем ниже ранг, тем сильнее сжатие.1.1. Если
matrix_approximation_rankслишком мало, для достижения исходного качества модели потребуется больше шагов обучения, либо его не удастся достичь вовсе, что приведёт к потере точности.1.2. Увеличение
matrix_approximation_rankможет значительно повысить вычислительные затраты на сжатие, а точность может перестать улучшаться после достижения определённого порогаmatrix_approximation_rank.
Для настройки
matrix_approximation_rankрекомендуется начать со значения 1 и увеличивать его в 2 раза (например, при экспоненциальном поиске по сетке: 1, 2, 4, …), пока не будет достигнута удовлетворительная точность. Обычно используют небольшие значения — 1–4. Для некоторых задач NLP (как показано в приложении D исходной статьи) это значение увеличивали до 32.-
start_powerSGD_iterоткладывает сжатие PowerSGD до шагаstart_powerSGD_iter, а до шагаstart_powerSGD_iterвыполняется обычный allreduce. Эта гибридная схема обычный allreduce + PowerSGD может эффективно повысить точность даже при относительно небольшом значенииmatrix_approximation_rank. Это связано с тем, что начальный этап обучения обычно очень чувствителен к неточным градиентам, и слишком раннее сжатие градиентов может быстро направить обучение по неоптимальной траектории, что может необратимо повлиять на точность.
Для настройки
start_powerSGD_iterрекомендуется начать с 10% от общего числа шагов обучения и увеличивать значение, пока не будет достигнута удовлетворительная точность. Если в обучении предусмотрен этап разогрева,start_powerSGD_iterобычно должно быть не меньше числа шагов разогрева.-
min_compression_rate— минимальная требуемая степень сжатия для сжимаемого слоя. Учитывая накладные расходы на вычисления при сжатии, сжимать тензор целесообразно только в том случае, если это обеспечивает достаточную экономию пропускной способности, где(num_rows + num_cols) * matrix_approximation_rank * min_compression_rate < num_rows * num_cols. Если заданный порог степени сжатия не достигнут, тензор будет обработан напрямую с помощью allreduce, без сжатия.
Статистика сжатия выводится каждые
compression_stats_logging_frequencyитераций после начала сжатия PowerSGD.-
orthogonalization_epsilonможет быть очень малым значением (например, 1e-8), которое добавляется к каждому столбцу нормализованной матрицы на этапе ортогонализации, чтобы предотвратить ошибку деления на ноль, если столбец состоит только из нулей. Если эту ситуацию можно предотвратить другим способом (например, с помощью пакетной нормализации), для повышения точности рекомендуется задать epsilon равным 0. -
batch_tensors_with_same_shapeопределяет, следует ли сжимать и распаковывать тензоры одинаковой формы пакетно, чтобы повысить параллелизм. Обратите внимание: чтобы в одну корзину попадало больше тензоров одинаковой формы, следует также увеличить размер корзины (то есть аргументbucket_cap_mbв конструкторе DDP). Однако это может уменьшить перекрытие вычислений и обмена данными, а также увеличить потребление памяти из-за объединения тензоров одинаковой формы. Установите значениеTrue, если вычисления сжатия и распаковки являются узким местом.
Предупреждение
Если включена обратная связь по ошибке или разогрев, минимальное допустимое значение
start_powerSGD_iterв DDP равно 2. Это связано с тем, что в DDP применяется ещё одна внутренняя оптимизация, которая перестраивает корзины на итерации 1; она может конфликтовать с любым тензором, сохранённым до перестройки. -
Хуки PowerSGD
Предупреждение
Для обратной связи по ошибке PowerSGD обычно требуется дополнительная память размером с градиенты модели. Это позволяет компенсировать смещение при сжатом обмене данными и повысить точность.
Предупреждение
Хуки PowerSGD могут конфликтовать с пакетом автоматической смешанной точности Apex. Вместо него используйте встроенный пакет автоматической смешанной точности PyTorch.
-
torch.distributed.algorithms.ddp_comm_hooks.powerSGD_hook.powerSGD_hook(state, bucket)[исходный код] -
Реализует алгоритм PowerSGD.
Этот коммуникационный хук DDP реализует алгоритм сжатия градиентов PowerSGD, описанный в статье. После того как градиентные тензоры собраны со всех рабочих процессов, хук выполняет сжатие следующим образом:
-
Интерпретирует входной одномерный развёрнутый тензор градиентов как список тензоров отдельных параметров и делит все тензоры на две группы:
1.1 Тензоры, которые следует сжать до allreduce, поскольку сжатие обеспечивает достаточную экономию пропускной способности.
1.2 Остальные тензоры обрабатываются напрямую с помощью allreduce, без сжатия; к ним относятся все векторные тензоры (для смещений).
-
Обрабатывает несжатые тензоры:
2.1. Выделяет непрерывную область памяти для несжатых тензоров и выполняет для них пакетный allreduce без сжатия;
2.2. Копирует отдельные несжатые тензоры из непрерывной области памяти обратно во входной тензор.
-
Обрабатывает тензоры, подлежащие сжатию с помощью PowerSGD:
3.1. Для каждого тензора M создаёт два тензора низкого ранга P и Q для разложения M, так что M = PQ^T; Q инициализируется из стандартного нормального распределения и ортогонализуется;
3.2. Вычисляет каждый P в Ps, который равен MQ;
3.3. Выполняет пакетный allreduce для Ps;
3.4. Ортогонализует каждый P в Ps;
3.5. Вычисляет каждый Q в Qs, который приблизительно равен M^TP;
3.6. Выполняет пакетный allreduce для Qs;
3.7. Вычисляет каждый M среди всех сжатых тензоров, который приблизительно равен PQ^T.
Обратите внимание, что этот коммуникационный хук принудительно использует обычный allreduce в течение первых
state.start_powerSGD_iterитераций. Это не только даёт пользователю больше контроля над компромиссом между ускорением и точностью, но и позволяет упростить некоторые аспекты внутренней оптимизации DDP для разработчиков будущих коммуникационных хуков.- Параметры:
-
-
state (PowerSGDState) – Информация о состоянии для настройки степени сжатия и поддержки обратной связи по ошибке, тёплого запуска и т. д. Для настройки параметров сжатия в первую очередь необходимо настроить
matrix_approximation_rank,start_powerSGD_iterиmin_compression_rate. - bucket (dist.GradBucket) – Корзина, в которой хранится одномерный развёрнутый тензор градиентов, объединяющий несколько тензоров отдельных переменных. Обратите внимание: поскольку коммуникационный хук DDP поддерживает только режим с одним процессом и одним устройством, в этой корзине хранится ровно один тензор.
-
state (PowerSGDState) – Информация о состоянии для настройки степени сжатия и поддержки обратной связи по ошибке, тёплого запуска и т. д. Для настройки параметров сжатия в первую очередь необходимо настроить
- Возвращает:
-
Обработчик Future для коммуникации, который обновляет градиенты на месте.
- Тип возвращаемого значения:
- Пример::
-
>>> state = PowerSGDState(process_group=process_group, matrix_approximation_rank=1, start_powerSGD_iter=10, min_compression_rate=0.5) >>> ddp_model.register_comm_hook(state, powerSGD_hook)
-
-
torch.distributed.algorithms.ddp_comm_hooks.powerSGD_hook.batched_powerSGD_hook(state, bucket)[исходный код] -
Реализует упрощённый алгоритм PowerSGD.
Этот коммуникационный хук DDP реализует упрощённый алгоритм сжатия градиентов PowerSGD, описанный в статье. Этот вариант не сжимает градиенты по слоям, а вместо этого сжимает развёрнутый входной тензор, объединяющий все градиенты. Поэтому он быстрее, чем
powerSGD_hook(), но обычно обеспечивает значительно более низкую точность, если толькоmatrix_approximation_rankне равно 1.Предупреждение
Увеличение
matrix_approximation_rankздесь не обязательно повысит точность, поскольку объединение тензоров отдельных параметров без выравнивания по столбцам и строкам может разрушить структуру низкого ранга. Поэтому пользователю всегда следует в первую очередь рассматриватьpowerSGD_hook()и переходить к этому варианту, только если приmatrix_approximation_rank, равном 1, удаётся достичь удовлетворительной точности.После того как градиентные тензоры собраны со всех рабочих процессов, хук выполняет сжатие следующим образом:
- Интерпретирует входной одномерный развёрнутый тензор градиентов как квадратный тензор M, дополняя его нулями;
- Создаёт два тензора низкого ранга P и Q для разложения M, так что M = PQ^T; Q инициализируется из стандартного нормального распределения и ортогонализуется;
- Вычисляет P, равный MQ;
- Выполняет allreduce для P;
- Ортогонализует P;
- Вычисляет Q, приблизительно равный M^TP;
- Выполняет allreduce для Q;
- Вычисляет M, приблизительно равный PQ^T.
- Усекает входной тензор до исходной длины.
Обратите внимание, что этот коммуникационный хук принудительно использует обычный allreduce в течение первых
state.start_powerSGD_iterитераций. Это не только даёт пользователю больше контроля над компромиссом между ускорением и точностью, но и позволяет упростить некоторые аспекты внутренней оптимизации DDP для разработчиков будущих коммуникационных хуков.- Параметры:
-
-
state (PowerSGDState) – Информация о состоянии для настройки степени сжатия и поддержки обратной связи по ошибке, тёплого запуска и т. д. Для настройки параметров сжатия в первую очередь необходимо настроить
matrix_approximation_rankиstart_powerSGD_iter. - bucket (dist.GradBucket) – Корзина, в которой хранится одномерный развёрнутый тензор градиентов, объединяющий несколько тензоров отдельных переменных. Обратите внимание: поскольку коммуникационный хук DDP поддерживает только режим с одним процессом и одним устройством, в этой корзине хранится ровно один тензор.
-
state (PowerSGDState) – Информация о состоянии для настройки степени сжатия и поддержки обратной связи по ошибке, тёплого запуска и т. д. Для настройки параметров сжатия в первую очередь необходимо настроить
- Возвращает:
-
Обработчик Future для коммуникации, который обновляет градиенты на месте.
- Тип возвращаемого значения:
- Пример::
-
>>> state = PowerSGDState(process_group=process_group, matrix_approximation_rank=1) >>> ddp_model.register_comm_hook(state, batched_powerSGD_hook)
Отладка коммуникационных хуков
Как следует из названия, отладочные коммуникационные хуки используются только для отладки и оптимизации производительности.
Предупреждение
Отладочные коммуникационные хуки не обязательно выдают корректные результаты.
-
torch.distributed.algorithms.ddp_comm_hooks.debugging_hooks.noop_hook(_, bucket)[исходный код] -
Возвращает Future, оборачивающий входное значение, и ничего не делает, не создавая накладных расходов на коммуникацию.
Этот хук следует использовать только для анализа потенциального ускорения при оптимизации allreduce, а не для обычной синхронизации градиентов. Например, если после регистрации этого хука удаётся добиться ускорения обучения менее чем на 10%, это обычно означает, что allreduce не является узким местом производительности в данном случае. Такая инструментация может быть особенно полезна, если трассировки GPU трудно получить или их анализ усложнён такими факторами, как перекрытие allreduce с вычислениями или рассинхронизация между рангами.
- Пример::
-
>>> ddp_model.register_comm_hook(None, noop_hook)
Создание контрольных точек коммуникационных хуков
Коммуникационный хук с сохранением состояния можно сохранить вместе с контрольной точкой модели, чтобы иметь возможность перезапустить обучение. Чтобы сделать хук сериализуемым, необходимо определить __setstate__ и __getstate__.
Предупреждение
__getstate__ должен исключать из возвращаемого словаря несериализуемые атрибуты.
Предупреждение
__setstate__ должен корректно инициализировать несериализуемые атрибуты, исключённые из предоставленного state.
В PowerSGDState реализованы __setstate__ и __getstate__; его можно использовать в качестве примера.
- классtorch.distributed.algorithms.ddp_comm_hooks.powerSGD_hook.PowerSGDState[исходный код]
-
-
__getstate__()[исходный код] -
Возвращает
Dict[str, Any], который будет сериализован с помощью pickle и сохранён.process_groupне сериализуется и исключается из возвращаемого состояния.
-
__setstate__(state)[исходный код] -
Принимает предоставленный
stateи устанавливает его для этого экземпляраPowerSGDState.Для
process_groupустанавливается значение по умолчанию.
-
Ниже приведён простой сквозной пример сохранения и повторной загрузки состояния и хука PowerSGD.
import os
import sys
import tempfile
import torch
import torch.distributed as dist
import torch.nn as nn
import torch.optim as optim
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel
from torch.distributed.algorithms.ddp_comm_hooks import powerSGD_hook as powerSGD
class SimpleModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(24,24)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(24,12)
def forward(self, x):
return self.fc2(self.relu(self.fc1(x)))
def setup(rank, world_size):
os.environ['MASTER_ADDR'] = 'localhost'
os.environ['MASTER_PORT'] = '12355'
# initialize the process group
dist.init_process_group("nccl", rank=rank, world_size=world_size)
def cleanup():
dist.destroy_process_group()
def run_demo(demo_fn, world_size):
mp.spawn(
demo_fn,
args=(world_size,),
nprocs=world_size,
join=True)
def demo_serialization(rank, world_size):
setup(rank, world_size)
CHECKPOINT = tempfile.gettempdir() + "/checkpoint.pt"
model = SimpleModel().to(rank)
ddp_model = DistributedDataParallel(model, device_ids=[rank])
powersgd_hook = powerSGD.powerSGD_hook
powersgd_state = powerSGD.PowerSGDState(process_group=None)
optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)
ddp_model.register_comm_hook(powersgd_state, powersgd_hook)
state = {
'state_dict': ddp_model.state_dict(),
'comm_hook': powersgd_hook,
'comm_hook_state': powersgd_state}
if rank == 0:
torch.save(state, CHECKPOINT)
dist.barrier()
map_location = {'cuda:%d' % 0: 'cuda:%d' % rank}
checkpoint = torch.load(CHECKPOINT, map_location=map_location)
new_ddp_model = DistributedDataParallel(SimpleModel().to(rank), device_ids=[rank])
new_ddp_model.load_state_dict(checkpoint['state_dict'])
powersgd_hook = checkpoint['comm_hook']
powersgd_state = checkpoint['comm_hook_state']
new_ddp_model.register_comm_hook(powersgd_state, powersgd_hook)
if rank == 0:
os.remove(CHECKPOINT)
cleanup()
if __name__ == "__main__":
n_gpus = torch.cuda.device_count()
assert n_gpus >= 2, f"Requires at least 2 GPUs to run, but got {n_gpus}"
world_size = n_gpus
run_demo(demo_serialization, world_size)
Благодарности
Большое спасибо автору статьи о PowerSGD Thijs Vogels за проверку кода коммуникационного хука PowerSGD, а также за сравнительные эксперименты, которые показывают, что производительность коммуникационного хука PowerSGD сопоставима с реализацией из оригинальной статьи.
© 2026, PyTorch Contributors
PyTorch has a BSD-style license, as found in the LICENSE file.
https://docs.pytorch.org/docs/2.14/ddp_comm_hooks.html