spmd_types 0.2.0__tar.gz → 0.2.2__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.
Files changed (40) hide show
  1. {spmd_types-0.2.0/spmd_types.egg-info → spmd_types-0.2.2}/PKG-INFO +34 -16
  2. spmd_types-0.2.2/README.md +69 -0
  3. {spmd_types-0.2.0 → spmd_types-0.2.2}/pyproject.toml +1 -1
  4. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/__init__.py +23 -9
  5. spmd_types-0.2.2/spmd_types/_backward_hooks.py +133 -0
  6. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_checker/__init__.py +506 -179
  7. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_collectives.py +512 -91
  8. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_dist.py +6 -0
  9. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_dtensor.py +6 -0
  10. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_dtensor_checker.py +6 -0
  11. spmd_types-0.2.2/spmd_types/_dtype_utils.py +243 -0
  12. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_frame.py +6 -0
  13. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_local.py +363 -114
  14. spmd_types-0.2.2/spmd_types/_mesh.py +126 -0
  15. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_mesh_axis.py +85 -22
  16. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_mesh_region.py +140 -33
  17. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_raw_dist.py +6 -0
  18. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_reinterpret_mesh.py +17 -11
  19. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_scalar.py +6 -0
  20. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_scalar_sentinel.py +6 -0
  21. spmd_types-0.2.2/spmd_types/_state.py +172 -0
  22. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_test_utils.py +44 -9
  23. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_testing.py +6 -0
  24. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_traceback.py +8 -4
  25. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_type_attr.py +6 -0
  26. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/_vmap.py +6 -0
  27. spmd_types-0.2.2/spmd_types/checker.py +13 -0
  28. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/runtime.py +421 -6
  29. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types/types.py +186 -51
  30. {spmd_types-0.2.0 → spmd_types-0.2.2/spmd_types.egg-info}/PKG-INFO +34 -16
  31. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types.egg-info/SOURCES.txt +3 -1
  32. spmd_types-0.2.0/README.md +0 -51
  33. spmd_types-0.2.0/spmd_types/_checker.py +0 -3636
  34. spmd_types-0.2.0/spmd_types/_mesh.py +0 -70
  35. spmd_types-0.2.0/spmd_types/_state.py +0 -72
  36. {spmd_types-0.2.0 → spmd_types-0.2.2}/LICENSE +0 -0
  37. {spmd_types-0.2.0 → spmd_types-0.2.2}/setup.cfg +0 -0
  38. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types.egg-info/dependency_links.txt +0 -0
  39. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types.egg-info/requires.txt +0 -0
  40. {spmd_types-0.2.0 → spmd_types-0.2.2}/spmd_types.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spmd_types
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A type system for distributed (SPMD) tensor computations in PyTorch
5
5
  Author: Meta Platforms, Inc.
6
6
  License: BSD 3-Clause License
@@ -50,14 +50,29 @@ License-File: LICENSE
50
50
  Requires-Dist: torch>=2.10.0
51
51
  Dynamic: license-file
52
52
 
53
- # spmd_types
53
+ # `spmd_types`
54
54
 
55
- A type system for distributed (SPMD) tensor computations in PyTorch.
55
+ A type system for distributed (SPMD) tensor computations in PyTorch. This
56
+ package provides two type systems:
56
57
 
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.
58
+ * **Local SPMD types**, which allow you to use Megatron-style differentiable
59
+ collectives in a safe way by tracking whether or not your backward gradients
60
+ are pending reduction or not.
61
+
62
+ * **Global SPMD types**, a DTensor-like abstraction for writing code that has
63
+ the same semantics whether run on a single device or in a distributed
64
+ fashion, but with explicit communication operations so you are never
65
+ guessing when a redistribute occurs.
66
+
67
+ In both cases, the SPMD types makes it possible for you to check that your
68
+ code computes correct gradients (local SPMD) or gives equivalent results
69
+ across different parallelizations (global SPMD), without having to actually
70
+ run a full E2E distributed training run to check for loss matching.
71
+
72
+ The goal of this package is to provide a flexible type system that can
73
+ typecheck realistic training code. We have used local SPMD types to typecheck
74
+ a realistic pretraining codebase, and global SPMD types is actively under
75
+ construction!
61
76
 
62
77
  ## Installation
63
78
 
@@ -71,6 +86,7 @@ pip install spmd_types
71
86
  import torch
72
87
  import torch.distributed as dist
73
88
  import spmd_types as spmd
89
+ import spmd_types.checker
74
90
  from torch.distributed.device_mesh import init_device_mesh
75
91
 
76
92
  # Set up a fake process group (no GPUs needed)
@@ -79,12 +95,12 @@ mesh = init_device_mesh("cpu", (2, 4), mesh_dim_names=("dp", "tp"))
79
95
  dp = mesh.get_group("dp")
80
96
  tp = mesh.get_group("tp")
81
97
 
82
- with spmd.set_current_mesh(mesh), spmd.typecheck():
98
+ with spmd.set_current_mesh(mesh), spmd.checker.typecheck():
83
99
  x = torch.randn(4)
84
- spmd.assert_type(x, {dp: spmd.R, tp: spmd.P}) # R on dp, partial on tp
100
+ spmd.assert_type(x, {dp: spmd.R, tp: spmd.P}) # R on dp, partial on tp
85
101
  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
102
+ spmd.assert_type(y, {dp: spmd.R, tp: spmd.R}) # now replicated everywhere
103
+ z = torch.mul(y, y) # type inference: R * R -> R
88
104
  spmd.assert_type(z, {dp: spmd.R, tp: spmd.R})
89
105
 
90
106
  dist.destroy_process_group()
@@ -92,12 +108,14 @@ dist.destroy_process_group()
92
108
 
93
109
  ## Documentation
94
110
 
95
- See [MEGATRON_QUICKSTART.md](MEGATRON_QUICKSTART.md) for a guide on porting
96
- Megatron-derived training frameworks to use spmd_types.
111
+ See [Local SPMD types](docs/local_spmd_types.md) for a hands-on guide on
112
+ porting Megatron-derived training frameworks, including the Megatron-to-spmd_types
113
+ function mapping table and advice on Invariant vs Replicate.
97
114
 
98
- See [DESIGN.md](DESIGN.md) for the full type system specification, including
99
- type inference rules, collective signatures, and forward-backward pairs.
115
+ See [Design](docs/design.md) for the full type system specification, including
116
+ local vs global SPMD modes, collective signatures with diagrams, forward-backward
117
+ pairs, expert mode, cross-mesh compatibility, and partition spec redistribute.
100
118
 
101
119
  ## License
102
120
 
103
- BSD 3-Clause License. See [LICENSE](LICENSE) for details.
121
+ BSD 3-Clause License. See [CONTRIBUTING.md](CONTRIBUTING.md) for how to contribute.
@@ -0,0 +1,69 @@
1
+ # `spmd_types`
2
+
3
+ A type system for distributed (SPMD) tensor computations in PyTorch. This
4
+ package provides two type systems:
5
+
6
+ * **Local SPMD types**, which allow you to use Megatron-style differentiable
7
+ collectives in a safe way by tracking whether or not your backward gradients
8
+ are pending reduction or not.
9
+
10
+ * **Global SPMD types**, a DTensor-like abstraction for writing code that has
11
+ the same semantics whether run on a single device or in a distributed
12
+ fashion, but with explicit communication operations so you are never
13
+ guessing when a redistribute occurs.
14
+
15
+ In both cases, the SPMD types makes it possible for you to check that your
16
+ code computes correct gradients (local SPMD) or gives equivalent results
17
+ across different parallelizations (global SPMD), without having to actually
18
+ run a full E2E distributed training run to check for loss matching.
19
+
20
+ The goal of this package is to provide a flexible type system that can
21
+ typecheck realistic training code. We have used local SPMD types to typecheck
22
+ a realistic pretraining codebase, and global SPMD types is actively under
23
+ construction!
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install spmd_types
29
+ ```
30
+
31
+ ## Quick start
32
+
33
+ ```python
34
+ import torch
35
+ import torch.distributed as dist
36
+ import spmd_types as spmd
37
+ import spmd_types.checker
38
+ from torch.distributed.device_mesh import init_device_mesh
39
+
40
+ # Set up a fake process group (no GPUs needed)
41
+ dist.init_process_group(backend="fake", rank=0, world_size=8)
42
+ mesh = init_device_mesh("cpu", (2, 4), mesh_dim_names=("dp", "tp"))
43
+ dp = mesh.get_group("dp")
44
+ tp = mesh.get_group("tp")
45
+
46
+ with spmd.set_current_mesh(mesh), spmd.checker.typecheck():
47
+ x = torch.randn(4)
48
+ spmd.assert_type(x, {dp: spmd.R, tp: spmd.P}) # R on dp, partial on tp
49
+ y = spmd.all_reduce(x, tp, src=spmd.P, dst=spmd.R) # sum across tp ranks
50
+ spmd.assert_type(y, {dp: spmd.R, tp: spmd.R}) # now replicated everywhere
51
+ z = torch.mul(y, y) # type inference: R * R -> R
52
+ spmd.assert_type(z, {dp: spmd.R, tp: spmd.R})
53
+
54
+ dist.destroy_process_group()
55
+ ```
56
+
57
+ ## Documentation
58
+
59
+ See [Local SPMD types](docs/local_spmd_types.md) for a hands-on guide on
60
+ porting Megatron-derived training frameworks, including the Megatron-to-spmd_types
61
+ function mapping table and advice on Invariant vs Replicate.
62
+
63
+ See [Design](docs/design.md) for the full type system specification, including
64
+ local vs global SPMD modes, collective signatures with diagrams, forward-backward
65
+ pairs, expert mode, cross-mesh compatibility, and partition spec redistribute.
66
+
67
+ ## License
68
+
69
+ BSD 3-Clause License. See [CONTRIBUTING.md](CONTRIBUTING.md) for how to contribute.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "spmd_types"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "A type system for distributed (SPMD) tensor computations in PyTorch"
9
9
  readme = "README.md"
10
10
  license = {file = "LICENSE"}
@@ -1,14 +1,14 @@
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
+
1
7
  # spmd_types package
2
8
  from __future__ import annotations
3
9
 
4
- import spmd_types._dtensor_checker as _dtensor_checker # noqa: F401
5
-
6
- # These still require _checker (the type inference engine)
7
- from spmd_types._checker import ( # noqa: F401
8
- _SpmdTypeBackwardCompatibleMode as SpmdTypeMode,
9
- is_type_checking,
10
- no_typecheck,
11
- typecheck,
10
+ from spmd_types._backward_hooks import ( # noqa: F401
11
+ register_local_backward_hook,
12
12
  )
13
13
  from spmd_types._collectives import ( # noqa: F401
14
14
  all_gather,
@@ -36,7 +36,13 @@ from spmd_types._mesh_axis import MeshAxis # noqa: F401
36
36
  # reinterpret_mesh lives in its own module
37
37
  from spmd_types._reinterpret_mesh import reinterpret_mesh # noqa: F401
38
38
  from spmd_types._scalar import Scalar # noqa: F401
39
- from spmd_types._state import current_mesh # 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
+ )
40
46
  from spmd_types._traceback import traceback_filtering # noqa: F401
41
47
  from spmd_types._type_attr import ( # noqa: F401
42
48
  get_axis_local_type,
@@ -47,9 +53,15 @@ from spmd_types._type_attr import ( # noqa: F401
47
53
  # Collectives and operations -- runtime API (no _checker dependency)
48
54
  from spmd_types.runtime import ( # noqa: F401
49
55
  assert_local_type,
56
+ assert_local_type_like,
50
57
  assert_type,
58
+ assert_type_like,
59
+ Infer,
60
+ local,
61
+ local_map,
51
62
  mutate_type,
52
63
  register_autograd_function,
64
+ register_decomposition,
53
65
  register_local_autograd_function,
54
66
  trace,
55
67
  )
@@ -62,6 +74,7 @@ from spmd_types.types import ( # noqa: F401
62
74
  LocalSpmdType,
63
75
  normalize_axis,
64
76
  normalize_mesh,
77
+ normalize_partition_spec,
65
78
  P,
66
79
  Partial,
67
80
  PartitionSpec,
@@ -72,6 +85,7 @@ from spmd_types.types import ( # noqa: F401
72
85
  Replicate,
73
86
  S,
74
87
  Shard,
88
+ SpmdType,
75
89
  SpmdTypeError,
76
90
  TensorSharding,
77
91
  V,
@@ -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