haliax 1.4.dev400__tar.gz → 1.4.dev403__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.
- {haliax-1.4.dev400 → haliax-1.4.dev403}/PKG-INFO +1 -1
- haliax-1.4.dev403/src/haliax/__about__.py +1 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/__init__.py +2 -0
- haliax-1.4.dev403/src/haliax/field.py +38 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/partitioning.py +90 -30
- haliax-1.4.dev403/tests/test_field.py +19 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_partitioning.py +48 -1
- haliax-1.4.dev400/src/haliax/__about__.py +0 -1
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.coveragerc +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.flake8 +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.github/workflows/run_tests.yaml +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.gitignore +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.playbooks/add-types.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.playbooks/wrap-non-named.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/AGENTS.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/LICENSE +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/README.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/api.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/css/material.css +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/faq.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/fp8.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/index.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/indexing.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/matmul.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/nn.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/partitioning.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/primer.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/rearrange.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/requirements.txt +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/scan.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/state-dict.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/tutorial.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/typing.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/docs/vmap.md +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/mkdocs.yml +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/pyproject.toml +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/einsum.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/scan.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/state_dict.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/core.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/haxtyping.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/jax_utils.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/__init__.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/linear.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/pool.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/nn/scan.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/ops.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/random.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/state_dict.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/types.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/util.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/core_test.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_attention.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_axis.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_conv.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_debug.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_dot.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_dtype_typing.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_hof.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_int8.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_moe_linear.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_namedarray_typing.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_nn.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_ops.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_pool.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_random.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_scan.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_scatter_gather.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_state_dict.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_tree_util.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_utils.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/tests/test_visualize_sharding.py +0 -0
- {haliax-1.4.dev400 → haliax-1.4.dev403}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haliax
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.dev403
|
|
4
4
|
Summary: Named Tensors for Legible Deep Learning in JAX
|
|
5
5
|
Project-URL: Homepage, https://github.com/stanford-crfm/haliax
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/stanford-crfm/haliax/issues/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.4.dev403"
|
|
@@ -17,6 +17,7 @@ import haliax.random as random
|
|
|
17
17
|
import haliax.state_dict as state_dict
|
|
18
18
|
import haliax.tree_util as tree_util
|
|
19
19
|
import haliax.util as util
|
|
20
|
+
from .field import field
|
|
20
21
|
|
|
21
22
|
from ._src.dot import dot
|
|
22
23
|
from ._src.einsum import einsum
|
|
@@ -932,6 +933,7 @@ __all__ = [
|
|
|
932
933
|
"tree_util",
|
|
933
934
|
"nn",
|
|
934
935
|
"state_dict",
|
|
936
|
+
"field",
|
|
935
937
|
"Axis",
|
|
936
938
|
"AxisSpec",
|
|
937
939
|
"AxisSelection",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
import equinox as eqx
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def field(
|
|
9
|
+
*,
|
|
10
|
+
converter: Callable[[Any], Any] | None = None,
|
|
11
|
+
static: bool = False,
|
|
12
|
+
axis_names: tuple[str, ...] | None = None,
|
|
13
|
+
**kwargs,
|
|
14
|
+
):
|
|
15
|
+
"""Wrapper around :func:`equinox.field` with optional ``axis_names`` metadata.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
converter: Optional function applied to the value during dataclass initialisation.
|
|
19
|
+
static: Whether the field is static in the PyTree.
|
|
20
|
+
axis_names: Optional axis names associated with array fields. Cannot be
|
|
21
|
+
specified together with ``static=True``.
|
|
22
|
+
**kwargs: Additional keyword arguments forwarded to :func:`dataclasses.field`.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
A dataclasses field configured like :func:`equinox.field` with additional
|
|
26
|
+
``axis_names`` metadata.
|
|
27
|
+
"""
|
|
28
|
+
if static and axis_names is not None:
|
|
29
|
+
raise ValueError("axis_names cannot be specified together with static=True")
|
|
30
|
+
|
|
31
|
+
metadata = dict(kwargs.pop("metadata", {}))
|
|
32
|
+
metadata["axis_names"] = axis_names
|
|
33
|
+
|
|
34
|
+
field_kwargs = {}
|
|
35
|
+
if converter is not None:
|
|
36
|
+
field_kwargs["converter"] = converter
|
|
37
|
+
|
|
38
|
+
return eqx.field(static=static, metadata=metadata, **field_kwargs, **kwargs)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import contextlib
|
|
2
|
+
import dataclasses
|
|
2
3
|
import functools
|
|
3
4
|
import threading
|
|
4
5
|
import typing
|
|
@@ -177,24 +178,21 @@ def shard_with_axis_mapping(x: T, mapping: ResourceMapping, mesh: Optional[Mesh]
|
|
|
177
178
|
return shard(x, mapping, mesh)
|
|
178
179
|
|
|
179
180
|
|
|
180
|
-
def
|
|
181
|
+
def pspec_for(
|
|
181
182
|
tree: PyTree,
|
|
182
183
|
resource_mapping: Optional[ResourceMapping] = None,
|
|
183
184
|
preserve_existing_shardings: bool = True,
|
|
184
185
|
use_auto_sharding: bool = True,
|
|
185
|
-
mesh: Optional[Mesh] = None,
|
|
186
186
|
) -> PyTree:
|
|
187
|
-
"""
|
|
188
|
-
Infer the sharding for a module, to be used with named_jit.
|
|
189
|
-
The basic idea is to tree all NamedArrays as leaves for the purposes of this function,
|
|
190
|
-
and to create NamedShardings from those names plus the resource_mapping.
|
|
191
|
-
If preserve_existing_shardings is True, then NamedArrays that are already sharded are left alone.
|
|
187
|
+
"""Infer the :class:`PartitionSpec` for a module.
|
|
192
188
|
|
|
193
|
-
|
|
189
|
+
This behaves like :func:`infer_resource_partitions` but returns ``PartitionSpec``
|
|
190
|
+
objects instead of :class:`~jax.sharding.NamedSharding`. It is primarily a helper
|
|
191
|
+
for :func:`infer_resource_partitions` but may be useful when only the partition
|
|
192
|
+
specification is required.
|
|
194
193
|
|
|
195
|
-
If
|
|
196
|
-
|
|
197
|
-
don't have a sharding.
|
|
194
|
+
If ``preserve_existing_shardings`` is ``True``, then arrays that already have a
|
|
195
|
+
sharding are left untouched and ``None`` is returned for those leaves.
|
|
198
196
|
"""
|
|
199
197
|
if resource_mapping is None:
|
|
200
198
|
resource_mapping = current_thread_local_mapping()
|
|
@@ -202,35 +200,57 @@ def infer_resource_partitions(
|
|
|
202
200
|
if resource_mapping is None:
|
|
203
201
|
raise ValueError("No resource mapping found")
|
|
204
202
|
|
|
205
|
-
mesh = mesh or _get_mesh()
|
|
206
|
-
assert not isinstance(mesh, dict)
|
|
207
|
-
|
|
208
203
|
def partition_spec(node: typing.Any):
|
|
209
204
|
if isinstance(node, NamedArray):
|
|
210
205
|
# If our NamedArray doesn't have an array (or a shapedtypestruct), we can't shard it
|
|
211
|
-
# so better to not try
|
|
212
206
|
if not is_jax_array_like(node.array):
|
|
213
207
|
return None
|
|
214
208
|
|
|
215
|
-
if preserve_existing_shardings
|
|
216
|
-
current_sharding = getattr(node.array, "sharding", None)
|
|
217
|
-
else:
|
|
218
|
-
current_sharding = None
|
|
219
|
-
|
|
209
|
+
current_sharding = getattr(node.array, "sharding", None) if preserve_existing_shardings else None
|
|
220
210
|
if current_sharding is not None:
|
|
221
|
-
return
|
|
211
|
+
return None
|
|
222
212
|
else:
|
|
223
|
-
|
|
224
|
-
|
|
213
|
+
return pspec_for_axis(node.axes, resource_mapping)
|
|
214
|
+
elif isinstance(node, eqx.Module):
|
|
215
|
+
# handle eqx.Module explicitly so that we can look at axis_names metadata
|
|
216
|
+
updates: dict[str, typing.Any] = {}
|
|
217
|
+
for field in dataclasses.fields(node):
|
|
218
|
+
if field.metadata.get("static", False):
|
|
219
|
+
continue
|
|
220
|
+
|
|
221
|
+
value = getattr(node, field.name)
|
|
222
|
+
axis_names = field.metadata.get("axis_names") if field.metadata is not None else None
|
|
223
|
+
if axis_names is not None and is_jax_array_like(value):
|
|
224
|
+
current_sharding = (
|
|
225
|
+
getattr(value, "sharding", None) if preserve_existing_shardings else None
|
|
226
|
+
)
|
|
227
|
+
if current_sharding is not None:
|
|
228
|
+
updates[field.name] = None
|
|
229
|
+
else:
|
|
230
|
+
updates[field.name] = pspec_for_axis(axis_names, resource_mapping)
|
|
231
|
+
else:
|
|
232
|
+
updates[field.name] = htu.tree_map(
|
|
233
|
+
partition_spec, value, is_leaf=lambda x: isinstance(x, eqx.Module)
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
new_node = object.__new__(type(node))
|
|
237
|
+
for field in dataclasses.fields(node):
|
|
238
|
+
object.__setattr__(
|
|
239
|
+
new_node,
|
|
240
|
+
field.name,
|
|
241
|
+
updates.get(field.name, getattr(node, field.name)),
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
return new_node
|
|
225
245
|
elif is_jax_array_like(node):
|
|
226
246
|
sharding = getattr(node, "sharding", None)
|
|
227
247
|
# TODO: these are usually replicated. Is there a better way to tell?
|
|
228
248
|
if node.shape == ():
|
|
229
|
-
return
|
|
249
|
+
return PartitionSpec()
|
|
230
250
|
elif isinstance(sharding, SingleDeviceSharding):
|
|
231
|
-
return
|
|
232
|
-
elif sharding is not None:
|
|
233
|
-
return
|
|
251
|
+
return PartitionSpec(None)
|
|
252
|
+
elif sharding is not None and preserve_existing_shardings:
|
|
253
|
+
return None
|
|
234
254
|
# elif use_auto_sharding:
|
|
235
255
|
# TODO: auto doesn't seem to really work reliably yet
|
|
236
256
|
# compat between 0.4.10 and 0.4.11
|
|
@@ -238,13 +258,52 @@ def infer_resource_partitions(
|
|
|
238
258
|
# return AUTO(mesh)
|
|
239
259
|
# else:
|
|
240
260
|
# return AUTO
|
|
241
|
-
return
|
|
261
|
+
return PartitionSpec(None)
|
|
242
262
|
elif isinstance(node, (bool, float, complex, int)):
|
|
243
|
-
return
|
|
263
|
+
return PartitionSpec()
|
|
244
264
|
else:
|
|
245
265
|
return None
|
|
246
266
|
|
|
247
|
-
return htu.tree_map(partition_spec, tree)
|
|
267
|
+
return htu.tree_map(partition_spec, tree, is_leaf=lambda x: isinstance(x, eqx.Module))
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def infer_resource_partitions(
|
|
271
|
+
tree: PyTree,
|
|
272
|
+
resource_mapping: Optional[ResourceMapping] = None,
|
|
273
|
+
preserve_existing_shardings: bool = True,
|
|
274
|
+
use_auto_sharding: bool = True,
|
|
275
|
+
mesh: Optional[Mesh] = None,
|
|
276
|
+
) -> PyTree:
|
|
277
|
+
"""
|
|
278
|
+
Infer the sharding for a module, to be used with ``named_jit``.
|
|
279
|
+
|
|
280
|
+
This first calls :func:`pspec_for` to compute ``PartitionSpec`` objects and then
|
|
281
|
+
wraps them in :class:`~jax.sharding.NamedSharding` using the provided mesh. If
|
|
282
|
+
``preserve_existing_shardings`` is ``True``, then arrays that are already sharded
|
|
283
|
+
retain their current sharding.
|
|
284
|
+
"""
|
|
285
|
+
pspecs = pspec_for(
|
|
286
|
+
tree,
|
|
287
|
+
resource_mapping=resource_mapping,
|
|
288
|
+
preserve_existing_shardings=preserve_existing_shardings,
|
|
289
|
+
use_auto_sharding=use_auto_sharding,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
mesh = mesh or _get_mesh()
|
|
293
|
+
assert not isinstance(mesh, dict)
|
|
294
|
+
|
|
295
|
+
def to_sharding(node: typing.Any, spec: typing.Any):
|
|
296
|
+
if spec is None:
|
|
297
|
+
if isinstance(node, NamedArray):
|
|
298
|
+
return getattr(node.array, "sharding", None)
|
|
299
|
+
elif is_jax_array_like(node):
|
|
300
|
+
return getattr(node, "sharding", None)
|
|
301
|
+
else:
|
|
302
|
+
return None
|
|
303
|
+
else:
|
|
304
|
+
return NamedSharding(mesh, spec)
|
|
305
|
+
|
|
306
|
+
return htu.tree_map(to_sharding, tree, pspecs)
|
|
248
307
|
|
|
249
308
|
|
|
250
309
|
class WrappedCallable(typing.Protocol[Args, R]):
|
|
@@ -659,6 +718,7 @@ __all__ = [
|
|
|
659
718
|
"auto_sharded",
|
|
660
719
|
"shard",
|
|
661
720
|
"shard_with_axis_mapping",
|
|
721
|
+
"pspec_for",
|
|
662
722
|
"infer_resource_partitions",
|
|
663
723
|
"named_jit",
|
|
664
724
|
"fsdp",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import jax.numpy as jnp
|
|
2
|
+
import equinox as eqx
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
import haliax as hax
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class M(eqx.Module):
|
|
9
|
+
a: jnp.ndarray = hax.field(axis_names=("batch",))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_axis_names_metadata():
|
|
13
|
+
field = M.__dataclass_fields__["a"]
|
|
14
|
+
assert field.metadata["axis_names"] == ("batch",)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_axis_names_static_exclusive():
|
|
18
|
+
with pytest.raises(ValueError):
|
|
19
|
+
hax.field(static=True, axis_names=("x",))
|
|
@@ -7,7 +7,13 @@ from jaxtyping import Array
|
|
|
7
7
|
|
|
8
8
|
import haliax as hax
|
|
9
9
|
from haliax import Axis, NamedArray
|
|
10
|
-
from haliax.partitioning import
|
|
10
|
+
from haliax.partitioning import (
|
|
11
|
+
ResourceAxis,
|
|
12
|
+
axis_mapping,
|
|
13
|
+
infer_resource_partitions,
|
|
14
|
+
named_jit,
|
|
15
|
+
pspec_for,
|
|
16
|
+
)
|
|
11
17
|
from test_utils import skip_if_not_enough_devices
|
|
12
18
|
|
|
13
19
|
|
|
@@ -40,6 +46,47 @@ def test_infer_named_axes():
|
|
|
40
46
|
assert axes.unnamed1.is_fully_replicated
|
|
41
47
|
|
|
42
48
|
|
|
49
|
+
def test_pspec_for_named_axes():
|
|
50
|
+
mesh = Mesh(np.array(jax.devices()).reshape(-1, 1), (ResourceAxis.DATA, ResourceAxis.MODEL))
|
|
51
|
+
with axis_mapping(resource_map), mesh:
|
|
52
|
+
mod = MyModule(named=hax.ones((Dim1, Dim2, Dim3)), unnamed1=jnp.ones(Dim2.size), static_field=1)
|
|
53
|
+
|
|
54
|
+
specs: MyModule = pspec_for(mod, preserve_existing_shardings=False)
|
|
55
|
+
|
|
56
|
+
spec = PartitionSpec(None, ResourceAxis.DATA, ResourceAxis.MODEL)
|
|
57
|
+
|
|
58
|
+
assert specs.named == spec
|
|
59
|
+
assert specs.unnamed1 == PartitionSpec(None)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ArrayModule(eqx.Module):
|
|
63
|
+
arr: Array = hax.field(axis_names=("dim2", "dim3"))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_pspec_for_plain_array_axis_names():
|
|
67
|
+
mesh = Mesh(np.array(jax.devices()).reshape(-1, 1), (ResourceAxis.DATA, ResourceAxis.MODEL))
|
|
68
|
+
with axis_mapping(resource_map), mesh:
|
|
69
|
+
mod = ArrayModule(jnp.ones((Dim2.size, Dim3.size)))
|
|
70
|
+
|
|
71
|
+
specs: ArrayModule = pspec_for(mod, preserve_existing_shardings=False)
|
|
72
|
+
|
|
73
|
+
assert specs.arr == PartitionSpec(ResourceAxis.DATA, ResourceAxis.MODEL)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class NestedArrayModule(eqx.Module):
|
|
77
|
+
inner: ArrayModule
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_pspec_for_plain_array_axis_names_nested_module():
|
|
81
|
+
mesh = Mesh(np.array(jax.devices()).reshape(-1, 1), (ResourceAxis.DATA, ResourceAxis.MODEL))
|
|
82
|
+
with axis_mapping(resource_map), mesh:
|
|
83
|
+
mod = NestedArrayModule(ArrayModule(jnp.ones((Dim2.size, Dim3.size))))
|
|
84
|
+
|
|
85
|
+
specs: NestedArrayModule = pspec_for(mod, preserve_existing_shardings=False)
|
|
86
|
+
|
|
87
|
+
assert specs.inner.arr == PartitionSpec(ResourceAxis.DATA, ResourceAxis.MODEL)
|
|
88
|
+
|
|
89
|
+
|
|
43
90
|
class MyModuleInit(eqx.Module):
|
|
44
91
|
named: NamedArray
|
|
45
92
|
unnamed1: Array
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.4.dev400"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|