haliax 1.4.dev322__tar.gz → 1.4.dev324__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 (103) hide show
  1. {haliax-1.4.dev322 → haliax-1.4.dev324}/PKG-INFO +1 -2
  2. haliax-1.4.dev324/src/haliax/__about__.py +1 -0
  3. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/state_dict.py +45 -29
  4. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/core.py +3 -1
  5. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/jax_utils.py +1 -1
  6. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/scan.py +6 -3
  7. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/state_dict.py +16 -1
  8. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/types.py +12 -1
  9. haliax-1.4.dev322/src/haliax/__about__.py +0 -1
  10. {haliax-1.4.dev322 → haliax-1.4.dev324}/.coveragerc +0 -0
  11. {haliax-1.4.dev322 → haliax-1.4.dev324}/.flake8 +0 -0
  12. {haliax-1.4.dev322 → haliax-1.4.dev324}/.github/workflows/publish_dev.yaml +0 -0
  13. {haliax-1.4.dev322 → haliax-1.4.dev324}/.github/workflows/run_pre_commit.yaml +0 -0
  14. {haliax-1.4.dev322 → haliax-1.4.dev324}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
  15. {haliax-1.4.dev322 → haliax-1.4.dev324}/.github/workflows/run_tests.yaml +0 -0
  16. {haliax-1.4.dev322 → haliax-1.4.dev324}/.gitignore +0 -0
  17. {haliax-1.4.dev322 → haliax-1.4.dev324}/.pre-commit-config.yaml +0 -0
  18. {haliax-1.4.dev322 → haliax-1.4.dev324}/.readthedocs.yaml +0 -0
  19. {haliax-1.4.dev322 → haliax-1.4.dev324}/CONTRIBUTING.md +0 -0
  20. {haliax-1.4.dev322 → haliax-1.4.dev324}/LICENSE +0 -0
  21. {haliax-1.4.dev322 → haliax-1.4.dev324}/README.md +0 -0
  22. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/api.md +0 -0
  23. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/broadcasting.md +0 -0
  24. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/cheatsheet.md +0 -0
  25. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/css/material.css +0 -0
  26. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/css/mkdocstrings.css +0 -0
  27. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/faq.md +0 -0
  28. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/data_parallel_mesh.png +0 -0
  29. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/data_parallel_mesh_replicated.png +0 -0
  30. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/device_mesh_1d.png +0 -0
  31. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/device_mesh_1d_zero.png +0 -0
  32. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/device_mesh_2d.png +0 -0
  33. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
  34. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
  35. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
  36. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
  37. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_zero.png +0 -0
  38. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/fp8.md +0 -0
  39. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/hof.md +0 -0
  40. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/index.md +0 -0
  41. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/indexing.md +0 -0
  42. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/matmul.md +0 -0
  43. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/nn.md +0 -0
  44. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/partitioning.md +0 -0
  45. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/rearrange.ipynb +0 -0
  46. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/rearrange.md +0 -0
  47. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/requirements.txt +0 -0
  48. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/state-dict.md +0 -0
  49. {haliax-1.4.dev322 → haliax-1.4.dev324}/docs/tutorial.md +0 -0
  50. {haliax-1.4.dev322 → haliax-1.4.dev324}/mkdocs.yml +0 -0
  51. {haliax-1.4.dev322 → haliax-1.4.dev324}/pyproject.toml +0 -0
  52. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/__init__.py +0 -0
  53. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/__init__.py +0 -0
  54. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/compile_utils.py +0 -0
  55. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/dot.py +0 -0
  56. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/einsum.py +0 -0
  57. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/fp8.py +0 -0
  58. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/parsing.py +0 -0
  59. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/rearrange.py +0 -0
  60. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/_src/util.py +0 -0
  61. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/axis.py +0 -0
  62. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/debug.py +0 -0
  63. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/hof.py +0 -0
  64. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/__init__.py +0 -0
  65. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/activations.py +0 -0
  66. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/attention.py +0 -0
  67. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/conv.py +0 -0
  68. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/dropout.py +0 -0
  69. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/embedding.py +0 -0
  70. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/linear.py +0 -0
  71. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/loss.py +0 -0
  72. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/mlp.py +0 -0
  73. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/normalization.py +0 -0
  74. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/nn/pool.py +0 -0
  75. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/ops.py +0 -0
  76. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/partitioning.py +0 -0
  77. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/quantization.py +0 -0
  78. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/random.py +0 -0
  79. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/specialized_fns.py +0 -0
  80. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/tree_util.py +0 -0
  81. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/util.py +0 -0
  82. {haliax-1.4.dev322 → haliax-1.4.dev324}/src/haliax/wrap.py +0 -0
  83. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/core_test.py +0 -0
  84. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_attention.py +0 -0
  85. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_axis.py +0 -0
  86. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_conv.py +0 -0
  87. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_debug.py +0 -0
  88. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_dot.py +0 -0
  89. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_einsum.py +0 -0
  90. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_fp8.py +0 -0
  91. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_hof.py +0 -0
  92. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_nn.py +0 -0
  93. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_ops.py +0 -0
  94. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_parsing.py +0 -0
  95. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_partitioning.py +0 -0
  96. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_pool.py +0 -0
  97. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_random.py +0 -0
  98. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_rearrange.py +0 -0
  99. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_scan.py +0 -0
  100. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_specialized_fns.py +0 -0
  101. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_state_dict.py +0 -0
  102. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_tree_util.py +0 -0
  103. {haliax-1.4.dev322 → haliax-1.4.dev324}/tests/test_utils.py +0 -0
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: haliax
3
- Version: 1.4.dev322
3
+ Version: 1.4.dev324
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/
7
7
  Project-URL: Documentation, https://haliax.readthedocs.io/en/latest/
8
8
  Author-email: David Hall <dlwh@cs.stanford.edu>
9
- License-File: LICENSE
10
9
  Classifier: Development Status :: 4 - Beta
11
10
  Classifier: Intended Audience :: Science/Research
12
11
  Classifier: License :: OSI Approved :: Apache Software License
@@ -0,0 +1 @@
1
+ __version__ = "1.4.dev324"
@@ -16,7 +16,7 @@ from jaxtyping import PyTree
16
16
  import haliax.partitioning as partitioning
17
17
  from haliax._src.util import index_where
18
18
  from haliax.core import NamedArray, named
19
- from haliax.jax_utils import is_jax_array_like
19
+ from haliax.jax_utils import is_jax_array_like, is_scalarish
20
20
 
21
21
 
22
22
  try:
@@ -166,7 +166,9 @@ def to_state_dict(tree: PyTree, prefix: Optional[str] = None) -> StateDict:
166
166
  Returns:
167
167
  The state dict representation of the input tree.
168
168
  """
169
- if isinstance(tree, eqx.Module):
169
+ if tree is None:
170
+ return {}
171
+ elif isinstance(tree, eqx.Module):
170
172
  if hasattr(tree, "to_state_dict"):
171
173
  state_dict = tree.to_state_dict(prefix)
172
174
  else:
@@ -198,6 +200,11 @@ def to_state_dict(tree: PyTree, prefix: Optional[str] = None) -> StateDict:
198
200
  state_dict = {}
199
201
  else:
200
202
  raise ValueError("Cannot convert a leaf value to a state dict without a prefix")
203
+ elif is_scalarish(tree):
204
+ if prefix is not None:
205
+ state_dict = {prefix: tree}
206
+ else:
207
+ raise ValueError("Cannot convert a leaf value to a state dict without a prefix")
201
208
  else:
202
209
  raise ValueError(f"Unsupported type {type(tree)}")
203
210
 
@@ -291,37 +298,46 @@ def to_numpy_state_dict(model, prefix: Optional[str] = None) -> StateDict:
291
298
  with jax.default_device(jax.local_devices(backend="cpu")[0]):
292
299
 
293
300
  def get_to_cpu(arr):
294
- if not is_jax_array_like(arr):
301
+ if is_scalarish(arr):
302
+ return arr
303
+ elif not is_jax_array_like(arr):
295
304
  return arr
296
305
  elif isinstance(arr, np.ndarray):
297
306
  return arr
298
- elif arr.is_fully_addressable:
299
- r = np.array(arr)
300
- return r
301
- else:
302
- # unfortunately, jax's allgather seems to replicate to every device rather than every host
303
- # which doesn't work for ~7B parameter models on TPU (assuming we also have optimizer state)
304
- # this approach limits us to <64B parameters, but that's good enough for now
305
- # we're going to do something a bit fancy, where we shard the model into a (process, device) mesh,
306
- # then look for some axis along which we can shard the array, and then we'll do an allgather
307
- # via pjit. If we can't find one, we'll just fully replicate since it probably isn't that big.
308
- # TODO: ensure that this mesh arranges devices correctly
309
- # (jax seems to do this internally itself, so we should be fine?)
310
- process_mesh = Mesh(np.array(jax.devices()).reshape((jax.process_count(), -1)), ("process", "device"))
311
- # now we need to find an axis along which we can shard the array.
312
- # for this, we need to find an axis s.t. size(axis) % local_devices == 0
313
-
314
- try:
315
- axis_to_shard = index_where(
316
- lambda axis_size: axis_size % process_mesh.devices.size == 0, arr.shape
307
+ elif is_jax_array_like(arr):
308
+ if arr.is_fully_addressable:
309
+ r = np.array(arr)
310
+ return r
311
+ else:
312
+ # unfortunately, jax's allgather seems to replicate to every device rather than every host
313
+ # which doesn't work for ~7B parameter models on TPU (assuming we also have optimizer state)
314
+ # this approach limits us to <64B parameters, but that's good enough for now
315
+ # we're going to do something a bit fancy, where we shard the model into a (process, device) mesh,
316
+ # then look for some axis along which we can shard the array, and then we'll do an allgather
317
+ # via pjit. If we can't find one, we'll just fully replicate since it probably isn't that big.
318
+ # TODO: ensure that this mesh arranges devices correctly
319
+ # (jax seems to do this internally itself, so we should be fine?)
320
+ process_mesh = Mesh(
321
+ np.array(jax.devices()).reshape((jax.process_count(), -1)), ("process", "device")
317
322
  )
318
- except ValueError:
319
- return np.array(arr)
320
-
321
- shardings = [None if i != axis_to_shard else "device" for i in range(len(arr.shape))]
322
- sharding = NamedSharding(process_mesh, PartitionSpec(*shardings))
323
- out = jax.jit(lambda x: x, out_shardings=sharding)(arr)
324
- return np.array(out)
323
+ # now we need to find an axis along which we can shard the array.
324
+ # for this, we need to find an axis s.t. size(axis) % local_devices == 0
325
+
326
+ try:
327
+ axis_to_shard = index_where(
328
+ lambda axis_size: axis_size % process_mesh.devices.size == 0, arr.shape
329
+ )
330
+ except ValueError:
331
+ return np.array(arr)
332
+
333
+ shardings = [None if i != axis_to_shard else "device" for i in range(len(arr.shape))]
334
+ sharding = NamedSharding(process_mesh, PartitionSpec(*shardings))
335
+ out = jax.jit(lambda x: x, out_shardings=sharding)(arr)
336
+ return np.array(out)
337
+ elif is_scalarish(arr):
338
+ return np.asarray(arr)
339
+ else:
340
+ raise ValueError(f"Unsupported type {type(arr)}")
325
341
 
326
342
  # need to make sure the model is on *this machine* and *this machine's CPU* before saving
327
343
  model = jax.tree.map(lambda arr: get_to_cpu(arr), model)
@@ -246,7 +246,9 @@ class NamedArray:
246
246
  try:
247
247
  axis_index = index_where(lambda a: a.name == ax_name, self.axes)
248
248
  if axis_index >= 0:
249
- warnings.warn("Found axis with same name but different size.", UserWarning)
249
+ raise RuntimeError(
250
+ f"Found axis with same name but different size: {axis} vs {self.axes[axis_index]}"
251
+ )
250
252
  return axis_index
251
253
  except ValueError:
252
254
  return None
@@ -152,7 +152,7 @@ def is_scalarish(x):
152
152
  if isinstance(x, haliax.NamedArray):
153
153
  return x.ndim == 0
154
154
  else:
155
- return jnp.isscalar(x) or x.shape == ()
155
+ return jnp.isscalar(x) or (getattr(x, "shape", None) == ())
156
156
 
157
157
 
158
158
  def is_on_mac_metal():
@@ -8,7 +8,8 @@ from jax import numpy as jnp
8
8
 
9
9
  import haliax
10
10
  import haliax.util
11
- from haliax.jax_utils import filter_checkpoint
11
+ from haliax.jax_utils import filter_checkpoint, is_jax_array_like
12
+ from haliax.util import is_jax_or_hax_array_like
12
13
 
13
14
  from .._src.state_dict import ModuleWithStateDictSerialization, StateDict, with_prefix
14
15
  from ..axis import Axis
@@ -167,7 +168,9 @@ class BlockSeq(ModuleWithStateDictSerialization, Generic[M]):
167
168
  state_dict: StateDict = {}
168
169
  for i, block in enumerate(self.blocks):
169
170
  my_prefix = with_prefix(prefix, str(i))
170
- state_dict.update(block.to_state_dict(my_prefix))
171
+ # we can't assume to_state_dict is implemented, so we have to do it manually
172
+ block_dict = haliax.state_dict.to_state_dict(block, my_prefix)
173
+ state_dict.update(block_dict)
171
174
 
172
175
  return state_dict
173
176
 
@@ -413,7 +416,7 @@ def _unstack_state_dict(state_dict: StateDict, prefix: Optional[str] = None) ->
413
416
  assert prefix is not None
414
417
 
415
418
  for k, v in state_dict.items():
416
- if k.startswith(prefix) and v is not None:
419
+ if k.startswith(prefix) and is_jax_or_hax_array_like(v):
417
420
  for i, v_i in enumerate(v):
418
421
  new_dict[f"{prefix}{i}.{k[len(prefix):]}"] = v_i
419
422
  else:
@@ -1,5 +1,10 @@
1
1
  from typing import Optional, TypeVar
2
2
 
3
+ import equinox
4
+
5
+ from haliax.jax_utils import is_jax_array_like
6
+ from haliax.types import FilterSpec
7
+
3
8
  from ._src.state_dict import (
4
9
  ModuleWithStateDictSerialization,
5
10
  StateDict,
@@ -18,12 +23,22 @@ from ._src.state_dict import (
18
23
  T = TypeVar("T")
19
24
 
20
25
 
21
- def to_torch_compatible_state_dict(t: T, *, flatten_linear: bool = True, prefix: Optional[str] = None) -> StateDict:
26
+ def to_torch_compatible_state_dict(
27
+ t: T, *, flatten_linear: bool = True, prefix: Optional[str] = None, filter: FilterSpec = is_jax_array_like
28
+ ) -> StateDict:
22
29
  """
23
30
  Convert a tree to a state dict that is compatible with torch-style state dicts.
24
31
 
25
32
  This applies [haliax.state_dict.flatten_linear_layers][] followed by [haliax.state_dict.to_state_dict][]
33
+
34
+ Args:
35
+ t: The tree to convert
36
+ flatten_linear: Whether to flatten linear layers
37
+ prefix: The prefix to use for the state dict keys
38
+ filter: The filter to use for selecting which nodes to include in the state dict. By default, this includes only
39
+ array-like objects (e.g. JAX and NumPy arrays).
26
40
  """
41
+ t = equinox.filter(t, filter)
27
42
  if flatten_linear:
28
43
  t = flatten_linear_layers(t)
29
44
  return to_numpy_state_dict(t, prefix=prefix)
@@ -1,8 +1,9 @@
1
- from typing import Any, Literal, Protocol, Tuple, TypeAlias, Union
1
+ from typing import Any, Callable, Literal, Protocol, Tuple, TypeAlias, Union
2
2
 
3
3
  import jax.numpy as jnp
4
4
  import numpy as np
5
5
  from jax.lax import Precision
6
+ from jaxtyping import PyTree
6
7
 
7
8
 
8
9
  DType: TypeAlias = np.dtype
@@ -30,3 +31,13 @@ IntScalar = Union[int, jnp.ndarray]
30
31
  PrecisionLike = Union[None, str, Precision, Tuple[str, str], Tuple[Precision, Precision]]
31
32
 
32
33
  GatherScatterModeStr = Literal["promise_in_bounds", "clip", "drop", "fill"]
34
+
35
+
36
+ FilterSpec = Union[bool, Callable[[Any], bool]]
37
+ """
38
+ A filter specification. Typically used on a pytree to filter out certain subtrees. Boolean values are
39
+ treated as-is, while callables are called on each element of the pytree. If the callable returns True, the element
40
+ is kept, otherwise it is filtered out.
41
+ """
42
+
43
+ FilterTree = FilterSpec | PyTree[FilterSpec]
@@ -1 +0,0 @@
1
- __version__ = "1.4.dev322"
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