Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/torch/distributed/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/__pycache__/_state_dict_utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/__pycache__/argparse_util.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/__pycache__/launch.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/__pycache__/logging_handlers.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/__pycache__/remote_device.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/__pycache__/run.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/__pycache__/utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/_composable/__init__.py +3 -0
- lib/python3.12/site-packages/torch/distributed/_composable/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/_composable/__pycache__/checkpoint_activation.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/_composable/__pycache__/contract.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/_composable/__pycache__/replicate.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/_composable/checkpoint_activation.py +126 -0
- lib/python3.12/site-packages/torch/distributed/_composable/contract.py +224 -0
- lib/python3.12/site-packages/torch/distributed/_composable/fsdp/__init__.py +3 -0
- lib/python3.12/site-packages/torch/distributed/_composable/fsdp/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/_composable/fsdp/__pycache__/fully_shard.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/_composable/fsdp/fully_shard.py +8 -0
- lib/python3.12/site-packages/torch/distributed/_composable/replicate.py +254 -0
- lib/python3.12/site-packages/torch/distributed/_sharded_tensor/__init__.py +21 -0
- lib/python3.12/site-packages/torch/distributed/_sharded_tensor/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/__init__.py +1 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/__pycache__/join.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_checkpoint/__init__.py +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_checkpoint/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_checkpoint/__pycache__/checkpoint_wrapper.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_checkpoint/checkpoint_wrapper.py +323 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_comm_hooks/__init__.py +7 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_comm_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_comm_hooks/__pycache__/default_hooks.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_comm_hooks/default_hooks.py +192 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_optimizer_overlap/__init__.py +1 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_optimizer_overlap/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_optimizer_overlap/__pycache__/optimizer_overlap.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_optimizer_overlap/optimizer_overlap.py +97 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_quantization/__init__.py +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_quantization/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_quantization/__pycache__/quantization.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/_quantization/quantization.py +150 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__init__.py +110 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/ddp_zero_hook.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/debugging_hooks.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/default_hooks.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/mixed_precision_hooks.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/optimizer_overlap_hooks.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/post_localSGD_hook.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/powerSGD_hook.cpython-312.pyc +0 -0
lib/python3.12/site-packages/torch/distributed/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (6.1 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/__pycache__/_state_dict_utils.cpython-312.pyc
ADDED
|
Binary file (30 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/__pycache__/argparse_util.cpython-312.pyc
ADDED
|
Binary file (4.53 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/__pycache__/launch.cpython-312.pyc
ADDED
|
Binary file (8.16 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/__pycache__/logging_handlers.cpython-312.pyc
ADDED
|
Binary file (529 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/__pycache__/remote_device.cpython-312.pyc
ADDED
|
Binary file (5.77 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/__pycache__/run.cpython-312.pyc
ADDED
|
Binary file (35.7 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/__pycache__/utils.cpython-312.pyc
ADDED
|
Binary file (18.5 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/_composable/__init__.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .checkpoint_activation import checkpoint
|
| 2 |
+
from .contract import _get_registry, contract
|
| 3 |
+
from .replicate import replicate
|
lib/python3.12/site-packages/torch/distributed/_composable/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (356 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/_composable/__pycache__/checkpoint_activation.cpython-312.pyc
ADDED
|
Binary file (6.28 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/_composable/__pycache__/contract.cpython-312.pyc
ADDED
|
Binary file (9.14 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/_composable/__pycache__/replicate.cpython-312.pyc
ADDED
|
Binary file (10.9 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/_composable/checkpoint_activation.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# mypy: allow-untyped-decorators
|
| 2 |
+
# mypy: allow-untyped-defs
|
| 3 |
+
from contextlib import contextmanager, nullcontext
|
| 4 |
+
from typing import Any, ContextManager, Dict, Optional, Tuple
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
import torch.nn as nn
|
| 8 |
+
from torch.utils.checkpoint import (
|
| 9 |
+
_checkpoint_without_reentrant_generator,
|
| 10 |
+
_DEFAULT_DETERMINISM_MODE,
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
from .contract import contract
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
@contextmanager
|
| 17 |
+
def _no_hook(module: nn.Module, user_ctx: Optional[ContextManager] = None):
|
| 18 |
+
r"""
|
| 19 |
+
Disable hooks installed by checkpoint to avoid unintentional recursion
|
| 20 |
+
during backward recomputation.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
with user_ctx if user_ctx else nullcontext():
|
| 24 |
+
orig_enable_hook = checkpoint.state(module).enable_hook
|
| 25 |
+
checkpoint.state(module).enable_hook = False
|
| 26 |
+
try:
|
| 27 |
+
yield
|
| 28 |
+
finally:
|
| 29 |
+
checkpoint.state(module).enable_hook = orig_enable_hook
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
@contract()
|
| 33 |
+
def checkpoint(module: nn.Module, **kwargs) -> nn.Module:
|
| 34 |
+
r"""
|
| 35 |
+
This is a composable activation checkpointing API. Unlike functional
|
| 36 |
+
activation checkpointing APIs, this one does not require changing model
|
| 37 |
+
source code. Unlike ``nn.Module`` wrapper activation checkpointing APIs,
|
| 38 |
+
this one does not modify model structure or fully-qualified names either.
|
| 39 |
+
Under the hood, it registers activation checkpointing logic as pre- and
|
| 40 |
+
post-forward hooks. Hence, this API can be easily applied to any model or
|
| 41 |
+
sub-modules in the model.
|
| 42 |
+
|
| 43 |
+
Args:
|
| 44 |
+
module (nn.Module): the target model or sub-module to apply activation
|
| 45 |
+
checkpointing.
|
| 46 |
+
|
| 47 |
+
Example::
|
| 48 |
+
>>> # xdoctest: +SKIP
|
| 49 |
+
>>> import torch.nn as nn
|
| 50 |
+
>>>
|
| 51 |
+
>>> class MyModel(nn.Module):
|
| 52 |
+
>>> def __init__(self) -> None:
|
| 53 |
+
>>> super().__init__()
|
| 54 |
+
>>> self.l1 = nn.Linear(10, 10)
|
| 55 |
+
>>> self.l2 = nn.Linear(10, 10)
|
| 56 |
+
>>>
|
| 57 |
+
>>> def forward(self, x):
|
| 58 |
+
>>> return self.l2(self.l1(x))
|
| 59 |
+
>>>
|
| 60 |
+
>>> model = MyModel()
|
| 61 |
+
>>> checkpoint(model.l1) # apply activation checkpointing only to l1
|
| 62 |
+
>>> model(torch.zeros(2, 10)).sum().backward()
|
| 63 |
+
|
| 64 |
+
"""
|
| 65 |
+
torch._C._log_api_usage_once("torch.distributed.checkpoint")
|
| 66 |
+
|
| 67 |
+
use_reentrant = kwargs.pop("use_reentrant", False)
|
| 68 |
+
if use_reentrant:
|
| 69 |
+
raise NotImplementedError(
|
| 70 |
+
"use_reentrant=True is not supported in composable checkpoint. "
|
| 71 |
+
"Please use torch.utils.checkpoint.checkpoint instead."
|
| 72 |
+
)
|
| 73 |
+
preserve_rng_state = kwargs.pop("preserve_rng_state", True)
|
| 74 |
+
user_context_fns = kwargs.pop("context_fn", None)
|
| 75 |
+
determinism_check = kwargs.pop("determinism_check", _DEFAULT_DETERMINISM_MODE)
|
| 76 |
+
debug = kwargs.pop("debug", False)
|
| 77 |
+
|
| 78 |
+
if kwargs:
|
| 79 |
+
raise ValueError(
|
| 80 |
+
"Unexpected keyword arguments: " + ",".join(arg for arg in kwargs)
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
def forward_pre_hook(
|
| 84 |
+
module: nn.Module, args: Tuple[Any, ...], kwargs: Dict[str, Any]
|
| 85 |
+
) -> None:
|
| 86 |
+
if checkpoint.state(module).enable_hook:
|
| 87 |
+
|
| 88 |
+
def context_fns():
|
| 89 |
+
if user_context_fns is not None:
|
| 90 |
+
ctx1, ctx2 = user_context_fns()
|
| 91 |
+
return ctx1, _no_hook(module, ctx2)
|
| 92 |
+
else:
|
| 93 |
+
return nullcontext(), _no_hook(module)
|
| 94 |
+
|
| 95 |
+
checkpoint.state(
|
| 96 |
+
module
|
| 97 |
+
)._ac_generator = _checkpoint_without_reentrant_generator(
|
| 98 |
+
module,
|
| 99 |
+
preserve_rng_state,
|
| 100 |
+
context_fns,
|
| 101 |
+
determinism_check,
|
| 102 |
+
debug,
|
| 103 |
+
*args,
|
| 104 |
+
**kwargs,
|
| 105 |
+
)
|
| 106 |
+
next(checkpoint.state(module)._ac_generator)
|
| 107 |
+
|
| 108 |
+
def forward_hook(module: nn.Module, inputs: Tuple[Any, ...], output: Any) -> Any:
|
| 109 |
+
if checkpoint.state(module).enable_hook:
|
| 110 |
+
try:
|
| 111 |
+
next(checkpoint.state(module)._ac_generator)
|
| 112 |
+
except StopIteration:
|
| 113 |
+
pass
|
| 114 |
+
else:
|
| 115 |
+
raise RuntimeError(
|
| 116 |
+
"Expected non-reentrant activation checkpoint generator to be exhausted, but it was not!"
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
# Ensure that we no longer hold on to the generator. always_call=True helps ensure we
|
| 120 |
+
# clear this even in the case of exception in fwd pass.
|
| 121 |
+
checkpoint.state(module)._ac_generator = None
|
| 122 |
+
|
| 123 |
+
checkpoint.state(module).enable_hook = True
|
| 124 |
+
module.register_forward_pre_hook(forward_pre_hook, with_kwargs=True)
|
| 125 |
+
module.register_forward_hook(forward_hook, prepend=True, always_call=True)
|
| 126 |
+
return module
|
lib/python3.12/site-packages/torch/distributed/_composable/contract.py
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# mypy: allow-untyped-defs
|
| 2 |
+
import uuid
|
| 3 |
+
from collections import OrderedDict
|
| 4 |
+
from functools import wraps
|
| 5 |
+
from typing import Callable, Dict, List, Optional, Sequence, Type, Union
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
import torch.nn as nn
|
| 9 |
+
from torch.distributed._composable_state import _State
|
| 10 |
+
from torch.distributed.utils import _get_root_modules
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def generate_state_key(string="__composable_api_state_key"):
|
| 14 |
+
return f"{string}_{str(uuid.uuid4())}"
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
STATE_KEY = generate_state_key()
|
| 18 |
+
REGISTRY_KEY = generate_state_key()
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
# TODO: we can add additional info to RegistryItem to share across APIs. E.g.,
|
| 22 |
+
# we can add args and kwargs here, and then we can detect whether fully_shard
|
| 23 |
+
# is combined with reentrant activation checkpointing and error out with a clear
|
| 24 |
+
# message.
|
| 25 |
+
class RegistryItem:
|
| 26 |
+
pass
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def contract(state_cls: Type[_State] = _State):
|
| 30 |
+
r"""
|
| 31 |
+
Decorate a function as a composable distributed API, where the first
|
| 32 |
+
argument of the function must be an :class:`nn.Module` instance or sequence
|
| 33 |
+
of :class:`nn.Module` instances.
|
| 34 |
+
|
| 35 |
+
The decorator verifies that the decorated function does not modify
|
| 36 |
+
fully-qualified names (FQNs) for parameters, buffers, or modules. The
|
| 37 |
+
decorated function can return different module instances than the input
|
| 38 |
+
modules; the FQN invariant will be enforced following the input order.
|
| 39 |
+
|
| 40 |
+
When a function ``func`` is decorated by ``@contract()``, a
|
| 41 |
+
``.state(module: nn.Module)`` method will be installed to the decorated
|
| 42 |
+
function. Then you can retrieve and modify the state on a module by calling
|
| 43 |
+
``func.state(module)``.
|
| 44 |
+
|
| 45 |
+
Example::
|
| 46 |
+
>>> # xdoctest: +SKIP
|
| 47 |
+
>>> import torch.nn as nn
|
| 48 |
+
>>>
|
| 49 |
+
>>> class MyModel(nn.Module):
|
| 50 |
+
>>> def __init__(self) -> None:
|
| 51 |
+
>>> super().__init__()
|
| 52 |
+
>>> self.l1 = nn.Linear(10, 10)
|
| 53 |
+
>>> self.l2 = nn.Linear(10, 10)
|
| 54 |
+
>>>
|
| 55 |
+
>>> def forward(self, x):
|
| 56 |
+
>>> return self.l2(self.l1(x))
|
| 57 |
+
>>>
|
| 58 |
+
>>> @contract()
|
| 59 |
+
>>> def my_feature(module: nn.Module) -> nn.Module:
|
| 60 |
+
>>> my_feature.state(module).some_state = "any value"
|
| 61 |
+
>>> return module
|
| 62 |
+
>>>
|
| 63 |
+
>>> model = MyModel()
|
| 64 |
+
>>> my_feature(model.l1)
|
| 65 |
+
>>> assert my_feature.state(model.l1).some_state == "any value"
|
| 66 |
+
>>> my_feature(model.l2)
|
| 67 |
+
>>> model(torch.randn(2, 10)).sum().backward()
|
| 68 |
+
"""
|
| 69 |
+
|
| 70 |
+
# wraps will make functions decorated with contract() pickleable - needed for integration with torch.package
|
| 71 |
+
@wraps(state_cls)
|
| 72 |
+
def inner(func):
|
| 73 |
+
@wraps(func)
|
| 74 |
+
def wrapper(
|
| 75 |
+
module: Union[nn.Module, Sequence[nn.Module]], *args, **kwargs
|
| 76 |
+
) -> Optional[nn.Module]:
|
| 77 |
+
inp_module = module
|
| 78 |
+
if isinstance(module, nn.Module):
|
| 79 |
+
modules = [module]
|
| 80 |
+
else:
|
| 81 |
+
# If the user passes a sequence of modules, then we assume that
|
| 82 |
+
# we only need to insert the state object on the root modules
|
| 83 |
+
# (i.e. those without a parent) among the passed-in modules.
|
| 84 |
+
modules = _get_root_modules(list(module))
|
| 85 |
+
state = state_cls() # shared across all modules
|
| 86 |
+
registry_item = RegistryItem() # shared across all modules
|
| 87 |
+
|
| 88 |
+
# `func` is allowed to return different module instances than the
|
| 89 |
+
# input modules as long as FQNs are preserved following the input
|
| 90 |
+
# module order
|
| 91 |
+
all_orig_named_params: List[Dict[str, nn.Parameter]] = []
|
| 92 |
+
all_orig_named_buffers: List[Dict[str, torch.Tensor]] = []
|
| 93 |
+
all_orig_named_modules: List[Dict[str, nn.Module]] = []
|
| 94 |
+
|
| 95 |
+
for module in modules:
|
| 96 |
+
default_all_state: Dict[Callable, _State] = OrderedDict()
|
| 97 |
+
default_registry: Dict[str, RegistryItem] = OrderedDict()
|
| 98 |
+
all_state: Dict[Callable, _State] = module.__dict__.setdefault( # type: ignore[call-overload]
|
| 99 |
+
STATE_KEY, default_all_state
|
| 100 |
+
)
|
| 101 |
+
if not isinstance(all_state, dict):
|
| 102 |
+
raise AssertionError(
|
| 103 |
+
f"Distributed composable API states corrupted: {all_state}"
|
| 104 |
+
)
|
| 105 |
+
registry: Dict[str, RegistryItem] = module.__dict__.setdefault( # type: ignore[call-overload]
|
| 106 |
+
REGISTRY_KEY, default_registry
|
| 107 |
+
)
|
| 108 |
+
if not isinstance(registry, dict):
|
| 109 |
+
raise AssertionError(
|
| 110 |
+
f"Distributed composable API registry corrupted: {registry}"
|
| 111 |
+
)
|
| 112 |
+
if func in all_state or func.__name__ in registry:
|
| 113 |
+
raise AssertionError(
|
| 114 |
+
"Each distinct composable distributed API can only be applied to a "
|
| 115 |
+
f"module once. {func.__name__} has already been applied to the "
|
| 116 |
+
f"following module:\n{module}"
|
| 117 |
+
)
|
| 118 |
+
all_state.setdefault(func, state)
|
| 119 |
+
registry.setdefault(func.__name__, registry_item)
|
| 120 |
+
|
| 121 |
+
all_orig_named_params.append(OrderedDict(module.named_parameters()))
|
| 122 |
+
all_orig_named_buffers.append(OrderedDict(module.named_buffers()))
|
| 123 |
+
all_orig_named_modules.append(OrderedDict(module.named_modules()))
|
| 124 |
+
|
| 125 |
+
updated = func(inp_module, *args, **kwargs)
|
| 126 |
+
if updated is None:
|
| 127 |
+
updated = inp_module
|
| 128 |
+
if isinstance(updated, nn.Module):
|
| 129 |
+
updated_modules = [updated]
|
| 130 |
+
else:
|
| 131 |
+
updated_modules = _get_root_modules(list(inp_module)) # type: ignore[arg-type]
|
| 132 |
+
|
| 133 |
+
all_new_named_params: List[Dict[str, nn.Parameter]] = []
|
| 134 |
+
all_new_named_buffers: List[Dict[str, torch.Tensor]] = []
|
| 135 |
+
all_new_named_modules: List[Dict[str, nn.Module]] = []
|
| 136 |
+
for module in updated_modules:
|
| 137 |
+
all_new_named_params.append(OrderedDict(module.named_parameters()))
|
| 138 |
+
all_new_named_buffers.append(OrderedDict(module.named_buffers()))
|
| 139 |
+
all_new_named_modules.append(OrderedDict(module.named_modules()))
|
| 140 |
+
|
| 141 |
+
num_orig_modules = len(all_orig_named_modules)
|
| 142 |
+
num_new_modules = len(all_new_named_modules)
|
| 143 |
+
if num_orig_modules != num_new_modules:
|
| 144 |
+
raise AssertionError(
|
| 145 |
+
f"{func.__name__} should return the same number of modules as input modules"
|
| 146 |
+
f"Inputs: {num_orig_modules} modules\n"
|
| 147 |
+
f"Outputs: {num_new_modules} modules"
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
def check_fqn(orig_fqns: List[str], new_fqns: List[str], check_key: str):
|
| 151 |
+
if orig_fqns == new_fqns:
|
| 152 |
+
return
|
| 153 |
+
|
| 154 |
+
orig_fqn_set, new_fqn_set = set(orig_fqns), set(new_fqns)
|
| 155 |
+
orig_only = orig_fqn_set - new_fqn_set
|
| 156 |
+
new_only = new_fqn_set - orig_fqn_set
|
| 157 |
+
if len(orig_only) or len(new_only):
|
| 158 |
+
raise RuntimeError(
|
| 159 |
+
f"{check_key}"
|
| 160 |
+
"Composable distributed API implementations cannot modify FQNs.\n"
|
| 161 |
+
f"FQNs only in original: {orig_only}\n"
|
| 162 |
+
f"FQNs only in new: {new_only}"
|
| 163 |
+
)
|
| 164 |
+
else:
|
| 165 |
+
raise RuntimeError(
|
| 166 |
+
f"{check_key}"
|
| 167 |
+
"Composable distributed API implementations cannot modify "
|
| 168 |
+
"the order of FQNs.\n"
|
| 169 |
+
f"Original FQNs: {orig_only}\n"
|
| 170 |
+
f"New FQNs: {new_only}"
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
for orig_named_params, new_named_params in zip(
|
| 174 |
+
all_orig_named_params, all_new_named_params
|
| 175 |
+
):
|
| 176 |
+
check_fqn(
|
| 177 |
+
list(orig_named_params.keys()),
|
| 178 |
+
list(new_named_params.keys()),
|
| 179 |
+
"Checking parameters: ",
|
| 180 |
+
)
|
| 181 |
+
for orig_named_buffers, new_named_buffers in zip(
|
| 182 |
+
all_orig_named_buffers, all_new_named_buffers
|
| 183 |
+
):
|
| 184 |
+
check_fqn(
|
| 185 |
+
list(orig_named_buffers.keys()),
|
| 186 |
+
list(new_named_buffers.keys()),
|
| 187 |
+
"Checking buffers: ",
|
| 188 |
+
)
|
| 189 |
+
for orig_named_modules, new_named_modules in zip(
|
| 190 |
+
all_orig_named_modules, all_new_named_modules
|
| 191 |
+
):
|
| 192 |
+
check_fqn(
|
| 193 |
+
list(orig_named_modules.keys()),
|
| 194 |
+
list(new_named_modules.keys()),
|
| 195 |
+
"Checking modules: ",
|
| 196 |
+
)
|
| 197 |
+
|
| 198 |
+
# TODO: verify that installed distributed paradigms are compatible with
|
| 199 |
+
# each other.
|
| 200 |
+
|
| 201 |
+
return updated
|
| 202 |
+
|
| 203 |
+
def get_state(module: nn.Module) -> Optional[_State]:
|
| 204 |
+
return module.__dict__.setdefault( # type: ignore[call-overload]
|
| 205 |
+
STATE_KEY,
|
| 206 |
+
{}, # TODO(@yhcharles): this is a temporary fix, need a better way
|
| 207 |
+
).get(
|
| 208 |
+
func
|
| 209 |
+
) # type: ignore[call-overload]
|
| 210 |
+
|
| 211 |
+
wrapper.state = get_state # type: ignore[attr-defined]
|
| 212 |
+
|
| 213 |
+
return wrapper
|
| 214 |
+
|
| 215 |
+
return inner
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
def _get_registry(module: nn.Module) -> Optional[Dict[str, RegistryItem]]:
|
| 219 |
+
r"""
|
| 220 |
+
Get an ``OrderedDict`` of composable APIs that have been applied to the
|
| 221 |
+
``module``, indexed by the API name. If no API has been applied, then this
|
| 222 |
+
returns ``None``.
|
| 223 |
+
"""
|
| 224 |
+
return getattr(module, REGISTRY_KEY, None)
|
lib/python3.12/site-packages/torch/distributed/_composable/fsdp/__init__.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from torch.distributed.fsdp import CPUOffloadPolicy, MixedPrecisionPolicy, OffloadPolicy
|
| 2 |
+
|
| 3 |
+
from .fully_shard import FSDPModule, fully_shard, register_fsdp_forward_method
|
lib/python3.12/site-packages/torch/distributed/_composable/fsdp/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (440 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/_composable/fsdp/__pycache__/fully_shard.cpython-312.pyc
ADDED
|
Binary file (368 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/_composable/fsdp/fully_shard.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# TODO: For backward compatibility, we are importing the public objects
|
| 2 |
+
# originally from this file.
|
| 3 |
+
from torch.distributed.fsdp import ( # noqa: F401
|
| 4 |
+
FSDPModule,
|
| 5 |
+
fully_shard,
|
| 6 |
+
register_fsdp_forward_method,
|
| 7 |
+
UnshardHandle,
|
| 8 |
+
)
|
lib/python3.12/site-packages/torch/distributed/_composable/replicate.py
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# mypy: allow-untyped-decorators
|
| 2 |
+
# mypy: allow-untyped-defs
|
| 3 |
+
import weakref
|
| 4 |
+
from typing import Any, cast, Dict, Iterable, List, NoReturn, Optional, Set, Tuple
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
import torch.nn as nn
|
| 8 |
+
from torch.distributed._composable_state import _State
|
| 9 |
+
from torch.nn.parallel import DistributedDataParallel
|
| 10 |
+
|
| 11 |
+
from .contract import _get_registry, contract
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
_ROOT_MODULE_PREFIX = ""
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class _ReplicateState(_State):
|
| 18 |
+
def __init__(self) -> None:
|
| 19 |
+
super().__init__()
|
| 20 |
+
self.module: nn.Module = nn.ParameterList()
|
| 21 |
+
self.has_initialized: bool = False
|
| 22 |
+
self._param_list: nn.ParameterList = nn.ParameterList()
|
| 23 |
+
# TODO(@fegin): this variable is originally create for testing, we
|
| 24 |
+
# should remove this if possible.
|
| 25 |
+
self._orig_module = self.module
|
| 26 |
+
self._param_names: List[str] = []
|
| 27 |
+
self._no_sync: bool = False
|
| 28 |
+
self._init_args: Optional[Tuple[Any, ...]] = None
|
| 29 |
+
self._init_kwargs: Dict[str, Any] = {}
|
| 30 |
+
self._comm_hook_args: List[Any] = []
|
| 31 |
+
|
| 32 |
+
def _collect_params(
|
| 33 |
+
self,
|
| 34 |
+
module: nn.Module,
|
| 35 |
+
ignored_modules: Set[nn.Module],
|
| 36 |
+
ignored_params: Set[nn.Parameter],
|
| 37 |
+
prefix: str = _ROOT_MODULE_PREFIX,
|
| 38 |
+
) -> None:
|
| 39 |
+
# skip if managed by fully_sharded API
|
| 40 |
+
if _is_fully_sharded(module):
|
| 41 |
+
return
|
| 42 |
+
|
| 43 |
+
# if a module is ignored, all descendants of the module are ignored.
|
| 44 |
+
if module in ignored_modules:
|
| 45 |
+
return
|
| 46 |
+
|
| 47 |
+
recurse_prefix = (
|
| 48 |
+
f"{prefix}." if prefix != _ROOT_MODULE_PREFIX else _ROOT_MODULE_PREFIX
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
for n, p in module.named_parameters(recurse=False):
|
| 52 |
+
if p not in ignored_params:
|
| 53 |
+
self._param_list.append(p)
|
| 54 |
+
self._param_names.append(f"{recurse_prefix}{n}")
|
| 55 |
+
|
| 56 |
+
for name, child_module in module.named_children():
|
| 57 |
+
self._collect_params(
|
| 58 |
+
child_module,
|
| 59 |
+
ignored_modules,
|
| 60 |
+
ignored_params,
|
| 61 |
+
prefix=f"{recurse_prefix}{name}",
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
def lazy_init(self) -> None:
|
| 65 |
+
@torch._disable_dynamo(recursive=True)
|
| 66 |
+
def _lazy_init():
|
| 67 |
+
assert self._init_args is not None
|
| 68 |
+
self.init(*self._init_args, **self._init_kwargs)
|
| 69 |
+
self.register_comm_hook()
|
| 70 |
+
self._init_args = ()
|
| 71 |
+
self._init_kwargs = {}
|
| 72 |
+
|
| 73 |
+
_lazy_init()
|
| 74 |
+
|
| 75 |
+
def init(
|
| 76 |
+
self,
|
| 77 |
+
module: nn.Module,
|
| 78 |
+
ignored_modules: Set[nn.Module],
|
| 79 |
+
**kwargs,
|
| 80 |
+
) -> None:
|
| 81 |
+
if self.has_initialized:
|
| 82 |
+
return
|
| 83 |
+
|
| 84 |
+
self.has_initialized = True
|
| 85 |
+
self.module = module
|
| 86 |
+
ignored_params = {p for m in ignored_modules for p in m.parameters()}
|
| 87 |
+
for submodule in module.modules():
|
| 88 |
+
if _is_fully_sharded(submodule):
|
| 89 |
+
ignored_params.update(submodule.parameters())
|
| 90 |
+
from torch.distributed.tensor.parallel.ddp import _localize_dtensor
|
| 91 |
+
|
| 92 |
+
_localize_dtensor(module, ignored_params=ignored_params)
|
| 93 |
+
self._collect_params(module, ignored_modules, ignored_params)
|
| 94 |
+
|
| 95 |
+
if "device_id" in kwargs:
|
| 96 |
+
# replicate() supports a small usability enhancement where
|
| 97 |
+
# user can pass in device_id as a Union[int, torch.device] even for
|
| 98 |
+
# CPU devices so users don't have to change code for CPU/GPU runs.
|
| 99 |
+
# We derive the right device_ids to feed into DDP to support this.
|
| 100 |
+
if kwargs["device_id"] is not None:
|
| 101 |
+
device_id = kwargs["device_id"]
|
| 102 |
+
# Convert to device_ids that DDP expects.
|
| 103 |
+
if isinstance(device_id, torch.device) and device_id.type == "cpu":
|
| 104 |
+
# CPU modules receive device_ids None
|
| 105 |
+
kwargs["device_ids"] = None
|
| 106 |
+
else:
|
| 107 |
+
# GPU modules expect device_ids=[cuda_device]
|
| 108 |
+
kwargs["device_ids"] = [device_id]
|
| 109 |
+
else:
|
| 110 |
+
kwargs["device_ids"] = None
|
| 111 |
+
kwargs.pop("device_id")
|
| 112 |
+
|
| 113 |
+
self._ddp = DistributedDataParallel(self._param_list, **kwargs)
|
| 114 |
+
# Weakref to the DDP instance is currently only used for testing.
|
| 115 |
+
replicate.state(self.module)._ddp_weakref = weakref.ref(self._ddp)
|
| 116 |
+
|
| 117 |
+
def register_comm_hook(self) -> None:
|
| 118 |
+
for comm_args, comm_kwargs in self._comm_hook_args:
|
| 119 |
+
self._ddp.register_comm_hook(*comm_args, **comm_kwargs)
|
| 120 |
+
self._comm_hook_args.clear()
|
| 121 |
+
|
| 122 |
+
def record_init_args(self, *args, **kwargs) -> None:
|
| 123 |
+
self._init_args = args
|
| 124 |
+
self._init_kwargs = kwargs
|
| 125 |
+
|
| 126 |
+
def forward_pre_hook(
|
| 127 |
+
self, module: nn.Module, args: Tuple[Any, ...], kwargs: Dict[str, Any]
|
| 128 |
+
) -> Any:
|
| 129 |
+
if self._init_args or self._init_kwargs:
|
| 130 |
+
self.lazy_init()
|
| 131 |
+
self._ddp.require_backward_grad_sync = not self._no_sync
|
| 132 |
+
return self._ddp._pre_forward(*args, **kwargs)
|
| 133 |
+
|
| 134 |
+
def forward_post_hook(
|
| 135 |
+
self,
|
| 136 |
+
module: nn.Module,
|
| 137 |
+
input: Tuple[torch.Tensor],
|
| 138 |
+
output: torch.Tensor,
|
| 139 |
+
) -> torch.Tensor:
|
| 140 |
+
return self._ddp._post_forward(output)
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def unimplemented_deepcopy(*args: Any, **kwargs: Any) -> NoReturn:
|
| 144 |
+
raise AssertionError(
|
| 145 |
+
"DDP does not support deepcopy. Please use state dict for serialization."
|
| 146 |
+
)
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
# Follow the same pattern as FSDP/fully_shard
|
| 150 |
+
class DDP:
|
| 151 |
+
def __new__(cls, *args, **kwargs):
|
| 152 |
+
"""
|
| 153 |
+
Override ``__new__`` to remove the DDP class and directly construct
|
| 154 |
+
the original class for cases like indexing into a container module.
|
| 155 |
+
"""
|
| 156 |
+
# Use index 2 since 0 is the dynamically constructed `DDP<...>` class
|
| 157 |
+
# and index 1 is the `DDP` class itself
|
| 158 |
+
orig_cls = cls.__mro__[2]
|
| 159 |
+
return orig_cls.__new__(orig_cls, *args, **kwargs)
|
| 160 |
+
|
| 161 |
+
def set_requires_gradient_sync(self, requires_gradient_sync: bool) -> None:
|
| 162 |
+
"""
|
| 163 |
+
Sets if the module should sync gradients. This can be used to implement
|
| 164 |
+
gradient accumulation without communication.
|
| 165 |
+
|
| 166 |
+
Args:
|
| 167 |
+
requires_gradient_sync (bool): Whether to reduce gradients for the
|
| 168 |
+
module's parameters.
|
| 169 |
+
"""
|
| 170 |
+
replicate.state(self)._no_sync = not requires_gradient_sync
|
| 171 |
+
|
| 172 |
+
def register_comm_hook(self, *args, **kwargs) -> None:
|
| 173 |
+
replicate.state(self)._comm_hook_args.append((args, kwargs))
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
@contract(state_cls=_ReplicateState)
|
| 177 |
+
def replicate(
|
| 178 |
+
module: nn.Module,
|
| 179 |
+
ignored_modules: Optional[Iterable[torch.nn.Module]] = None,
|
| 180 |
+
**kwargs,
|
| 181 |
+
) -> nn.Module:
|
| 182 |
+
r"""Replicates a module
|
| 183 |
+
|
| 184 |
+
Args:
|
| 185 |
+
module (torch.nn.Module): module to replicate
|
| 186 |
+
|
| 187 |
+
Example::
|
| 188 |
+
>>> # xdoctest: +REQUIRES(module:torch._C._distributed_c10d)
|
| 189 |
+
>>> module = nn.Linear(3, 3)
|
| 190 |
+
>>> replicate(module)
|
| 191 |
+
"""
|
| 192 |
+
torch._C._log_api_usage_once("torch.distributed.replicate")
|
| 193 |
+
|
| 194 |
+
# TODO(fegin): using kwargs is not a good idea if we would like to make
|
| 195 |
+
# replicate a formal API to replace DDP.
|
| 196 |
+
if "device_id" in kwargs:
|
| 197 |
+
if not isinstance(kwargs["device_id"], (int, torch.device)):
|
| 198 |
+
raise RuntimeError(
|
| 199 |
+
"Expected device_id to be int or torch.device, "
|
| 200 |
+
f"but got {type(kwargs['device_id'])}"
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
if _is_fully_sharded(module):
|
| 204 |
+
raise RuntimeError(
|
| 205 |
+
"Cannot apply `replicate()` on a Module already managed by `fully_shard`"
|
| 206 |
+
)
|
| 207 |
+
|
| 208 |
+
if ignored_modules is None:
|
| 209 |
+
ignored_modules = {}
|
| 210 |
+
else:
|
| 211 |
+
ignored_modules = set(ignored_modules)
|
| 212 |
+
|
| 213 |
+
state = cast(_ReplicateState, replicate.state(module))
|
| 214 |
+
module.register_forward_pre_hook(state.forward_pre_hook, with_kwargs=True)
|
| 215 |
+
device_mesh = kwargs.get("device_mesh", None)
|
| 216 |
+
if device_mesh is not None:
|
| 217 |
+
from torch.distributed.device_mesh import _mesh_resources
|
| 218 |
+
|
| 219 |
+
root_mesh = _mesh_resources.get_root_mesh(device_mesh)
|
| 220 |
+
# if a root mesh is not the same as device_mesh,
|
| 221 |
+
# meaning the device_mesh is sliced out from the root mesh.
|
| 222 |
+
if root_mesh != device_mesh:
|
| 223 |
+
# TODO: This is a temporary work around to enable DDP + TP.
|
| 224 |
+
# We should do the logic in DDP so that the 2D implementation is
|
| 225 |
+
# sound and the state_dict works out of the box.
|
| 226 |
+
#
|
| 227 |
+
# This won't conflict with what is done in DDP class as the module
|
| 228 |
+
# replicate is going to pass is NOT the original module.
|
| 229 |
+
from torch.distributed.tensor.parallel.ddp import (
|
| 230 |
+
_localize_dtensor,
|
| 231 |
+
_reconstruct_dtensor,
|
| 232 |
+
)
|
| 233 |
+
|
| 234 |
+
module.register_forward_pre_hook(_reconstruct_dtensor)
|
| 235 |
+
module.register_forward_hook(_localize_dtensor)
|
| 236 |
+
|
| 237 |
+
module.register_forward_hook(state.forward_post_hook) # type: ignore[arg-type]
|
| 238 |
+
|
| 239 |
+
state.record_init_args(module, ignored_modules, **kwargs)
|
| 240 |
+
|
| 241 |
+
# Place DDP leftmost for highest priority in the method resolution order
|
| 242 |
+
cls = module.__class__
|
| 243 |
+
dct = {"__deepcopy__": unimplemented_deepcopy}
|
| 244 |
+
new_cls = type(f"DDP{cls.__name__}", (DDP, cls), dct)
|
| 245 |
+
module.__class__ = new_cls
|
| 246 |
+
return module
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
def _is_fully_sharded(module: nn.Module) -> bool:
|
| 250 |
+
r"""Check if module is marked with fully_shard."""
|
| 251 |
+
registry = _get_registry(module)
|
| 252 |
+
if registry is None:
|
| 253 |
+
return False
|
| 254 |
+
return "fully_shard" in registry
|
lib/python3.12/site-packages/torch/distributed/_sharded_tensor/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Keep old package for BC purposes, this file should be removed once
|
| 2 |
+
# everything moves to the `torch.distributed._shard` package.
|
| 3 |
+
import sys
|
| 4 |
+
import warnings
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
from torch.distributed._shard.sharded_tensor import * # noqa: F403
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
with warnings.catch_warnings():
|
| 11 |
+
warnings.simplefilter("always")
|
| 12 |
+
warnings.warn(
|
| 13 |
+
"`torch.distributed._sharded_tensor` will be deprecated, "
|
| 14 |
+
"use `torch.distributed._shard.sharded_tensor` instead",
|
| 15 |
+
DeprecationWarning,
|
| 16 |
+
stacklevel=2,
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
sys.modules[
|
| 20 |
+
"torch.distributed._sharded_tensor"
|
| 21 |
+
] = torch.distributed._shard.sharded_tensor
|
lib/python3.12/site-packages/torch/distributed/_sharded_tensor/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (972 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
from .join import Join, Joinable, JoinHook
|
lib/python3.12/site-packages/torch/distributed/algorithms/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (284 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/__pycache__/join.cpython-312.pyc
ADDED
|
Binary file (15.5 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_checkpoint/__init__.py
ADDED
|
File without changes
|
lib/python3.12/site-packages/torch/distributed/algorithms/_checkpoint/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (219 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_checkpoint/__pycache__/checkpoint_wrapper.cpython-312.pyc
ADDED
|
Binary file (14 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_checkpoint/checkpoint_wrapper.py
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# mypy: allow-untyped-defs
|
| 2 |
+
import warnings
|
| 3 |
+
from abc import ABC, abstractmethod
|
| 4 |
+
from enum import auto, Enum
|
| 5 |
+
from functools import partial
|
| 6 |
+
from typing import Any, Callable, Dict, Iterator, Optional, Tuple
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn as nn
|
| 10 |
+
from torch.autograd.graph import save_on_cpu
|
| 11 |
+
from torch.distributed.utils import _pack_kwargs, _replace_by_prefix, _unpack_kwargs
|
| 12 |
+
from torch.utils.checkpoint import checkpoint as torch_utils_checkpoint
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
_CHECKPOINT_WRAPPED_MODULE = "_checkpoint_wrapped_module"
|
| 16 |
+
_CHECKPOINT_PREFIX = _CHECKPOINT_WRAPPED_MODULE + "."
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class CheckpointImpl(Enum):
|
| 20 |
+
REENTRANT = auto()
|
| 21 |
+
NO_REENTRANT = auto()
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class ActivationWrapper(torch.nn.Module, ABC):
|
| 25 |
+
"""
|
| 26 |
+
Base class for Activation Checkpoint and Activation Offload.
|
| 27 |
+
|
| 28 |
+
Not meant to be instantiated directly.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
def __init__(self, mod):
|
| 32 |
+
super().__init__()
|
| 33 |
+
self._checkpoint_wrapped_module = mod
|
| 34 |
+
# state_dict post hook to remove prefix to allow loading into a
|
| 35 |
+
# non-checkpoint wrapped module.
|
| 36 |
+
self._register_state_dict_hook(self._post_state_dict_hook)
|
| 37 |
+
# load_state_dict pre-hook to allow loading back into
|
| 38 |
+
# checkpoint-wrapped module.
|
| 39 |
+
self.register_load_state_dict_pre_hook(self._pre_load_state_dict_hook)
|
| 40 |
+
|
| 41 |
+
@abstractmethod
|
| 42 |
+
def forward(self, *args, **kwargs):
|
| 43 |
+
raise ValueError("Subclasses should implement forward().")
|
| 44 |
+
|
| 45 |
+
def __getattr__(self, name: str) -> Any:
|
| 46 |
+
"""Forward missing attributes to wrapped module."""
|
| 47 |
+
try:
|
| 48 |
+
return super().__getattr__(name) # defer to nn.Module's logic
|
| 49 |
+
except AttributeError:
|
| 50 |
+
return getattr(self._checkpoint_wrapped_module, name)
|
| 51 |
+
|
| 52 |
+
def __getitem__(self, key: int) -> Any:
|
| 53 |
+
"""Forward indexing calls in case the module is a nn.Sequential."""
|
| 54 |
+
return self._checkpoint_wrapped_module.__getitem__(key) # type: ignore[operator]
|
| 55 |
+
|
| 56 |
+
def named_parameters(
|
| 57 |
+
self,
|
| 58 |
+
*args,
|
| 59 |
+
**kwargs,
|
| 60 |
+
) -> Iterator[Tuple[str, torch.nn.Parameter]]:
|
| 61 |
+
"""
|
| 62 |
+
Override :meth:`named_parameters()` to intercept parameter names.
|
| 63 |
+
|
| 64 |
+
remove all occurrences of ``_CHECKPOINT_PREFIX``.
|
| 65 |
+
"""
|
| 66 |
+
for param_name, param in super().named_parameters(*args, **kwargs):
|
| 67 |
+
yield param_name.replace(_CHECKPOINT_PREFIX, ""), param
|
| 68 |
+
|
| 69 |
+
@staticmethod
|
| 70 |
+
def _post_state_dict_hook(
|
| 71 |
+
module: nn.Module,
|
| 72 |
+
state_dict: Dict[str, Any],
|
| 73 |
+
prefix: str,
|
| 74 |
+
*args: Any,
|
| 75 |
+
) -> Dict[str, Any]:
|
| 76 |
+
"""
|
| 77 |
+
_post_state_dict_hook() is called after the state_dict() of this FSDP module is executed.
|
| 78 |
+
|
| 79 |
+
For ``checkpoint_wrapper``, it will strip checkpoint-wrapped module prefix,
|
| 80 |
+
so that this module can be loaded into non-checkpointed modules.
|
| 81 |
+
It would still be able to be loaded into checkpoint-wrapped modules as this class,
|
| 82 |
+
adds the prefix back before loading the state_dict.
|
| 83 |
+
"""
|
| 84 |
+
_replace_by_prefix(state_dict, f"{prefix}{_CHECKPOINT_PREFIX}", prefix)
|
| 85 |
+
return state_dict
|
| 86 |
+
|
| 87 |
+
@staticmethod
|
| 88 |
+
def _pre_load_state_dict_hook(
|
| 89 |
+
module: nn.Module,
|
| 90 |
+
state_dict: Dict[str, Any],
|
| 91 |
+
prefix: str,
|
| 92 |
+
*args: Any,
|
| 93 |
+
) -> None:
|
| 94 |
+
"""
|
| 95 |
+
``_pre_state_dict_hook` is called before ``self._load_from_state_dict()`` is called.
|
| 96 |
+
|
| 97 |
+
For ``checkpoint_wrapper``, it will add back the module
|
| 98 |
+
prefix so that non-checkpointed modules can be loaded into
|
| 99 |
+
checkpoint_wrapper modules properly.
|
| 100 |
+
"""
|
| 101 |
+
_replace_by_prefix(state_dict, prefix, prefix + f"{_CHECKPOINT_PREFIX}")
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class OffloadWrapper(ActivationWrapper):
|
| 105 |
+
def __init__(self, mod):
|
| 106 |
+
super().__init__(mod)
|
| 107 |
+
|
| 108 |
+
def forward(self, *args, **kwargs):
|
| 109 |
+
with save_on_cpu(pin_memory=True):
|
| 110 |
+
return self._checkpoint_wrapped_module(*args, **kwargs)
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
class CheckpointWrapper(ActivationWrapper):
|
| 114 |
+
"""
|
| 115 |
+
An ``nn.Module`` that wraps another ``nn.Module`` with checkpointing.
|
| 116 |
+
|
| 117 |
+
Note that this module is not meant to be used directly but instead,
|
| 118 |
+
it is to be used through the ``checkpoint_wrapper`` function.
|
| 119 |
+
"""
|
| 120 |
+
|
| 121 |
+
def __init__(
|
| 122 |
+
self,
|
| 123 |
+
mod: torch.nn.Module,
|
| 124 |
+
checkpoint_impl: CheckpointImpl = CheckpointImpl.NO_REENTRANT,
|
| 125 |
+
checkpoint_fn=None,
|
| 126 |
+
**checkpoint_fn_kwargs,
|
| 127 |
+
):
|
| 128 |
+
super().__init__(mod)
|
| 129 |
+
self.checkpoint_impl = checkpoint_impl
|
| 130 |
+
if checkpoint_fn is None:
|
| 131 |
+
# use torch.utils.checkpoint
|
| 132 |
+
self.checkpoint_fn = partial(
|
| 133 |
+
torch_utils_checkpoint,
|
| 134 |
+
use_reentrant=(self.checkpoint_impl == CheckpointImpl.REENTRANT),
|
| 135 |
+
**checkpoint_fn_kwargs,
|
| 136 |
+
)
|
| 137 |
+
else:
|
| 138 |
+
# Construct user-specified checkpoint function.
|
| 139 |
+
self.checkpoint_fn = partial(
|
| 140 |
+
checkpoint_fn,
|
| 141 |
+
**checkpoint_fn_kwargs,
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
def forward(self, *args, **kwargs):
|
| 145 |
+
# Support keyword arguments for reentrant checkpoint. Note that this
|
| 146 |
+
# only works if user has specified self.checkpoint_impl and is not
|
| 147 |
+
# using their own custom checkpoint_fn.
|
| 148 |
+
if self.checkpoint_impl == CheckpointImpl.REENTRANT and kwargs != {}:
|
| 149 |
+
# Pack the args and kwargs
|
| 150 |
+
flat_args, kwarg_keys = _pack_kwargs(*args, **kwargs)
|
| 151 |
+
|
| 152 |
+
# Function that only takes (packed) args, but can unpack them
|
| 153 |
+
# into the original args and kwargs for the checkpointed
|
| 154 |
+
# function, and runs that function.
|
| 155 |
+
def my_function(*inputs):
|
| 156 |
+
# unpack back into args and kwargs
|
| 157 |
+
unpacked_args, unpacked_kwargs = _unpack_kwargs(inputs, kwarg_keys)
|
| 158 |
+
# run original module
|
| 159 |
+
return self._checkpoint_wrapped_module(
|
| 160 |
+
*unpacked_args, **unpacked_kwargs
|
| 161 |
+
)
|
| 162 |
+
|
| 163 |
+
# Pass the function that only takes packed args into reentrant
|
| 164 |
+
# checkpoint API.
|
| 165 |
+
return self.checkpoint_fn( # type: ignore[misc]
|
| 166 |
+
my_function,
|
| 167 |
+
*flat_args,
|
| 168 |
+
)
|
| 169 |
+
else:
|
| 170 |
+
return self.checkpoint_fn( # type: ignore[misc]
|
| 171 |
+
self._checkpoint_wrapped_module, *args, **kwargs
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def offload_wrapper(module: torch.nn.Module) -> torch.nn.Module:
|
| 176 |
+
"""
|
| 177 |
+
Wrap a module for activation offloading to CPU.
|
| 178 |
+
|
| 179 |
+
Offloads intermediate activations to the CPU for modules wrapped with this function.
|
| 180 |
+
Wrappers with activation offload can be composed with ones that do recomputation-based
|
| 181 |
+
checkpoint to trade off increased compute versus increased CPU
|
| 182 |
+
memory usage and additional H2D transfers.
|
| 183 |
+
|
| 184 |
+
Usage::
|
| 185 |
+
offloaded_module = offload_wrapper(module)
|
| 186 |
+
outputs = checkpointed_module(inputs)
|
| 187 |
+
Args:
|
| 188 |
+
module (nn.Module):
|
| 189 |
+
The module to be wrapped
|
| 190 |
+
Returns:
|
| 191 |
+
(nn.Module):
|
| 192 |
+
Wrapped module
|
| 193 |
+
"""
|
| 194 |
+
return OffloadWrapper(module)
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def checkpoint_wrapper(
|
| 198 |
+
module: torch.nn.Module,
|
| 199 |
+
checkpoint_impl: CheckpointImpl = CheckpointImpl.NO_REENTRANT,
|
| 200 |
+
checkpoint_fn=None,
|
| 201 |
+
**checkpoint_fn_kwargs,
|
| 202 |
+
) -> torch.nn.Module:
|
| 203 |
+
"""
|
| 204 |
+
Wrap a module for activation checkpointing.
|
| 205 |
+
|
| 206 |
+
If the module is wrapped with this function, all subsequent calls to the module will,
|
| 207 |
+
automatically perform checkpointing without the user having to explicitly call ``checkpoint`` function.
|
| 208 |
+
|
| 209 |
+
Usage::
|
| 210 |
+
checkpointed_module = checkpoint_wrapper(module)
|
| 211 |
+
outputs = checkpointed_module(inputs)
|
| 212 |
+
Args:
|
| 213 |
+
module (nn.Module):
|
| 214 |
+
The module to be wrapped
|
| 215 |
+
checkpoint_impl (Optional[CheckpointImpl]):
|
| 216 |
+
The checkpointing implementation to use. Note that this will only
|
| 217 |
+
be passed into the ``torch.utils.checkpoint.checkpoint``
|
| 218 |
+
implementation, and is ignored if a custom ``checkpoint_fn`` is
|
| 219 |
+
specified. Note that for implementations using reentrant checkpoint
|
| 220 |
+
from ``torch.utils.checkpoint``, keyword arguments will only be
|
| 221 |
+
supported if ``checkpoint_impl`` is passed as ``CheckpointImpl.REENTRANT`.
|
| 222 |
+
checkpoint_fn (Optional[Callable]):
|
| 223 |
+
Functional checkpoint implementation to use. If this is specified,
|
| 224 |
+
it will be used over the default ``torch.utils.checkpoint.checkpoint``
|
| 225 |
+
implementation and the `checkpoint_impl` argument will be ignored.
|
| 226 |
+
**checkpoint_fn_kwargs: (Dict[str, Any]): Keyword arguments to pass into `checkpoint_fn`.
|
| 227 |
+
|
| 228 |
+
Returns:
|
| 229 |
+
(nn.Module):
|
| 230 |
+
Wrapped module
|
| 231 |
+
"""
|
| 232 |
+
|
| 233 |
+
if checkpoint_impl == CheckpointImpl.REENTRANT:
|
| 234 |
+
warnings.warn(
|
| 235 |
+
f"Please specify {CheckpointImpl.NO_REENTRANT} as "
|
| 236 |
+
f"{CheckpointImpl.REENTRANT} will soon be removed as "
|
| 237 |
+
"the default and eventually deprecated.",
|
| 238 |
+
FutureWarning,
|
| 239 |
+
stacklevel=2,
|
| 240 |
+
)
|
| 241 |
+
return CheckpointWrapper(
|
| 242 |
+
module,
|
| 243 |
+
checkpoint_impl,
|
| 244 |
+
checkpoint_fn,
|
| 245 |
+
**checkpoint_fn_kwargs,
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
def apply_activation_checkpointing(
|
| 250 |
+
model,
|
| 251 |
+
checkpoint_wrapper_fn=checkpoint_wrapper,
|
| 252 |
+
check_fn=lambda _: True,
|
| 253 |
+
auto_wrap_policy: Optional[Callable[[nn.Module, bool, int], bool]] = None,
|
| 254 |
+
):
|
| 255 |
+
"""
|
| 256 |
+
Apply :func:`checkpoint_wrapper` to modules within `model` based on a user-defined configuration.
|
| 257 |
+
|
| 258 |
+
For each module within `model`, the `check_fn` is used to decide
|
| 259 |
+
whether `module` should be wrapped with :func:`checkpoint_wrapper` or not.
|
| 260 |
+
|
| 261 |
+
Note::
|
| 262 |
+
This function modifies `model` in place and replaces appropriate layers with
|
| 263 |
+
their checkpoint-wrapped modules.
|
| 264 |
+
Note::
|
| 265 |
+
This function will not wrap the overall root module. If this is needed, please directly use
|
| 266 |
+
:func:`checkpoint_wrapper` or :func:`offload_wrapper`.
|
| 267 |
+
Usage::
|
| 268 |
+
model = nn.Sequential(
|
| 269 |
+
nn.Linear(10, 10), nn.Linear(10, 10), nn.Linear(10, 10)
|
| 270 |
+
)
|
| 271 |
+
check_fn = lambda l: isinstance(l, nn.Linear)
|
| 272 |
+
# checkpoint activations
|
| 273 |
+
apply_activation_checkpointing(model, checkpoint_wrapper_fn=checkpoint_wrapper, check_fn=check_fn)
|
| 274 |
+
# Or offload activations to CPU
|
| 275 |
+
apply_activation_checkpointing(model, checkpoint_wrapper_fn=offload_wrapper, check_fn=check_fn)
|
| 276 |
+
Args:
|
| 277 |
+
model (nn.Module):
|
| 278 |
+
The model whose submodules should be wrapped with activation checkpointing.
|
| 279 |
+
checkpoint_wrapper_fn (Optional[Callable[nn.Module]])
|
| 280 |
+
A ``Callable`` which will wrap modules
|
| 281 |
+
check_fn (Optional[Callable[nn.Module, nn.Module]])
|
| 282 |
+
A lambda function which will be passed each child submodule of ``model`` and returns
|
| 283 |
+
``True`` or ``False`` depending on whether the submodule should be wrapped.
|
| 284 |
+
auto_wrap_policy (Optional[Callable[[nn.Module, bool, int], bool]]): A policy to wrap model's
|
| 285 |
+
submodules with AC. Note that if this is specified, it takes precedence over ``check_fn``.
|
| 286 |
+
Returns: None (`model` is modified inplace)
|
| 287 |
+
"""
|
| 288 |
+
# TODO: Importing inside function to avoid circular import issue between FSDP and
|
| 289 |
+
# checkpoint_wrapper. This can be resolved once wrap() APIs are decoupled from FSDP code.
|
| 290 |
+
from torch.distributed.fsdp._wrap_utils import _construct_wrap_fn, _post_order_apply
|
| 291 |
+
from torch.distributed.fsdp.wrap import (
|
| 292 |
+
_Policy,
|
| 293 |
+
_recursive_wrap,
|
| 294 |
+
lambda_auto_wrap_policy,
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
policy = (
|
| 298 |
+
auto_wrap_policy
|
| 299 |
+
if auto_wrap_policy is not None
|
| 300 |
+
else partial(lambda_auto_wrap_policy, lambda_fn=check_fn)
|
| 301 |
+
)
|
| 302 |
+
if not callable(policy):
|
| 303 |
+
if not isinstance(policy, _Policy):
|
| 304 |
+
raise ValueError(
|
| 305 |
+
f"Expected {policy} to be callable or be a pre-defined wrap policy"
|
| 306 |
+
)
|
| 307 |
+
target_module_to_kwargs = policy._run_policy(
|
| 308 |
+
model, ignored_modules=set(), root_kwargs={}
|
| 309 |
+
)
|
| 310 |
+
wrap_fn = _construct_wrap_fn(
|
| 311 |
+
model, target_module_to_kwargs, checkpoint_wrapper_fn
|
| 312 |
+
)
|
| 313 |
+
_post_order_apply(model, wrap_fn)
|
| 314 |
+
return
|
| 315 |
+
|
| 316 |
+
_recursive_wrap(
|
| 317 |
+
module=model,
|
| 318 |
+
auto_wrap_policy=policy, # type: ignore[arg-type]
|
| 319 |
+
wrapper_cls=checkpoint_wrapper_fn,
|
| 320 |
+
ignored_modules=set(),
|
| 321 |
+
ignored_params=set(),
|
| 322 |
+
only_wrap_children=True,
|
| 323 |
+
)
|
lib/python3.12/site-packages/torch/distributed/algorithms/_comm_hooks/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from . import default_hooks as default
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
LOW_PRECISION_HOOKS = [
|
| 5 |
+
default.fp16_compress_hook,
|
| 6 |
+
default.bf16_compress_hook,
|
| 7 |
+
]
|
lib/python3.12/site-packages/torch/distributed/algorithms/_comm_hooks/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (406 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_comm_hooks/__pycache__/default_hooks.cpython-312.pyc
ADDED
|
Binary file (9.49 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_comm_hooks/default_hooks.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# mypy: allow-untyped-defs
|
| 2 |
+
import functools
|
| 3 |
+
from typing import Optional
|
| 4 |
+
|
| 5 |
+
import torch
|
| 6 |
+
import torch.distributed as dist
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class DefaultState:
|
| 10 |
+
r"""
|
| 11 |
+
Stores state needed to perform the default communication algorithm within a communication hook.
|
| 12 |
+
|
| 13 |
+
Args:
|
| 14 |
+
process_group (ProcessGroup): The process group to be used.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
__slots__ = [
|
| 18 |
+
"process_group",
|
| 19 |
+
"world_size",
|
| 20 |
+
"gradient_predivide_factor",
|
| 21 |
+
"gradient_postdivide_factor",
|
| 22 |
+
]
|
| 23 |
+
|
| 24 |
+
def __init__(self, process_group: dist.ProcessGroup):
|
| 25 |
+
if process_group is None:
|
| 26 |
+
raise ValueError(f"Expected to pass in an explicit ProcessGroup to {self}.")
|
| 27 |
+
self.process_group = process_group
|
| 28 |
+
self.world_size = dist.get_world_size(process_group)
|
| 29 |
+
# Setting two factors `self.gradient_predivide_factor`
|
| 30 |
+
# and `self.gradient_postdivide_factor` to avoid underflow and overflow
|
| 31 |
+
self.gradient_predivide_factor = self._get_gradient_predivide_factor(
|
| 32 |
+
self.world_size
|
| 33 |
+
)
|
| 34 |
+
self.gradient_postdivide_factor = (
|
| 35 |
+
self.world_size / self.gradient_predivide_factor
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
@staticmethod
|
| 39 |
+
def _get_gradient_predivide_factor(world_size: int) -> float:
|
| 40 |
+
factor: int = 1
|
| 41 |
+
while world_size % factor == 0 and world_size / factor > factor:
|
| 42 |
+
factor *= 2
|
| 43 |
+
return float(factor)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class LowPrecisionState(DefaultState):
|
| 47 |
+
r"""
|
| 48 |
+
Stores state needed to perform gradient communication in a lower precision within a communication hook.
|
| 49 |
+
|
| 50 |
+
Communication hook will cast gradients back to the original
|
| 51 |
+
parameter precision specified by ``parameter_type`` (default: torch.float32).
|
| 52 |
+
Builds on top of the :class:`DefaultState`.
|
| 53 |
+
|
| 54 |
+
Args:
|
| 55 |
+
parameter_type (torch.dtype): The precision of model's parameters.
|
| 56 |
+
Required for a hook to cast gradients back to a parameter's precision.
|
| 57 |
+
"""
|
| 58 |
+
|
| 59 |
+
__slots__ = [
|
| 60 |
+
"parameter_type",
|
| 61 |
+
]
|
| 62 |
+
|
| 63 |
+
def __init__(
|
| 64 |
+
self,
|
| 65 |
+
process_group,
|
| 66 |
+
parameter_type=torch.float32,
|
| 67 |
+
):
|
| 68 |
+
super().__init__(process_group)
|
| 69 |
+
self.parameter_type = parameter_type
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def _decompress(state: LowPrecisionState, grad: torch.Tensor):
|
| 73 |
+
"""
|
| 74 |
+
Casts gradients back to full parameter precision so that further computation happens in full precision.
|
| 75 |
+
"""
|
| 76 |
+
orig_grad_data = grad.data
|
| 77 |
+
grad.data = grad.data.to(state.parameter_type)
|
| 78 |
+
device_type = ""
|
| 79 |
+
try:
|
| 80 |
+
if grad.device.type == "privateuse1":
|
| 81 |
+
device_type = torch._C._get_privateuse1_backend_name()
|
| 82 |
+
else:
|
| 83 |
+
device_type = grad.device.type
|
| 84 |
+
backend = getattr(torch, device_type)
|
| 85 |
+
except AttributeError as e:
|
| 86 |
+
raise AttributeError(
|
| 87 |
+
f"Device {grad.device} does not have a \
|
| 88 |
+
corresponding backend registered as 'torch.device_type'."
|
| 89 |
+
) from e
|
| 90 |
+
|
| 91 |
+
# Don't let this memory get reused until after the transfer.
|
| 92 |
+
orig_grad_data.record_stream(backend.current_stream()) # type: ignore[arg-type]
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def allreduce_hook(state: DefaultState, grad: torch.Tensor):
|
| 96 |
+
r"""
|
| 97 |
+
Implement the FSDP communication hook for ``all_reduce`` algorithm and a necessary pre- and post-division of gradients.
|
| 98 |
+
|
| 99 |
+
Args:
|
| 100 |
+
state (DefaultState): State information, configures pre- and post-division factors.
|
| 101 |
+
grad (torch.Tensor): A gradient for the local batch that needs to be communicated across ranks.
|
| 102 |
+
"""
|
| 103 |
+
# Average grad by pre-division factor. Together pre- and post-division factors
|
| 104 |
+
# lead to an overall averaging by world_size, required for consistency with PyTorch DDP.
|
| 105 |
+
# This is a two-step process to avoid potential underflow and overflow.
|
| 106 |
+
if state.gradient_predivide_factor > 1:
|
| 107 |
+
grad.div_(state.gradient_predivide_factor)
|
| 108 |
+
dist.all_reduce(grad, group=state.process_group)
|
| 109 |
+
# Average grad by post-division factor.
|
| 110 |
+
if state.gradient_postdivide_factor > 1:
|
| 111 |
+
grad.div_(state.gradient_postdivide_factor)
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def reduce_scatter_hook(state: DefaultState, grad: torch.Tensor, output: torch.Tensor):
|
| 115 |
+
r"""
|
| 116 |
+
Implement the FSDP communication hook for ``reduce_scatter`` algorithm.
|
| 117 |
+
|
| 118 |
+
For sharded FSDP strategies and a necessary pre- and post-division of gradients.
|
| 119 |
+
|
| 120 |
+
Args:
|
| 121 |
+
state (DefaultState): State information, configures pre- and post-division factors.
|
| 122 |
+
grad (torch.Tensor): An unsharded gradient for the local batch that needs to be
|
| 123 |
+
communicated across ranks.
|
| 124 |
+
output (torch.Tensor): Stores a single shard of the gradient after ``reduce_scatter``.
|
| 125 |
+
"""
|
| 126 |
+
# Average grad by pre-division factor.
|
| 127 |
+
if state.gradient_predivide_factor > 1:
|
| 128 |
+
grad.div_(state.gradient_predivide_factor)
|
| 129 |
+
dist.reduce_scatter_tensor(output, grad, group=state.process_group)
|
| 130 |
+
# Average grad's shard by post-division factor.
|
| 131 |
+
if state.gradient_postdivide_factor > 1:
|
| 132 |
+
output.div_(state.gradient_postdivide_factor)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def _low_precision_hook(
|
| 136 |
+
prec: torch.dtype,
|
| 137 |
+
state: LowPrecisionState,
|
| 138 |
+
grad: torch.Tensor,
|
| 139 |
+
output: Optional[torch.Tensor],
|
| 140 |
+
):
|
| 141 |
+
if grad.dtype != prec:
|
| 142 |
+
grad.data = grad.data.to(prec)
|
| 143 |
+
if output is not None:
|
| 144 |
+
if output.dtype != prec:
|
| 145 |
+
output.data = output.data.to(prec)
|
| 146 |
+
reduce_scatter_hook(state, grad, output)
|
| 147 |
+
_decompress(state, output)
|
| 148 |
+
else:
|
| 149 |
+
allreduce_hook(state, grad)
|
| 150 |
+
_decompress(state, grad)
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def fp16_compress_hook(
|
| 154 |
+
state: LowPrecisionState, grad: torch.Tensor, output: Optional[torch.Tensor] = None
|
| 155 |
+
):
|
| 156 |
+
r"""
|
| 157 |
+
Implement FSDP communication hook for a simple gradient compression approach.
|
| 158 |
+
Casts ``grad`` to half-precision floating-point format (``torch.float16``).
|
| 159 |
+
|
| 160 |
+
It also averages gradients by ``world_size`` in two steps: first it pre-divides gradients by a
|
| 161 |
+
``state.gradient_predivide_factor``, and after a communication step (``all_reduce`` or ``reduce_scatter``)
|
| 162 |
+
gradients are averaged by a ``state.gradient_postdivide_factor``.
|
| 163 |
+
Once post-division is done, compressed gradients are casted back to parameters' precision.
|
| 164 |
+
|
| 165 |
+
Args:
|
| 166 |
+
state (LowPrecisionState): State information, configures pre- and post-division factors, parameters' precision.
|
| 167 |
+
grad (torch.Tensor): A gradient for the local batch that needs to be communicated across ranks in a lower precision.
|
| 168 |
+
output (torch.Tensor): Stores a single shard of the gradient after ``reduce_scatter``.
|
| 169 |
+
"""
|
| 170 |
+
fp16_hook = functools.partial(_low_precision_hook, torch.float16)
|
| 171 |
+
return fp16_hook(state, grad, output)
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def bf16_compress_hook(
|
| 175 |
+
state: LowPrecisionState, grad: torch.Tensor, output: Optional[torch.Tensor] = None
|
| 176 |
+
):
|
| 177 |
+
r"""
|
| 178 |
+
Implement FSDP communication hook for a simple gradient compression approach .
|
| 179 |
+
Casts ``grad`` to half-precision floating-point format.
|
| 180 |
+
|
| 181 |
+
It also averages gradients by ``world_size`` in two steps: first it pre-divides gradients by a
|
| 182 |
+
``state.gradient_predivide_factor``, and after a communication step (``all_reduce`` or ``reduce_scatter``)
|
| 183 |
+
gradients are averaged by a ``state.gradient_postdivide_factor``.
|
| 184 |
+
Once post-division is done, compressed gradients are casted back to parameters' precision.
|
| 185 |
+
|
| 186 |
+
Args:
|
| 187 |
+
state (LowPrecisionState): State information, configures pre- and post-division factors, parameters' precision.
|
| 188 |
+
grad (torch.Tensor): A gradient for the local batch that needs to be communicated across ranks in a lower precision.
|
| 189 |
+
output (torch.Tensor): Stores a single shard of the gradient after ``reduce_scatter``.
|
| 190 |
+
"""
|
| 191 |
+
bf16_hook = functools.partial(_low_precision_hook, torch.bfloat16)
|
| 192 |
+
return bf16_hook(state, grad, output)
|
lib/python3.12/site-packages/torch/distributed/algorithms/_optimizer_overlap/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
from .optimizer_overlap import _as_overlapped_optim
|
lib/python3.12/site-packages/torch/distributed/algorithms/_optimizer_overlap/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (291 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_optimizer_overlap/__pycache__/optimizer_overlap.cpython-312.pyc
ADDED
|
Binary file (4.91 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_optimizer_overlap/optimizer_overlap.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# mypy: allow-untyped-defs
|
| 2 |
+
import inspect
|
| 3 |
+
from abc import ABC, abstractmethod
|
| 4 |
+
from typing import Dict, Type
|
| 5 |
+
|
| 6 |
+
from torch.distributed.algorithms.ddp_comm_hooks.default_hooks import allreduce_hook
|
| 7 |
+
from torch.distributed.algorithms.ddp_comm_hooks.optimizer_overlap_hooks import (
|
| 8 |
+
_hook_then_optimizer,
|
| 9 |
+
_OptimizerHookState,
|
| 10 |
+
)
|
| 11 |
+
from torch.distributed.fsdp import FullyShardedDataParallel
|
| 12 |
+
from torch.distributed.optim import as_functional_optim
|
| 13 |
+
from torch.nn.parallel import DistributedDataParallel
|
| 14 |
+
from torch.optim import Optimizer
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
# Contains the mappings between the regular and overlapped optimizer types.
|
| 18 |
+
_registered_overlapped_optims: Dict[Type, Type] = {}
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def register_overlapped(optim_cls):
|
| 22 |
+
def decorator(target_overlapped_optim_cls):
|
| 23 |
+
if target_overlapped_optim_cls in _registered_overlapped_optims:
|
| 24 |
+
raise ValueError(
|
| 25 |
+
f"{target_overlapped_optim_cls} already registered with optim_cls "
|
| 26 |
+
f"{_registered_overlapped_optims[optim_cls]} {optim_cls}, trying to"
|
| 27 |
+
f"re-register it for {optim_cls} is not supported."
|
| 28 |
+
)
|
| 29 |
+
_registered_overlapped_optims[optim_cls] = target_overlapped_optim_cls
|
| 30 |
+
return target_overlapped_optim_cls
|
| 31 |
+
|
| 32 |
+
return decorator
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
class OverlappedOptimizer(ABC):
|
| 36 |
+
def __init__(self, optim_cls: Type) -> None:
|
| 37 |
+
"""
|
| 38 |
+
Initialize the OverlappedOptimizer.
|
| 39 |
+
|
| 40 |
+
Overlappedoptimizer is a base class that child classes can implement to
|
| 41 |
+
specify how different optimizers will register themselves with DDP.
|
| 42 |
+
"""
|
| 43 |
+
self.optim_cls = optim_cls
|
| 44 |
+
|
| 45 |
+
@abstractmethod
|
| 46 |
+
def register_ddp(self, ddp: DistributedDataParallel) -> None:
|
| 47 |
+
"""Registers the overlapped optimizer with DDP."""
|
| 48 |
+
raise NotImplementedError(
|
| 49 |
+
f"{self.__class__.__name__} does not support overlapped DDP."
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
@abstractmethod
|
| 53 |
+
def register_fsdp(self, fsdp: FullyShardedDataParallel) -> None:
|
| 54 |
+
"""Registers the overlapped optimizer with FSDP."""
|
| 55 |
+
raise NotImplementedError(
|
| 56 |
+
f"{self.__class__.__name__} does not support overlapped FSDP."
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
@register_overlapped(Optimizer)
|
| 61 |
+
class _OverlappedStandardOptimizer(OverlappedOptimizer):
|
| 62 |
+
"""Overlaps a regular ``Optimizer``."""
|
| 63 |
+
|
| 64 |
+
def __init__(self, optim_cls: Type, params, *optim_args, **optim_kwargs) -> None:
|
| 65 |
+
super().__init__(optim_cls)
|
| 66 |
+
f_optim = as_functional_optim(self.optim_cls, *optim_args, **optim_kwargs)
|
| 67 |
+
self._opt_hook_state = _OptimizerHookState(f_optim, params)
|
| 68 |
+
|
| 69 |
+
def register_ddp(self, ddp_inst: DistributedDataParallel):
|
| 70 |
+
# NOTE: using a custom communication hook and fused optimizer is not
|
| 71 |
+
# yet supported.
|
| 72 |
+
ddp_inst.register_comm_hook( # type: ignore[operator]
|
| 73 |
+
None, # wrapped hook state
|
| 74 |
+
_hook_then_optimizer(allreduce_hook, self._opt_hook_state),
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
# TODO: register_fsdp once FSDP supports communication hook.
|
| 78 |
+
def register_fsdp(self, fsdp: FullyShardedDataParallel) -> None:
|
| 79 |
+
"""Register the overlapped optimizer with FSDP."""
|
| 80 |
+
raise NotImplementedError(
|
| 81 |
+
f"{self.__class__.__name__} does not support overlapped FSDP."
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _as_overlapped_optim(optim_cls: Type, params, *args, **kwargs):
|
| 86 |
+
"""Return a new ``OverlappedOptimizer`` instance that supports ``optim_cls``."""
|
| 87 |
+
for clz in inspect.getmro(optim_cls):
|
| 88 |
+
try:
|
| 89 |
+
return _registered_overlapped_optims[clz](
|
| 90 |
+
optim_cls, params, *args, **kwargs
|
| 91 |
+
)
|
| 92 |
+
except KeyError:
|
| 93 |
+
pass
|
| 94 |
+
|
| 95 |
+
# Fallback to standard overlapped optimizer, which will raise errors if user
|
| 96 |
+
# is attempting to use an unsupported optimizer.
|
| 97 |
+
return _OverlappedStandardOptimizer(optim_cls, params, *args, **kwargs)
|
lib/python3.12/site-packages/torch/distributed/algorithms/_quantization/__init__.py
ADDED
|
File without changes
|
lib/python3.12/site-packages/torch/distributed/algorithms/_quantization/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (221 Bytes). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_quantization/__pycache__/quantization.cpython-312.pyc
ADDED
|
Binary file (7.84 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/_quantization/quantization.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# mypy: allow-untyped-defs
|
| 2 |
+
import functools
|
| 3 |
+
from enum import Enum
|
| 4 |
+
|
| 5 |
+
import torch
|
| 6 |
+
import torch.distributed as dist
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
TORCH_HALF_MIN = torch.finfo(torch.float16).min
|
| 10 |
+
TORCH_HALF_MAX = torch.finfo(torch.float16).max
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class DQuantType(Enum):
|
| 14 |
+
"""
|
| 15 |
+
Different quantization methods for auto_quantize API are identified here.
|
| 16 |
+
|
| 17 |
+
auto_quantize API currently supports fp16 and bfp16 methods.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
FP16 = ("fp16",)
|
| 21 |
+
BFP16 = "bfp16"
|
| 22 |
+
|
| 23 |
+
def __str__(self) -> str:
|
| 24 |
+
return self.value
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def _fp32_to_fp16_with_clamp(tensor: torch.Tensor) -> torch.Tensor:
|
| 28 |
+
return torch.clamp(tensor, TORCH_HALF_MIN, TORCH_HALF_MAX).half()
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def _quantize_tensor(tensor, qtype):
|
| 32 |
+
if not isinstance(tensor, torch.Tensor):
|
| 33 |
+
raise RuntimeError(
|
| 34 |
+
f"_quantize_tensor expecting torch.Tensor as input but found {type(tensor)}"
|
| 35 |
+
)
|
| 36 |
+
if qtype == DQuantType.FP16:
|
| 37 |
+
return _fp32_to_fp16_with_clamp(tensor)
|
| 38 |
+
elif qtype == DQuantType.BFP16:
|
| 39 |
+
return torch.ops.quantization._FloatToBfloat16Quantized(tensor)
|
| 40 |
+
else:
|
| 41 |
+
raise RuntimeError(f"Quantization type {qtype} is not supported")
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def _quantize_tensor_list(tensor_list, qtype):
|
| 45 |
+
if not isinstance(tensor_list, list) or not all(
|
| 46 |
+
isinstance(p, torch.Tensor) for p in tensor_list
|
| 47 |
+
):
|
| 48 |
+
raise RuntimeError(
|
| 49 |
+
f"_quantize_tensor_list expecting list of torch.Tensor as input but found {type(tensor_list)}"
|
| 50 |
+
)
|
| 51 |
+
quantized_tensor_list = [_quantize_tensor(t, qtype) for t in tensor_list]
|
| 52 |
+
return quantized_tensor_list
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def _dequantize_tensor(tensor, qtype, quant_loss=None):
|
| 56 |
+
if not isinstance(tensor, torch.Tensor):
|
| 57 |
+
raise RuntimeError(
|
| 58 |
+
f"_dequantize_tensor expecting torch.Tensor as input but found {type(tensor)}"
|
| 59 |
+
)
|
| 60 |
+
if qtype == DQuantType.FP16:
|
| 61 |
+
if tensor.dtype != torch.float16:
|
| 62 |
+
raise RuntimeError(
|
| 63 |
+
f"tensor dtype is {tensor.dtype} while expected to be FP16."
|
| 64 |
+
)
|
| 65 |
+
elif tensor.dtype == torch.float16 and quant_loss is None:
|
| 66 |
+
return tensor.float()
|
| 67 |
+
else:
|
| 68 |
+
return tensor.float() / quant_loss
|
| 69 |
+
elif qtype == DQuantType.BFP16:
|
| 70 |
+
if tensor.dtype != torch.float16:
|
| 71 |
+
raise RuntimeError(
|
| 72 |
+
f"tensor dtype is {tensor.dtype} while expected to be FP16."
|
| 73 |
+
)
|
| 74 |
+
else:
|
| 75 |
+
return torch.ops.quantization._Bfloat16QuantizedToFloat(tensor)
|
| 76 |
+
else:
|
| 77 |
+
raise RuntimeError(f"Quantization type {qtype} is not supported")
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def _dequantize_tensor_list(tensor_list, qtype, quant_loss=None):
|
| 81 |
+
if not isinstance(tensor_list, list) or not all(
|
| 82 |
+
isinstance(p, torch.Tensor) for p in tensor_list
|
| 83 |
+
):
|
| 84 |
+
raise RuntimeError(
|
| 85 |
+
f"_dequantize_tensor_list expecting list of torch.Tensor as input but found {type(tensor_list)}"
|
| 86 |
+
)
|
| 87 |
+
dequantized_tensor_list = [_dequantize_tensor(t, qtype) for t in tensor_list]
|
| 88 |
+
return dequantized_tensor_list
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def auto_quantize(func, qtype, quant_loss=None):
|
| 92 |
+
"""
|
| 93 |
+
Quantize the input tensors, choose the precision types, and pass other necessary arguments and then dequantizes the output.
|
| 94 |
+
|
| 95 |
+
Currently it only supports:
|
| 96 |
+
. FP16 and BFP16 quantization method supported for gloo and nccl backends
|
| 97 |
+
. all_gather, all_to_all collective ops
|
| 98 |
+
Note: BFP16 only supports 2D tensors.
|
| 99 |
+
Args:
|
| 100 |
+
func (Callable): A function representing collective operations.
|
| 101 |
+
qtype (QuantType): Quantization method
|
| 102 |
+
quant_loss (float, optional): This can be used to improve accuracy in the dequantization.
|
| 103 |
+
Returns:
|
| 104 |
+
(Callable): the same collective as func but enables automatic quantization/dequantization.
|
| 105 |
+
"""
|
| 106 |
+
|
| 107 |
+
@functools.wraps(func)
|
| 108 |
+
def wrapper(*args, **kwargs):
|
| 109 |
+
group = kwargs.get("group", None)
|
| 110 |
+
async_op = kwargs.get("async_op", False)
|
| 111 |
+
if async_op is True:
|
| 112 |
+
raise RuntimeError("The async_op=True mode is not supported yet.")
|
| 113 |
+
if func == dist.all_gather:
|
| 114 |
+
tensors = args[0]
|
| 115 |
+
input_tensors = _quantize_tensor(args[1], qtype)
|
| 116 |
+
out_tensors = _quantize_tensor_list(tensors, qtype)
|
| 117 |
+
dist.all_gather(out_tensors, input_tensors, group=group, async_op=async_op)
|
| 118 |
+
for i, t in enumerate(
|
| 119 |
+
_dequantize_tensor_list(out_tensors, qtype, quant_loss=quant_loss)
|
| 120 |
+
):
|
| 121 |
+
tensors[i] = t
|
| 122 |
+
|
| 123 |
+
elif func == dist.all_to_all:
|
| 124 |
+
tensors = args[0]
|
| 125 |
+
input_tensors = _quantize_tensor_list(args[1], qtype)
|
| 126 |
+
out_tensors = _quantize_tensor_list(tensors, qtype)
|
| 127 |
+
dist.all_to_all(out_tensors, input_tensors, group=group, async_op=async_op)
|
| 128 |
+
for i, t in enumerate(
|
| 129 |
+
_dequantize_tensor_list(out_tensors, qtype, quant_loss=quant_loss)
|
| 130 |
+
):
|
| 131 |
+
tensors[i] = t
|
| 132 |
+
|
| 133 |
+
elif func == dist.all_to_all_single:
|
| 134 |
+
tensors = args[0]
|
| 135 |
+
out_splits = kwargs.get("out_splits", None)
|
| 136 |
+
in_splits = kwargs.get("in_splits", None)
|
| 137 |
+
# Quantizing the input/output tensor
|
| 138 |
+
input_tensors = _quantize_tensor(args[1], qtype)
|
| 139 |
+
out_tensors = _quantize_tensor(tensors, qtype)
|
| 140 |
+
dist.all_to_all_single(
|
| 141 |
+
out_tensors, input_tensors, out_splits, in_splits, group=group
|
| 142 |
+
)
|
| 143 |
+
for i, t in enumerate(
|
| 144 |
+
_dequantize_tensor(out_tensors, qtype, quant_loss=quant_loss)
|
| 145 |
+
):
|
| 146 |
+
tensors[i] = t
|
| 147 |
+
else:
|
| 148 |
+
raise RuntimeError(f"The collective op {func} is not supported yet")
|
| 149 |
+
|
| 150 |
+
return wrapper
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__init__.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# mypy: allow-untyped-defs
|
| 2 |
+
from enum import Enum
|
| 3 |
+
from functools import partial
|
| 4 |
+
|
| 5 |
+
import torch.distributed as dist
|
| 6 |
+
|
| 7 |
+
from . import (
|
| 8 |
+
debugging_hooks as debugging,
|
| 9 |
+
default_hooks as default,
|
| 10 |
+
optimizer_overlap_hooks as optimizer_overlap,
|
| 11 |
+
powerSGD_hook as powerSGD,
|
| 12 |
+
quantization_hooks as quantization,
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
__all__ = ["DDPCommHookType", "register_ddp_comm_hook"]
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def _ddp_comm_hook_wrapper(comm_hook, model, state):
|
| 20 |
+
model.register_comm_hook(state, comm_hook)
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _powerSGD_comm_hook_wrapper(
|
| 24 |
+
comm_hook,
|
| 25 |
+
model,
|
| 26 |
+
state,
|
| 27 |
+
matrix_approximation_rank,
|
| 28 |
+
start_powerSGD_iter=1_000,
|
| 29 |
+
):
|
| 30 |
+
"""
|
| 31 |
+
Wrap PowerSGD communication hook.
|
| 32 |
+
|
| 33 |
+
To be consistent with the wrappers of other DDP comm hooks, the input state only needs to be a process group,
|
| 34 |
+
which will be wrapped up with other state info.
|
| 35 |
+
"""
|
| 36 |
+
powerSGD_state = powerSGD.PowerSGDState(
|
| 37 |
+
process_group=state,
|
| 38 |
+
matrix_approximation_rank=matrix_approximation_rank,
|
| 39 |
+
start_powerSGD_iter=start_powerSGD_iter,
|
| 40 |
+
)
|
| 41 |
+
model.register_comm_hook(powerSGD_state, comm_hook)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class DDPCommHookType(Enum):
|
| 45 |
+
"""
|
| 46 |
+
Enumerate ``ddp_comm_hooks`` and ``ddp_comm_hook_wrapper`` communucation hook types.
|
| 47 |
+
|
| 48 |
+
DDPCommHookType enumerates the hooks of ``torch.distributed.algorithms.ddp_comm_hooks``
|
| 49 |
+
as names and ``ddp_comm_hook_wrapper`` partials with hook specified. As an example,
|
| 50 |
+
you can register allreduce hook by
|
| 51 |
+
``DDPCommHookType.ALLREDUCE.value(model=model, state=process_group)``.
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
ALLREDUCE = partial(_ddp_comm_hook_wrapper, comm_hook=default.allreduce_hook)
|
| 55 |
+
FP16_COMPRESS = partial(
|
| 56 |
+
_ddp_comm_hook_wrapper, comm_hook=default.fp16_compress_hook
|
| 57 |
+
)
|
| 58 |
+
BF16_COMPRESS = partial(
|
| 59 |
+
_ddp_comm_hook_wrapper, comm_hook=default.bf16_compress_hook
|
| 60 |
+
)
|
| 61 |
+
QUANTIZE_PER_TENSOR = partial(
|
| 62 |
+
_ddp_comm_hook_wrapper, comm_hook=quantization.quantization_pertensor_hook
|
| 63 |
+
)
|
| 64 |
+
QUANTIZE_PER_CHANNEL = partial(
|
| 65 |
+
_ddp_comm_hook_wrapper, comm_hook=quantization.quantization_perchannel_hook
|
| 66 |
+
)
|
| 67 |
+
POWER_SGD = partial(
|
| 68 |
+
_powerSGD_comm_hook_wrapper,
|
| 69 |
+
comm_hook=powerSGD.powerSGD_hook,
|
| 70 |
+
matrix_approximation_rank=1,
|
| 71 |
+
)
|
| 72 |
+
# Rank-2 PowerSGD can give a higher accuracy than the default rank-1 version,
|
| 73 |
+
# but it runs slower and consumes more memory.
|
| 74 |
+
POWER_SGD_RANK2 = partial(
|
| 75 |
+
_powerSGD_comm_hook_wrapper,
|
| 76 |
+
comm_hook=powerSGD.powerSGD_hook,
|
| 77 |
+
matrix_approximation_rank=2,
|
| 78 |
+
)
|
| 79 |
+
# Batching can lead to a faster training at the cost of accuracy.
|
| 80 |
+
BATCHED_POWER_SGD = partial(
|
| 81 |
+
_powerSGD_comm_hook_wrapper,
|
| 82 |
+
comm_hook=powerSGD.batched_powerSGD_hook,
|
| 83 |
+
matrix_approximation_rank=1,
|
| 84 |
+
)
|
| 85 |
+
BATCHED_POWER_SGD_RANK2 = partial(
|
| 86 |
+
_powerSGD_comm_hook_wrapper,
|
| 87 |
+
comm_hook=powerSGD.batched_powerSGD_hook,
|
| 88 |
+
matrix_approximation_rank=2,
|
| 89 |
+
)
|
| 90 |
+
NOOP = partial(
|
| 91 |
+
_ddp_comm_hook_wrapper,
|
| 92 |
+
comm_hook=debugging.noop_hook,
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def register_ddp_comm_hook(comm_hook_type: DDPCommHookType, model, state=None):
|
| 97 |
+
"""
|
| 98 |
+
Register ``ddp_comm_hooks`` to DDP model.
|
| 99 |
+
|
| 100 |
+
Registers the hooks of ``torch.distributed.algorithms.ddp_comm_hooks``
|
| 101 |
+
to the DDP model. User can specify the type of hook as an enum
|
| 102 |
+
``DDPCommHookType`` type using ``comm_hook_type`` input. State input will
|
| 103 |
+
be passed to the model.
|
| 104 |
+
Uses Python comm hook implementations.
|
| 105 |
+
|
| 106 |
+
Example::
|
| 107 |
+
>>> # xdoctest: +SKIP
|
| 108 |
+
>>> register_ddp_comm_hook(DDPCommHookType.FP16_COMPRESS, model, state)
|
| 109 |
+
"""
|
| 110 |
+
comm_hook_type.value(model=model, state=state)
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (3.77 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/ddp_zero_hook.cpython-312.pyc
ADDED
|
Binary file (20.1 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/debugging_hooks.cpython-312.pyc
ADDED
|
Binary file (1.65 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/default_hooks.cpython-312.pyc
ADDED
|
Binary file (10.6 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/mixed_precision_hooks.cpython-312.pyc
ADDED
|
Binary file (4.57 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/optimizer_overlap_hooks.cpython-312.pyc
ADDED
|
Binary file (7.87 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/post_localSGD_hook.cpython-312.pyc
ADDED
|
Binary file (5 kB). View file
|
|
|
lib/python3.12/site-packages/torch/distributed/algorithms/ddp_comm_hooks/__pycache__/powerSGD_hook.cpython-312.pyc
ADDED
|
Binary file (35.2 kB). View file
|
|
|