spmd_types 0.2.3__tar.gz → 0.2.4__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 (36) hide show
  1. {spmd_types-0.2.3/spmd_types.egg-info → spmd_types-0.2.4}/PKG-INFO +1 -1
  2. {spmd_types-0.2.3 → spmd_types-0.2.4}/pyproject.toml +1 -1
  3. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/__init__.py +4 -4
  4. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_backward_hooks.py +4 -16
  5. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_checker/__init__.py +26 -20
  6. spmd_types-0.2.4/spmd_types/_local_registration.py +50 -0
  7. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/runtime.py +50 -42
  8. {spmd_types-0.2.3 → spmd_types-0.2.4/spmd_types.egg-info}/PKG-INFO +1 -1
  9. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types.egg-info/SOURCES.txt +1 -0
  10. {spmd_types-0.2.3 → spmd_types-0.2.4}/LICENSE +0 -0
  11. {spmd_types-0.2.3 → spmd_types-0.2.4}/README.md +0 -0
  12. {spmd_types-0.2.3 → spmd_types-0.2.4}/setup.cfg +0 -0
  13. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_collectives.py +0 -0
  14. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_dist.py +0 -0
  15. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_dtensor.py +0 -0
  16. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_dtensor_checker.py +0 -0
  17. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_dtype_utils.py +0 -0
  18. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_frame.py +0 -0
  19. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_local.py +0 -0
  20. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_mesh.py +0 -0
  21. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_mesh_axis.py +0 -0
  22. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_mesh_region.py +0 -0
  23. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_raw_dist.py +0 -0
  24. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_reinterpret_mesh.py +0 -0
  25. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_scalar.py +0 -0
  26. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_scalar_sentinel.py +0 -0
  27. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_state.py +0 -0
  28. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_test_utils.py +0 -0
  29. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_testing.py +0 -0
  30. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_traceback.py +0 -0
  31. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_type_attr.py +0 -0
  32. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/_vmap.py +0 -0
  33. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/checker.py +0 -0
  34. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types/types.py +0 -0
  35. {spmd_types-0.2.3 → spmd_types-0.2.4}/spmd_types.egg-info/dependency_links.txt +0 -0
  36. {spmd_types-0.2.3 → spmd_types-0.2.4}/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.3
3
+ Version: 0.2.4
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "spmd_types"
7
- version = "0.2.3"
7
+ version = "0.2.4"
8
8
  description = "A type system for distributed (SPMD) tensor computations in PyTorch"
9
9
  readme = "README.md"
10
10
  license = {file = "LICENSE"}
@@ -7,9 +7,6 @@
7
7
  # spmd_types package
8
8
  from __future__ import annotations
9
9
 
10
- from spmd_types._backward_hooks import ( # noqa: F401
11
- register_local_backward_hook,
12
- )
13
10
  from spmd_types._collectives import ( # noqa: F401
14
11
  all_gather,
15
12
  all_reduce,
@@ -30,6 +27,10 @@ from spmd_types._local import ( # noqa: F401
30
27
  reinterpret,
31
28
  shard,
32
29
  )
30
+ from spmd_types._local_registration import ( # noqa: F401
31
+ register_local_autograd_function,
32
+ register_local_backward_hook,
33
+ )
33
34
  from spmd_types._mesh import set_current_mesh # noqa: F401
34
35
  from spmd_types._mesh_axis import MeshAxis # noqa: F401
35
36
 
@@ -64,7 +65,6 @@ from spmd_types.runtime import ( # noqa: F401
64
65
  no_typecheck,
65
66
  register_autograd_function,
66
67
  register_decomposition,
67
- register_local_autograd_function,
68
68
  trace,
69
69
  )
70
70
 
@@ -18,10 +18,12 @@ motivates the exact shape.
18
18
 
19
19
  from __future__ import annotations
20
20
 
21
- from collections.abc import Callable
22
-
23
21
  import torch
24
22
  import torch.utils.hooks as _torch_hooks
23
+ from spmd_types._local_registration import ( # noqa: F401
24
+ _LOCAL_BACKWARD_HOOKS,
25
+ register_local_backward_hook,
26
+ )
25
27
  from spmd_types._state import is_type_checking
26
28
  from spmd_types.runtime import (
27
29
  _set_partition_spec,
@@ -31,20 +33,6 @@ from spmd_types.runtime import (
31
33
  from spmd_types.types import SpmdTypeError
32
34
  from torch.nn.modules._functions import BackwardHookFunction
33
35
 
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
36
 
49
37
  def _validate(hooks):
50
38
  if not is_type_checking():
@@ -36,6 +36,10 @@ from spmd_types._collectives import (
36
36
  reduce_scatter,
37
37
  )
38
38
  from spmd_types._local import convert, invariant_to_replicate, reinterpret
39
+ from spmd_types._local_registration import ( # noqa: F401
40
+ _LOCAL_AUTOGRAD_FUNCTIONS,
41
+ register_local_autograd_function,
42
+ )
39
43
  from spmd_types._mesh_axis import MeshAxis
40
44
  from spmd_types._reinterpret_mesh import ( # noqa: F401
41
45
  _format_arg_for_context,
@@ -53,8 +57,9 @@ from spmd_types._state import _current_mode, _set_current_mode, current_mesh
53
57
  from spmd_types._traceback import _filter_and_reraise
54
58
  from spmd_types._type_attr import get_local_type
55
59
  from spmd_types.runtime import ( # noqa: F401
56
- _LOCAL_AUTOGRAD_FUNCTIONS,
60
+ _get_autograd_spmd_typecheck,
57
61
  _PARTITION_SPEC_ATTR,
62
+ _run_autograd_spmd_typecheck,
58
63
  _set_local_type,
59
64
  _set_partition_spec,
60
65
  _TRACE,
@@ -71,7 +76,6 @@ from spmd_types.runtime import ( # noqa: F401
71
76
  no_typecheck,
72
77
  register_autograd_function,
73
78
  register_decomposition,
74
- register_local_autograd_function,
75
79
  trace,
76
80
  )
77
81
  from spmd_types.types import (
@@ -2455,10 +2459,9 @@ from spmd_types._state import is_type_checking # noqa: E402, F401
2455
2459
  # Set of autograd.Function subclasses whose apply is known to be local-only
2456
2460
  # (i.e., each output element depends only on the corresponding input elements
2457
2461
  # so the standard element-wise type propagation rule is safe).
2458
- # Set of autograd.Function subclasses registered with a typecheck_forward
2459
- # staticmethod. When .apply() is intercepted by __torch_function__,
2460
- # typecheck_forward is called INSTEAD of .apply(). It should assert_type()
2461
- # on inputs, call .apply() to execute, and assert_type() on the output.
2462
+ # Set of autograd.Function subclasses registered with custom typechecking.
2463
+ # Legacy typecheck_forward wrappers execute the function themselves, while
2464
+ # spmd_typecheck runs after the real apply call managed by the checker.
2462
2465
 
2463
2466
 
2464
2467
  # The original C++ descriptor for autograd.Function.apply, saved when the
@@ -2707,18 +2710,22 @@ class _SpmdTypeMode(torch.overrides.TorchFunctionMode):
2707
2710
  is_global_axis=self._is_global_axis,
2708
2711
  )
2709
2712
 
2710
- # Typecheck-registered autograd function: dispatch to typecheck_forward
2711
- # INSTEAD of executing func. The mode is popped off the
2713
+ # Typecheck-registered autograd function. The mode is popped off the
2712
2714
  # TorchFunctionMode stack during __torch_function__ dispatch (via
2713
- # _pop_mode_temporarily in torch/overrides.py), so .apply() called
2714
- # inside typecheck_forward executes normally without re-entering
2715
- # this method.
2715
+ # _pop_mode_temporarily in torch/overrides.py), so the real apply
2716
+ # executes normally without re-entering this method.
2716
2717
  autograd_cls = _get_autograd_function_class(func)
2717
- if (
2718
- autograd_cls is not None
2719
- and autograd_cls in _TYPECHECK_AUTOGRAD_FUNCTIONS
2720
- ):
2721
- return autograd_cls.typecheck_forward(*args, **kwargs)
2718
+ if autograd_cls is not None:
2719
+ spmd_typecheck = _get_autograd_spmd_typecheck(autograd_cls)
2720
+ if spmd_typecheck is not None:
2721
+ if kwargs:
2722
+ raise TypeError(
2723
+ f"{autograd_cls.__name__}.apply() accepts positional "
2724
+ "arguments only"
2725
+ )
2726
+ return _run_autograd_spmd_typecheck(autograd_cls, func, args)
2727
+ if autograd_cls in _TYPECHECK_AUTOGRAD_FUNCTIONS:
2728
+ return autograd_cls.typecheck_forward(*args, **kwargs)
2722
2729
 
2723
2730
  # DTensor tracks its own placement metadata; the SPMD type checker
2724
2731
  # should not interfere with DTensor operations. This covers
@@ -2908,10 +2915,9 @@ class _SpmdTypeMode(torch.overrides.TorchFunctionMode):
2908
2915
  f"checking. Use "
2909
2916
  f"{register_local_autograd_function.__name__}("
2910
2917
  f"{autograd_cls.__name__}) to mark it as safe "
2911
- f"for type propagation, and provide "
2912
- f"register_autograd_function("
2913
- f"{autograd_cls.__name__}) for a custom "
2914
- f"typecheck_forward."
2918
+ f"for type propagation, or define "
2919
+ f"{autograd_cls.__name__}.spmd_typecheck for a custom "
2920
+ f"typecheck rule."
2915
2921
  )
2916
2922
  return result
2917
2923
 
@@ -0,0 +1,50 @@
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
+ """Lightweight registries for local SPMD type propagation."""
8
+
9
+ from __future__ import annotations
10
+
11
+ from collections.abc import Callable
12
+
13
+ _LOCAL_AUTOGRAD_FUNCTIONS: set[type] = set()
14
+ _LOCAL_BACKWARD_HOOKS: set[Callable] = set()
15
+
16
+
17
+ def register_local_autograd_function(cls: type) -> type:
18
+ """Register an autograd.Function subclass as local-only for SPMD type checking.
19
+
20
+ Local-only means the function's forward operates element-wise (or more
21
+ generally, does not rearrange data across the tensor in a way that would
22
+ change its sharding type). It must not perform collectives or cross-device
23
+ communication. For functions that do, use ``register_autograd_function``
24
+ with custom typechecking instead.
25
+
26
+ Registered functions get the standard local type propagation rule when
27
+ type checking is active:
28
+
29
+ - Inputs may freely mix R and V types; the output is R unless any input
30
+ is V, in which case it is V.
31
+ - All-I inputs produce I outputs.
32
+ - R/V and I cannot be mixed.
33
+ - P is forbidden.
34
+
35
+ Unregistered autograd functions that reach the type checker leave their
36
+ outputs untyped or raise in strict mode.
37
+ """
38
+ _LOCAL_AUTOGRAD_FUNCTIONS.add(cls)
39
+ return cls
40
+
41
+
42
+ def register_local_backward_hook(fn: Callable) -> Callable:
43
+ """Declare that ``fn`` does not alter SPMD types when it runs in backward.
44
+
45
+ Analogous to ``register_local_autograd_function``, the hook's backward is
46
+ treated as local with no collectives or type-changing effects on gradients.
47
+ This covers both full backward post-hooks and pre-hooks.
48
+ """
49
+ _LOCAL_BACKWARD_HOOKS.add(fn)
50
+ return fn
@@ -25,6 +25,7 @@ need the annotation APIs.
25
25
  from __future__ import annotations
26
26
 
27
27
  import builtins
28
+ import inspect
28
29
  import logging
29
30
  import os
30
31
  from contextlib import AbstractContextManager, contextmanager
@@ -32,6 +33,9 @@ from typing import Any, Callable, overload, TypeAlias
32
33
 
33
34
  import torch
34
35
  from spmd_types._frame import _get_user_frame
36
+ from spmd_types._local_registration import ( # noqa: F401
37
+ register_local_autograd_function,
38
+ )
35
39
  from spmd_types._mesh_axis import MeshAxis
36
40
  from spmd_types._scalar_sentinel import _Scalar
37
41
  from spmd_types._state import _no_typecheck_context, current_mesh, is_type_checking
@@ -731,43 +735,37 @@ def mutate_type(
731
735
  # Autograd function registration
732
736
  # =============================================================================
733
737
 
734
- # Sets of autograd.Function subclasses registered for type checking.
735
- # _LOCAL_AUTOGRAD_FUNCTIONS: element-wise / local-only functions.
736
- # _TYPECHECK_AUTOGRAD_FUNCTIONS: functions with custom typecheck_forward.
737
- _LOCAL_AUTOGRAD_FUNCTIONS: set[type] = set()
738
+ # Autograd.Function subclasses with custom typechecking.
738
739
  _TYPECHECK_AUTOGRAD_FUNCTIONS: set[type] = set()
739
740
 
740
741
 
741
- def register_local_autograd_function(cls: type) -> type:
742
- """Register an autograd.Function subclass as local-only for SPMD type checking.
743
-
744
- Local-only means the function's forward operates element-wise (or more
745
- generally, does not rearrange data across the tensor in a way that would
746
- change its sharding type). It must NOT perform any collectives or
747
- cross-device communication. For functions that do, use
748
- :func:`register_autograd_function` with a ``typecheck_forward`` method instead.
749
-
750
- Registered functions get the standard local type propagation rule when
751
- type checking is active:
742
+ def _run_autograd_spmd_typecheck(
743
+ cls: type,
744
+ func: Callable[..., object],
745
+ args: tuple[object, ...],
746
+ ) -> object:
747
+ signature = inspect.signature(cls.forward)
748
+ has_ctx = cls.setup_context is torch.autograd.Function.setup_context
749
+ bound = signature.bind(*(args if not has_ctx else (None, *args)))
750
+ bound.apply_defaults()
751
+ forward_args = dict(bound.arguments)
752
+ if has_ctx:
753
+ forward_args.pop(next(iter(signature.parameters)))
752
754
 
753
- - Inputs may freely mix R and V types; the output is R unless any input
754
- is V, in which case it is V.
755
- - All-I inputs produce I outputs.
756
- - R/V and I cannot be mixed.
757
- - P is forbidden.
755
+ outputs = func(*args)
756
+ hook = cls.spmd_typecheck
757
+ names = tuple(inspect.signature(hook).parameters)[1:]
758
+ hook(outputs, **{name: forward_args[name] for name in names})
758
759
 
759
- Unregistered autograd functions that reach the type checker will leave
760
- their outputs untyped (or raise in strict mode), since the checker
761
- cannot know whether the function is safe for automatic type propagation.
760
+ return outputs
762
761
 
763
- Can be used as a decorator::
764
762
 
765
- @register_local_autograd_function
766
- class MyOp(torch.autograd.Function):
767
- ...
768
- """
769
- _LOCAL_AUTOGRAD_FUNCTIONS.add(cls)
770
- return cls
763
+ def _get_autograd_spmd_typecheck(cls: type) -> Callable[..., object] | None:
764
+ """Return and validate an autograd.Function's SPMD typecheck hook."""
765
+ hook = getattr(cls, "spmd_typecheck", None)
766
+ if hook is not None and not callable(hook):
767
+ raise TypeError(f"{cls.__name__}.spmd_typecheck must be callable")
768
+ return hook
771
769
 
772
770
 
773
771
  def register_autograd_function(cls: type) -> type:
@@ -777,34 +775,44 @@ def register_autograd_function(cls: type) -> type:
777
775
  non-trivial type transformations where the default local-only rule
778
776
  would produce incorrect output types.
779
777
 
780
- The class must define a ``typecheck_forward`` staticmethod that receives
781
- the same positional/keyword arguments as ``.apply()``. Inside, it should
782
- call ``assert_type`` on inputs, call ``.apply()`` to run the function,
783
- then call ``assert_type`` on the output. This is symmetric with
784
- ``typecheck_forward`` on ``nn.Module`` subclasses in llama4x::
778
+ A class may define an ``spmd_typecheck`` staticmethod. Its presence is
779
+ detected automatically, so new classes do not need this decorator. The
780
+ hook runs after the function, receives its exact return value as the first
781
+ argument, and names only the forward arguments it needs::
785
782
 
786
- @register_autograd_function
787
783
  class MyCollectiveOp(torch.autograd.Function):
788
784
  @staticmethod
789
785
  def forward(ctx, x, y):
790
786
  return x + y
791
787
 
792
788
  @staticmethod
793
- def typecheck_forward(x, y):
789
+ def spmd_typecheck(outputs, *, x):
794
790
  assert_type(x, {pg: S(-1)})
795
- out = MyCollectiveOp.apply(x, y)
796
- assert_type(out, {pg: R})
797
- return out
791
+ assert_type_like(outputs, x, {pg: R})
798
792
 
799
793
  @staticmethod
800
794
  def backward(ctx, g):
801
795
  return g, g
796
+
797
+ The legacy ``typecheck_forward`` wrapper remains supported for existing
798
+ registrations, but cannot be combined with ``spmd_typecheck``.
802
799
  """
803
- if not callable(getattr(cls, "typecheck_forward", None)):
800
+ legacy_hook = getattr(cls, "typecheck_forward", None)
801
+ spmd_typecheck = _get_autograd_spmd_typecheck(cls)
802
+
803
+ if legacy_hook is not None and spmd_typecheck is not None:
804
804
  raise TypeError(
805
- f"{cls.__name__} must define a typecheck_forward staticmethod "
805
+ f"{cls.__name__} cannot define typecheck_forward together with "
806
+ "spmd_typecheck"
807
+ )
808
+ if legacy_hook is None and spmd_typecheck is None:
809
+ raise TypeError(
810
+ f"{cls.__name__} must define typecheck_forward or spmd_typecheck "
806
811
  f"when using @register_autograd_function"
807
812
  )
813
+ if legacy_hook is not None and not callable(legacy_hook):
814
+ raise TypeError(f"{cls.__name__}.typecheck_forward must be callable")
815
+
808
816
  _TYPECHECK_AUTOGRAD_FUNCTIONS.add(cls)
809
817
  return cls
810
818
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spmd_types
3
- Version: 0.2.3
3
+ Version: 0.2.4
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
@@ -10,6 +10,7 @@ spmd_types/_dtensor_checker.py
10
10
  spmd_types/_dtype_utils.py
11
11
  spmd_types/_frame.py
12
12
  spmd_types/_local.py
13
+ spmd_types/_local_registration.py
13
14
  spmd_types/_mesh.py
14
15
  spmd_types/_mesh_axis.py
15
16
  spmd_types/_mesh_region.py
File without changes
File without changes
File without changes