spmd-types 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spmd_types-0.2.1/LICENSE +28 -0
- spmd_types-0.2.1/PKG-INFO +103 -0
- spmd_types-0.2.1/README.md +51 -0
- spmd_types-0.2.1/pyproject.toml +51 -0
- spmd_types-0.2.1/setup.cfg +4 -0
- spmd_types-0.2.1/spmd_types/__init__.py +109 -0
- spmd_types-0.2.1/spmd_types/_backward_hooks.py +133 -0
- spmd_types-0.2.1/spmd_types/_checker/__init__.py +3146 -0
- spmd_types-0.2.1/spmd_types/_collectives.py +1418 -0
- spmd_types-0.2.1/spmd_types/_dist.py +31 -0
- spmd_types-0.2.1/spmd_types/_dtensor.py +262 -0
- spmd_types-0.2.1/spmd_types/_dtensor_checker.py +107 -0
- spmd_types-0.2.1/spmd_types/_dtype_utils.py +243 -0
- spmd_types-0.2.1/spmd_types/_frame.py +68 -0
- spmd_types-0.2.1/spmd_types/_local.py +1207 -0
- spmd_types-0.2.1/spmd_types/_mesh.py +95 -0
- spmd_types-0.2.1/spmd_types/_mesh_axis.py +427 -0
- spmd_types-0.2.1/spmd_types/_mesh_region.py +313 -0
- spmd_types-0.2.1/spmd_types/_raw_dist.py +227 -0
- spmd_types-0.2.1/spmd_types/_reinterpret_mesh.py +255 -0
- spmd_types-0.2.1/spmd_types/_scalar.py +279 -0
- spmd_types-0.2.1/spmd_types/_scalar_sentinel.py +50 -0
- spmd_types-0.2.1/spmd_types/_state.py +145 -0
- spmd_types-0.2.1/spmd_types/_test_utils.py +290 -0
- spmd_types-0.2.1/spmd_types/_testing.py +30 -0
- spmd_types-0.2.1/spmd_types/_traceback.py +211 -0
- spmd_types-0.2.1/spmd_types/_type_attr.py +90 -0
- spmd_types-0.2.1/spmd_types/_vmap.py +117 -0
- spmd_types-0.2.1/spmd_types/checker.py +13 -0
- spmd_types-0.2.1/spmd_types/runtime.py +1070 -0
- spmd_types-0.2.1/spmd_types/types.py +676 -0
- spmd_types-0.2.1/spmd_types.egg-info/PKG-INFO +103 -0
- spmd_types-0.2.1/spmd_types.egg-info/SOURCES.txt +34 -0
- spmd_types-0.2.1/spmd_types.egg-info/dependency_links.txt +1 -0
- spmd_types-0.2.1/spmd_types.egg-info/requires.txt +1 -0
- spmd_types-0.2.1/spmd_types.egg-info/top_level.txt +1 -0
spmd_types-0.2.1/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
(c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
6
|
+
are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this list
|
|
9
|
+
of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this
|
|
12
|
+
list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its contributors may
|
|
16
|
+
be used to endorse or promote products derived from this software without specific
|
|
17
|
+
prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
20
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
21
|
+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
22
|
+
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
23
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
24
|
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
25
|
+
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
26
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
27
|
+
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
28
|
+
DAMAGE.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spmd_types
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: A type system for distributed (SPMD) tensor computations in PyTorch
|
|
5
|
+
Author: Meta Platforms, Inc.
|
|
6
|
+
License: BSD 3-Clause License
|
|
7
|
+
|
|
8
|
+
(c) Meta Platforms, Inc. and affiliates.
|
|
9
|
+
|
|
10
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
11
|
+
are permitted provided that the following conditions are met:
|
|
12
|
+
|
|
13
|
+
1. Redistributions of source code must retain the above copyright notice, this list
|
|
14
|
+
of conditions and the following disclaimer.
|
|
15
|
+
|
|
16
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this
|
|
17
|
+
list of conditions and the following disclaimer in the documentation
|
|
18
|
+
and/or other materials provided with the distribution.
|
|
19
|
+
|
|
20
|
+
3. Neither the name of the copyright holder nor the names of its contributors may
|
|
21
|
+
be used to endorse or promote products derived from this software without specific
|
|
22
|
+
prior written permission.
|
|
23
|
+
|
|
24
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
25
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
26
|
+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
27
|
+
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
28
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
29
|
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
30
|
+
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
31
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
32
|
+
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
33
|
+
DAMAGE.
|
|
34
|
+
|
|
35
|
+
Project-URL: Homepage, https://github.com/meta-pytorch/spmd_types
|
|
36
|
+
Project-URL: Repository, https://github.com/meta-pytorch/spmd_types
|
|
37
|
+
Project-URL: Issues, https://github.com/meta-pytorch/spmd_types/issues
|
|
38
|
+
Classifier: Development Status :: 4 - Beta
|
|
39
|
+
Classifier: Intended Audience :: Developers
|
|
40
|
+
Classifier: Intended Audience :: Science/Research
|
|
41
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
42
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
46
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
47
|
+
Requires-Python: >=3.10
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
License-File: LICENSE
|
|
50
|
+
Requires-Dist: torch>=2.10.0
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
|
|
53
|
+
# spmd_types
|
|
54
|
+
|
|
55
|
+
A type system for distributed (SPMD) tensor computations in PyTorch.
|
|
56
|
+
|
|
57
|
+
spmd_types tracks per-mesh-axis types on tensors -- Replicate (R), Invariant (I),
|
|
58
|
+
Varying (V), Partial (P), and Shard (S) -- and enforces type-correct transitions
|
|
59
|
+
through collective operations and local rewrites. It catches distributed
|
|
60
|
+
programming errors at development time without requiring a GPU cluster.
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install spmd_types
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quick start
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import torch
|
|
72
|
+
import torch.distributed as dist
|
|
73
|
+
import spmd_types as spmd
|
|
74
|
+
from torch.distributed.device_mesh import init_device_mesh
|
|
75
|
+
|
|
76
|
+
# Set up a fake process group (no GPUs needed)
|
|
77
|
+
dist.init_process_group(backend="fake", rank=0, world_size=8)
|
|
78
|
+
mesh = init_device_mesh("cpu", (2, 4), mesh_dim_names=("dp", "tp"))
|
|
79
|
+
dp = mesh.get_group("dp")
|
|
80
|
+
tp = mesh.get_group("tp")
|
|
81
|
+
|
|
82
|
+
with spmd.set_current_mesh(mesh), spmd.typecheck():
|
|
83
|
+
x = torch.randn(4)
|
|
84
|
+
spmd.assert_type(x, {dp: spmd.R, tp: spmd.P}) # R on dp, partial on tp
|
|
85
|
+
y = spmd.all_reduce(x, tp, src=spmd.P, dst=spmd.R) # sum across tp ranks
|
|
86
|
+
spmd.assert_type(y, {dp: spmd.R, tp: spmd.R}) # now replicated everywhere
|
|
87
|
+
z = torch.mul(y, y) # type inference: R * R -> R
|
|
88
|
+
spmd.assert_type(z, {dp: spmd.R, tp: spmd.R})
|
|
89
|
+
|
|
90
|
+
dist.destroy_process_group()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Documentation
|
|
94
|
+
|
|
95
|
+
See [MEGATRON_QUICKSTART.md](MEGATRON_QUICKSTART.md) for a guide on porting
|
|
96
|
+
Megatron-derived training frameworks to use spmd_types.
|
|
97
|
+
|
|
98
|
+
See [DESIGN.md](DESIGN.md) for the full type system specification, including
|
|
99
|
+
type inference rules, collective signatures, and forward-backward pairs.
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
BSD 3-Clause License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# spmd_types
|
|
2
|
+
|
|
3
|
+
A type system for distributed (SPMD) tensor computations in PyTorch.
|
|
4
|
+
|
|
5
|
+
spmd_types tracks per-mesh-axis types on tensors -- Replicate (R), Invariant (I),
|
|
6
|
+
Varying (V), Partial (P), and Shard (S) -- and enforces type-correct transitions
|
|
7
|
+
through collective operations and local rewrites. It catches distributed
|
|
8
|
+
programming errors at development time without requiring a GPU cluster.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install spmd_types
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
import torch
|
|
20
|
+
import torch.distributed as dist
|
|
21
|
+
import spmd_types as spmd
|
|
22
|
+
from torch.distributed.device_mesh import init_device_mesh
|
|
23
|
+
|
|
24
|
+
# Set up a fake process group (no GPUs needed)
|
|
25
|
+
dist.init_process_group(backend="fake", rank=0, world_size=8)
|
|
26
|
+
mesh = init_device_mesh("cpu", (2, 4), mesh_dim_names=("dp", "tp"))
|
|
27
|
+
dp = mesh.get_group("dp")
|
|
28
|
+
tp = mesh.get_group("tp")
|
|
29
|
+
|
|
30
|
+
with spmd.set_current_mesh(mesh), spmd.typecheck():
|
|
31
|
+
x = torch.randn(4)
|
|
32
|
+
spmd.assert_type(x, {dp: spmd.R, tp: spmd.P}) # R on dp, partial on tp
|
|
33
|
+
y = spmd.all_reduce(x, tp, src=spmd.P, dst=spmd.R) # sum across tp ranks
|
|
34
|
+
spmd.assert_type(y, {dp: spmd.R, tp: spmd.R}) # now replicated everywhere
|
|
35
|
+
z = torch.mul(y, y) # type inference: R * R -> R
|
|
36
|
+
spmd.assert_type(z, {dp: spmd.R, tp: spmd.R})
|
|
37
|
+
|
|
38
|
+
dist.destroy_process_group()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Documentation
|
|
42
|
+
|
|
43
|
+
See [MEGATRON_QUICKSTART.md](MEGATRON_QUICKSTART.md) for a guide on porting
|
|
44
|
+
Megatron-derived training frameworks to use spmd_types.
|
|
45
|
+
|
|
46
|
+
See [DESIGN.md](DESIGN.md) for the full type system specification, including
|
|
47
|
+
type inference rules, collective signatures, and forward-backward pairs.
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
BSD 3-Clause License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "spmd_types"
|
|
7
|
+
version = "0.2.1"
|
|
8
|
+
description = "A type system for distributed (SPMD) tensor computations in PyTorch"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {file = "LICENSE"}
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Meta Platforms, Inc."},
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"License :: OSI Approved :: BSD License",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"torch>=2.10.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/meta-pytorch/spmd_types"
|
|
32
|
+
Repository = "https://github.com/meta-pytorch/spmd_types"
|
|
33
|
+
Issues = "https://github.com/meta-pytorch/spmd_types/issues"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
include = ["spmd_types*"]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
line-length = 88
|
|
41
|
+
target-version = "py310"
|
|
42
|
+
|
|
43
|
+
[tool.ruff.lint]
|
|
44
|
+
select = ["E4", "E7", "E9", "F"]
|
|
45
|
+
|
|
46
|
+
[tool.ruff.format]
|
|
47
|
+
quote-style = "double"
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
testpaths = ["tests"]
|
|
51
|
+
python_files = ["*_test.py"]
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the BSD-style license found in the
|
|
5
|
+
# LICENSE file in the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
# spmd_types package
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from spmd_types._backward_hooks import ( # noqa: F401
|
|
11
|
+
register_local_backward_hook,
|
|
12
|
+
)
|
|
13
|
+
from spmd_types._collectives import ( # noqa: F401
|
|
14
|
+
all_gather,
|
|
15
|
+
all_reduce,
|
|
16
|
+
all_to_all,
|
|
17
|
+
redistribute,
|
|
18
|
+
reduce_scatter,
|
|
19
|
+
unshard,
|
|
20
|
+
)
|
|
21
|
+
from spmd_types._dist import set_dist # noqa: F401
|
|
22
|
+
from spmd_types._dtensor import ( # noqa: F401
|
|
23
|
+
dtensor_placement_to_spmd_type,
|
|
24
|
+
spmd_redistribute,
|
|
25
|
+
spmd_type_to_dtensor_placement,
|
|
26
|
+
)
|
|
27
|
+
from spmd_types._local import ( # noqa: F401
|
|
28
|
+
convert,
|
|
29
|
+
invariant_to_replicate,
|
|
30
|
+
reinterpret,
|
|
31
|
+
shard,
|
|
32
|
+
)
|
|
33
|
+
from spmd_types._mesh import set_current_mesh # noqa: F401
|
|
34
|
+
from spmd_types._mesh_axis import MeshAxis # noqa: F401
|
|
35
|
+
|
|
36
|
+
# reinterpret_mesh lives in its own module
|
|
37
|
+
from spmd_types._reinterpret_mesh import reinterpret_mesh # noqa: F401
|
|
38
|
+
from spmd_types._scalar import Scalar # noqa: F401
|
|
39
|
+
from spmd_types._state import ( # noqa: F401
|
|
40
|
+
current_mesh,
|
|
41
|
+
current_mesh_all_names,
|
|
42
|
+
current_mesh_names,
|
|
43
|
+
is_type_checking,
|
|
44
|
+
no_typecheck,
|
|
45
|
+
)
|
|
46
|
+
from spmd_types._traceback import traceback_filtering # noqa: F401
|
|
47
|
+
from spmd_types._type_attr import ( # noqa: F401
|
|
48
|
+
get_axis_local_type,
|
|
49
|
+
get_local_type,
|
|
50
|
+
maybe_get_axis_local_type,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Collectives and operations -- runtime API (no _checker dependency)
|
|
54
|
+
from spmd_types.runtime import ( # noqa: F401
|
|
55
|
+
assert_local_type,
|
|
56
|
+
assert_type,
|
|
57
|
+
assert_type_like,
|
|
58
|
+
Infer,
|
|
59
|
+
local,
|
|
60
|
+
local_map,
|
|
61
|
+
mutate_type,
|
|
62
|
+
register_autograd_function,
|
|
63
|
+
register_decomposition,
|
|
64
|
+
register_local_autograd_function,
|
|
65
|
+
trace,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Types
|
|
69
|
+
from spmd_types.types import ( # noqa: F401
|
|
70
|
+
DimSharding,
|
|
71
|
+
I,
|
|
72
|
+
Invariant,
|
|
73
|
+
LocalSpmdType,
|
|
74
|
+
normalize_axis,
|
|
75
|
+
normalize_mesh,
|
|
76
|
+
normalize_partition_spec,
|
|
77
|
+
P,
|
|
78
|
+
Partial,
|
|
79
|
+
PartitionSpec,
|
|
80
|
+
PerMeshAxisLocalSpmdType,
|
|
81
|
+
PerMeshAxisSpmdType,
|
|
82
|
+
PerMeshAxisSpmdTypes,
|
|
83
|
+
R,
|
|
84
|
+
Replicate,
|
|
85
|
+
S,
|
|
86
|
+
Shard,
|
|
87
|
+
SpmdTypeError,
|
|
88
|
+
TensorSharding,
|
|
89
|
+
V,
|
|
90
|
+
Varying,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class _TypeCheckingSentinel:
|
|
95
|
+
"""Singleton whose bool value reflects whether type checking is active.
|
|
96
|
+
|
|
97
|
+
``bool(TYPE_CHECKING)`` returns True when a ``typecheck()`` context is
|
|
98
|
+
active on the current thread, False otherwise. This avoids the
|
|
99
|
+
sys.modules replacement trick which breaks torch.compile / Dynamo.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
def __bool__(self) -> bool:
|
|
103
|
+
return is_type_checking()
|
|
104
|
+
|
|
105
|
+
def __repr__(self) -> str:
|
|
106
|
+
return f"TYPE_CHECKING({is_type_checking()})"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
TYPE_CHECKING = _TypeCheckingSentinel()
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the BSD-style license found in the
|
|
5
|
+
# LICENSE file in the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
"""Per-hook SPMD type-propagation registry for nn.Module backward hooks.
|
|
8
|
+
|
|
9
|
+
BackwardHookFunction (nn.Module.register_full_backward_hook) has a pure
|
|
10
|
+
pass-through forward. Each user hook callable must be explicitly registered
|
|
11
|
+
via ``register_local_backward_hook`` to declare that it does not alter SPMD
|
|
12
|
+
types; unregistered hooks raise SpmdTypeError when type checking is active.
|
|
13
|
+
|
|
14
|
+
TODO: a per-hook rule API (for hooks that do collectives on grads, e.g.
|
|
15
|
+
all-reduce flipping I -> R) can be added later when a real use case
|
|
16
|
+
motivates the exact shape.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from collections.abc import Callable
|
|
22
|
+
|
|
23
|
+
import torch
|
|
24
|
+
import torch.utils.hooks as _torch_hooks
|
|
25
|
+
from spmd_types._state import is_type_checking
|
|
26
|
+
from spmd_types.runtime import (
|
|
27
|
+
_set_partition_spec,
|
|
28
|
+
assert_type_like,
|
|
29
|
+
get_partition_spec,
|
|
30
|
+
)
|
|
31
|
+
from spmd_types.types import SpmdTypeError
|
|
32
|
+
from torch.nn.modules._functions import BackwardHookFunction
|
|
33
|
+
|
|
34
|
+
_LOCAL_BACKWARD_HOOKS: set[Callable] = set()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def register_local_backward_hook(fn: Callable) -> Callable:
|
|
38
|
+
"""Declare that ``fn`` does not alter SPMD types when it runs in backward.
|
|
39
|
+
|
|
40
|
+
Analogous to :func:`register_local_autograd_function`: the hook's backward
|
|
41
|
+
is treated as local (no collectives, no type-changing effects on grads).
|
|
42
|
+
Side-agnostic: covers both ``register_full_backward_hook`` (post) and
|
|
43
|
+
``register_full_backward_pre_hook`` (pre) use. Usable as a decorator.
|
|
44
|
+
"""
|
|
45
|
+
_LOCAL_BACKWARD_HOOKS.add(fn)
|
|
46
|
+
return fn
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _validate(hooks):
|
|
50
|
+
if not is_type_checking():
|
|
51
|
+
return
|
|
52
|
+
for fn in hooks:
|
|
53
|
+
if fn in _LOCAL_BACKWARD_HOOKS:
|
|
54
|
+
continue
|
|
55
|
+
raise SpmdTypeError(
|
|
56
|
+
f"Backward hook {getattr(fn, '__qualname__', fn)!r} attached to "
|
|
57
|
+
f"nn.Module is not registered for SPMD type propagation. Call "
|
|
58
|
+
f"register_local_backward_hook(fn) if the hook does not alter "
|
|
59
|
+
f"gradient SPMD types."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _apply_types(hooks, inputs, outputs):
|
|
64
|
+
"""Copy SPMD annotations across BackwardHookFunction wrappers.
|
|
65
|
+
|
|
66
|
+
BackwardHookFunction.apply creates fresh tensor objects for module
|
|
67
|
+
backward hooks. Registered local hooks are semantically pass-through, so
|
|
68
|
+
their wrapper tensors should keep the input SPMD metadata.
|
|
69
|
+
"""
|
|
70
|
+
if not isinstance(inputs, tuple):
|
|
71
|
+
inputs = (inputs,)
|
|
72
|
+
if not isinstance(outputs, tuple):
|
|
73
|
+
outputs = (outputs,)
|
|
74
|
+
|
|
75
|
+
for fn in hooks:
|
|
76
|
+
if fn in _LOCAL_BACKWARD_HOOKS:
|
|
77
|
+
for inp, out in zip(inputs, outputs):
|
|
78
|
+
if isinstance(inp, torch.Tensor) and isinstance(out, torch.Tensor):
|
|
79
|
+
spec = get_partition_spec(inp)
|
|
80
|
+
assert_type_like(out, inp)
|
|
81
|
+
if spec is not None:
|
|
82
|
+
_set_partition_spec(out, spec)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
_orig_setup_input_hook = None
|
|
86
|
+
_orig_setup_output_hook = None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _patched_setup_input_hook(self, input):
|
|
90
|
+
_validate(self.user_hooks)
|
|
91
|
+
result = _orig_setup_input_hook(self, input)
|
|
92
|
+
_apply_types(self.user_hooks, input, result)
|
|
93
|
+
_apply_types(self.user_pre_hooks, input, result)
|
|
94
|
+
return result
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _patched_setup_output_hook(self, output):
|
|
98
|
+
_validate(self.user_pre_hooks)
|
|
99
|
+
result = _orig_setup_output_hook(self, output)
|
|
100
|
+
_apply_types(self.user_pre_hooks, output, result)
|
|
101
|
+
_apply_types(self.user_hooks, output, result)
|
|
102
|
+
return result
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def install() -> None:
|
|
106
|
+
"""Install the BackwardHook monkey-patch. Idempotent."""
|
|
107
|
+
global _orig_setup_input_hook, _orig_setup_output_hook
|
|
108
|
+
|
|
109
|
+
if _orig_setup_input_hook is not None:
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
from spmd_types._checker import register_autograd_function
|
|
113
|
+
|
|
114
|
+
BackwardHookFunction.typecheck_forward = staticmethod(BackwardHookFunction.apply)
|
|
115
|
+
register_autograd_function(BackwardHookFunction)
|
|
116
|
+
|
|
117
|
+
_orig_setup_input_hook = _torch_hooks.BackwardHook.setup_input_hook
|
|
118
|
+
_orig_setup_output_hook = _torch_hooks.BackwardHook.setup_output_hook
|
|
119
|
+
_torch_hooks.BackwardHook.setup_input_hook = _patched_setup_input_hook
|
|
120
|
+
_torch_hooks.BackwardHook.setup_output_hook = _patched_setup_output_hook
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def uninstall() -> None:
|
|
124
|
+
"""Remove the BackwardHook monkey-patch. Idempotent."""
|
|
125
|
+
global _orig_setup_input_hook, _orig_setup_output_hook
|
|
126
|
+
|
|
127
|
+
if _orig_setup_input_hook is None:
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
_torch_hooks.BackwardHook.setup_input_hook = _orig_setup_input_hook
|
|
131
|
+
_torch_hooks.BackwardHook.setup_output_hook = _orig_setup_output_hook
|
|
132
|
+
_orig_setup_input_hook = None
|
|
133
|
+
_orig_setup_output_hook = None
|