haliax 1.4.dev321__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.dev321 → haliax-1.4.dev324}/PKG-INFO +3 -2
  2. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/indexing.md +23 -2
  3. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/matmul.md +1 -1
  4. haliax-1.4.dev324/docs/state-dict.md +160 -0
  5. {haliax-1.4.dev321 → haliax-1.4.dev324}/mkdocs.yml +1 -0
  6. {haliax-1.4.dev321 → haliax-1.4.dev324}/pyproject.toml +2 -0
  7. haliax-1.4.dev324/src/haliax/__about__.py +1 -0
  8. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/__init__.py +2 -0
  9. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/einsum.py +3 -2
  10. haliax-1.4.dev324/src/haliax/_src/state_dict.py +449 -0
  11. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/core.py +6 -2
  12. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/jax_utils.py +1 -1
  13. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/linear.py +7 -9
  14. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/pool.py +9 -9
  15. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/scan.py +109 -4
  16. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/partitioning.py +4 -2
  17. haliax-1.4.dev324/src/haliax/state_dict.py +60 -0
  18. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/types.py +12 -1
  19. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_scan.py +31 -0
  20. haliax-1.4.dev324/tests/test_state_dict.py +129 -0
  21. haliax-1.4.dev321/src/haliax/__about__.py +0 -1
  22. {haliax-1.4.dev321 → haliax-1.4.dev324}/.coveragerc +0 -0
  23. {haliax-1.4.dev321 → haliax-1.4.dev324}/.flake8 +0 -0
  24. {haliax-1.4.dev321 → haliax-1.4.dev324}/.github/workflows/publish_dev.yaml +0 -0
  25. {haliax-1.4.dev321 → haliax-1.4.dev324}/.github/workflows/run_pre_commit.yaml +0 -0
  26. {haliax-1.4.dev321 → haliax-1.4.dev324}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
  27. {haliax-1.4.dev321 → haliax-1.4.dev324}/.github/workflows/run_tests.yaml +0 -0
  28. {haliax-1.4.dev321 → haliax-1.4.dev324}/.gitignore +0 -0
  29. {haliax-1.4.dev321 → haliax-1.4.dev324}/.pre-commit-config.yaml +0 -0
  30. {haliax-1.4.dev321 → haliax-1.4.dev324}/.readthedocs.yaml +0 -0
  31. {haliax-1.4.dev321 → haliax-1.4.dev324}/CONTRIBUTING.md +0 -0
  32. {haliax-1.4.dev321 → haliax-1.4.dev324}/LICENSE +0 -0
  33. {haliax-1.4.dev321 → haliax-1.4.dev324}/README.md +0 -0
  34. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/api.md +0 -0
  35. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/broadcasting.md +0 -0
  36. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/cheatsheet.md +0 -0
  37. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/css/material.css +0 -0
  38. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/css/mkdocstrings.css +0 -0
  39. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/faq.md +0 -0
  40. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/data_parallel_mesh.png +0 -0
  41. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/data_parallel_mesh_replicated.png +0 -0
  42. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_1d.png +0 -0
  43. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_1d_zero.png +0 -0
  44. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d.png +0 -0
  45. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
  46. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
  47. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
  48. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
  49. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_zero.png +0 -0
  50. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/fp8.md +0 -0
  51. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/hof.md +0 -0
  52. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/index.md +0 -0
  53. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/nn.md +0 -0
  54. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/partitioning.md +0 -0
  55. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/rearrange.ipynb +0 -0
  56. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/rearrange.md +0 -0
  57. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/requirements.txt +0 -0
  58. {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/tutorial.md +0 -0
  59. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/__init__.py +0 -0
  60. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/compile_utils.py +0 -0
  61. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/dot.py +0 -0
  62. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/fp8.py +0 -0
  63. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/parsing.py +0 -0
  64. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/rearrange.py +0 -0
  65. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/util.py +0 -0
  66. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/axis.py +0 -0
  67. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/debug.py +0 -0
  68. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/hof.py +0 -0
  69. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/__init__.py +0 -0
  70. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/activations.py +0 -0
  71. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/attention.py +0 -0
  72. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/conv.py +0 -0
  73. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/dropout.py +0 -0
  74. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/embedding.py +0 -0
  75. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/loss.py +0 -0
  76. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/mlp.py +0 -0
  77. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/normalization.py +0 -0
  78. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/ops.py +0 -0
  79. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/quantization.py +0 -0
  80. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/random.py +0 -0
  81. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/specialized_fns.py +0 -0
  82. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/tree_util.py +0 -0
  83. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/util.py +0 -0
  84. {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/wrap.py +0 -0
  85. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/core_test.py +0 -0
  86. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_attention.py +0 -0
  87. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_axis.py +0 -0
  88. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_conv.py +0 -0
  89. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_debug.py +0 -0
  90. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_dot.py +0 -0
  91. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_einsum.py +0 -0
  92. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_fp8.py +0 -0
  93. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_hof.py +0 -0
  94. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_nn.py +0 -0
  95. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_ops.py +0 -0
  96. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_parsing.py +0 -0
  97. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_partitioning.py +0 -0
  98. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_pool.py +0 -0
  99. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_random.py +0 -0
  100. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_rearrange.py +0 -0
  101. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_specialized_fns.py +0 -0
  102. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_tree_util.py +0 -0
  103. {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_utils.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: haliax
3
- Version: 1.4.dev321
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
+ Project-URL: Documentation, https://haliax.readthedocs.io/en/latest/
7
8
  Author-email: David Hall <dlwh@cs.stanford.edu>
8
- License-File: LICENSE
9
9
  Classifier: Development Status :: 4 - Beta
10
10
  Classifier: Intended Audience :: Science/Research
11
11
  Classifier: License :: OSI Approved :: Apache Software License
@@ -16,6 +16,7 @@ Requires-Python: >=3.10
16
16
  Requires-Dist: equinox>=0.10.6
17
17
  Requires-Dist: jaxtyping>=0.2.20
18
18
  Requires-Dist: jmp>=0.0.4
19
+ Requires-Dist: safetensors>=0.4.3
19
20
  Provides-Extra: dev
20
21
  Requires-Dist: chex>=0.1.86; extra == 'dev'
21
22
  Requires-Dist: mkdocs-include-markdown-plugin; extra == 'dev'
@@ -72,7 +72,7 @@ can use [haliax.where][] for most of the same functionality, though.
72
72
 
73
73
  Before we continue, a note on shapes in JAX. Most JAX code will be used inside `jit`, which means that the sizes of all
74
74
  arrays must be determined at compile time (i.e. when JAX interprets your functions abstractly). This is a hard
75
- requirement in XLA. It might worked around one day, but it's the way things are for now.
75
+ requirement in XLA.
76
76
 
77
77
  A consequence of this restriction is that certain indexing patterns aren't allowed in `jit`-ed JAX code:
78
78
 
@@ -97,10 +97,31 @@ f(jnp.arange(10), 2)
97
97
  ```
98
98
 
99
99
  This is a not-uncommon pattern in situations where you want to process a large array in chunks. In Haliax, we provide
100
- two solutions: [haliax.slice][] as well as dynamic slices ([haliax.dslice][] a.k.a. [haliax.ds][]).
100
+ two solutions: [haliax.slice][] and dynamic slices ([haliax.dslice][] a.k.a. [haliax.ds][]).
101
101
 
102
102
  ## Dynamic Slices
103
103
 
104
+ [haliax.slice][] is a convenience function that wraps `jax.lax.dynamic_slice` and allows you to slice an array with a
105
+ dynamic start and size. This is useful for situations where you need to slice an array in a way that can't be determined
106
+ at compile time. For example, the above example can be written as follows:
107
+
108
+ ```python
109
+ import jax
110
+
111
+ import haliax as hax
112
+
113
+ N = hax.Axis("N", 10)
114
+ q = hax.arange(N)
115
+
116
+ @hax.named_jit
117
+ def f(x, slice_size: int):
118
+ num_blocks = N.size // slice_size
119
+ def body(i, m):
120
+ return i + hax.mean(hax.slice(x, {"N": i * slice_size}, {"N": slice_size}))
121
+ jax.lax.fori_loop(0, num_blocks, body, 0.0)
122
+ ```
123
+
124
+
104
125
  In light of the requirement that all array sizes be known at compile time, Haliax provides both a simple [haliax.slice][]
105
126
  function, as well as [haliax.dslice][], which can be used with `[]`. The simple slice function is just a wrapper
106
127
  around [jax.lax.dynamic_slice][]] and not worth discussing here.
@@ -62,7 +62,7 @@ y = hax.dot(x, w, c, axis=(), out_axes=(D, ..., H)) # shape is (D, W, C, H), eq
62
62
  [haliax.einsum][] is at its best when you want to express a more complex tensor contraction.
63
63
  It is similar to [numpy.einsum](https://numpy.org/doc/stable/reference/generated/numpy.einsum.html)
64
64
  or [einops.einsum](https://einops.rocks/api/einsum/) in terms of syntax and behavior,
65
- but extended to work with named axes, including added flexibility that named axes provide.
65
+ but extended to work with named axes, including the added flexibility that named axes provide.
66
66
  Our "flavor" of `einsum` is most similar to `einops.einsum`'s flavor, in that
67
67
  it supports long names for axes (like `"batch h w, h w channel -> batch channel"`)
68
68
  rather than the compact notation of `numpy.einsum` (like `"bhwc,hwc->bc"`).
@@ -0,0 +1,160 @@
1
+ # Serialization
2
+
3
+ Haliax supports serialization of modules (including any [equinox.Module][]) to and from PyTorch-compatible
4
+ state dicts using the [safetensors](https://github.com/huggingface/safetensors) library. For details on
5
+ how state dicts work in PyTorch, see the [PyTorch documentation](https://pytorch.org/docs/stable/notes/serialization.html#saving-and-loading-torch-nn-modules).
6
+
7
+ A state dict is a Python dictionary that maps string keys to tensors. It is used to store the parameters
8
+ of a model (though typically not the model's structure or hyperparameters). The keys are typically the names of the
9
+ model's parameters, arranged as `.`-separated paths. For example, a model with a `conv1` layer might have a
10
+ state dict with keys like `conv1.weight` and `conv1.bias`. Sequences of modules (e.g., for lists of layers) are
11
+ serialize with keys like `layer.0.weight`, `layer.1.weight`, etc.
12
+
13
+ Haliax uses the [safetensors](https://github.com/huggingface/safetensors) library to serialize state dicts. This
14
+ library is a safer, more portable format developed by Hugging Face. Serializing a native PyTorch state dict requires
15
+ PyTorch itself, and we want to avoid that dependency. Also, PyTorch uses pickles, which are in general not
16
+ safe to deserialize from untrusted sources.
17
+
18
+ This does mean that you can't directly load a Haliax state dict into PyTorch, but safetensors is lightweight and
19
+ easy to use. Hugging Face natively supports it in their libraries.
20
+
21
+ ## Saving a State Dict
22
+
23
+ To serialize a module to a Pytorch-compatible state dict, use the [haliax.state_dict.to_torch_compatible_state_dict][]
24
+ function. This function takes a module and returns a state dict. To save the state dict to a file, use the
25
+ [haliax.state_dict.save_state_dict][] function, which writes the state dict to a file in safetensor format.
26
+ `to_torch_compatible_state_dict` flattens [haliax.nn.Linear] module input and output axis specs to a format that
27
+ is compatible with PyTorch Linear modules (though `out_first=True` is necessary to match PyTorch's Linear module).
28
+
29
+ ```python
30
+ import haliax
31
+ import jax.random as jrandom
32
+
33
+ # Create a module
34
+ Heads = haliax.Axis("Heads", 8)
35
+ Dim = haliax.Axis("Dim", 16)
36
+ Out = haliax.Axis("Out", 5)
37
+ module = haliax.nn.Linear.init(In=(Heads, Dim), Out=Out, key=jrandom.PRNGKey(0))
38
+
39
+ # Serialize the module to a state dict
40
+ state_dict = haliax.state_dict.to_torch_compatible_state_dict(module)
41
+
42
+ # Save the state dict to a file
43
+ haliax.state_dict.save_state_dict(state_dict, 'state_dict.safetensors')
44
+ ```
45
+
46
+ Note that the state dict is saved in the [safetensors](https://github.com/huggingface/safetensors) format, which
47
+ is a safer, more portable format developed by Hugging Face. To load a model from a state dict in PyTorch, you
48
+ can use safetensors directly.
49
+
50
+ ```python
51
+ import torch
52
+ from safetensors.torch import load_model
53
+
54
+ model = torch.nn.Linear(10, 5)
55
+
56
+ # Load the state dict from a file
57
+ state_dict = load_model(model, 'state_dict.safetensors')
58
+ ```
59
+
60
+ ## Loading a State Dict
61
+
62
+ Similarly, you can load a state dict from a file using the [haliax.state_dict.load_state_dict][] function. This
63
+ function reads a state dict from a file in safetensors format and returns a dictionary. To load the state dict
64
+ into a module, use the [haliax.state_dict.from_torch_compatible_state_dict][] function.
65
+
66
+ ```python
67
+ import haliax as hax
68
+ import jax.random as jrandom
69
+
70
+ # Create a module
71
+ Heads = hax.Axis("Heads", 8)
72
+ Dim = hax.Axis("Dim", 16)
73
+ Out = hax.Axis("Out", 5)
74
+ module = hax.nn.Linear.init(In=(Heads, Dim), Out=Out, key=jrandom.PRNGKey(0))
75
+
76
+ # Load the state dict from a file
77
+ state_dict = hax.state_dict.load_state_dict('state_dict.safetensors')
78
+
79
+ # this will unflatten the state dict and load it into the module
80
+ module = hax.state_dict.from_torch_compatible_state_dict(module, state_dict)
81
+ ```
82
+
83
+ The `from_torch_compatible_state_dict` function will unflatten the state dict and load it into the module. Note
84
+ that the module must have the same structure as the module that was serialized to the state dict. If the module
85
+ structure has changed, you may need to manually update the state dict keys to match the new structure.
86
+
87
+
88
+ ## Customizing Serialization
89
+
90
+ ### Changing the State Dict Key Names
91
+
92
+ If for some reason you want to use different names in the serialized state dict (e.g. because you
93
+ chose to use different names from a Hugging Face implementation), you can extend your class from [haliax.state_dict.ModuleWithStateDictSerialization][]
94
+ and use `_state_dict_key_map` to rename keys. For instance, the `Gpt2Transformer` class in Levanter has this method:
95
+
96
+ ```python
97
+ from typing import Optional
98
+ from haliax.state_dict import ModuleWithStateDictSerialization
99
+
100
+ class Gpt2Transformer(ModuleWithStateDictSerialization):
101
+ ...
102
+
103
+ def _state_dict_key_map(self) -> dict[str, Optional[str]]:
104
+ return {"blocks": "h"}
105
+ ```
106
+
107
+ This says that the field called `blocks` in this class should be (de)serialized as `h`,
108
+ because the Hugging Face GPT-2 implementation uses `h`, which is not very clear.
109
+ You can also "flatten" the submodules of a field by using `None`.
110
+
111
+ ### Custom Serialization Logic
112
+
113
+ If your modules need fancier special logic, you'll need to extend your class from `ModuleWithStateDictSerialization` and
114
+ override the default functions `to_state_dict()` and `from_state_dict()`. It takes in and returns a modified
115
+ [haliax.state_dict.StateDict][]. As of June 2024, we almost never this in Levanter.
116
+
117
+ For implementation, there are a few helper methods from `haliax.state_dict` that you can use:
118
+ - To join specific prefix to the keys of Hugging Face state_dict, you can use the helper function `with_prefix()`.
119
+ The prefix comes from the name of attributes defined at the beginning of your model class.
120
+
121
+ For example, below is the implementation of `to_state_dict()` in [levanter.models.backpack.BackpackLMHeadModel][].
122
+ In this class, we want to preserve HF compatibility by saving untied output embeddings. (We chose not to implement
123
+ non-weight-tied embeddings.)
124
+
125
+ ```python
126
+ from typing import Optional
127
+
128
+ from haliax.state_dict import with_prefix, StateDict
129
+
130
+
131
+ class BackpackLMHeadModel(ModuleWithStateDictSerialization):
132
+ ...
133
+
134
+ def to_state_dict(self, prefix: Optional[str] = None) -> StateDict:
135
+ state_dict = super().to_state_dict(prefix=prefix)
136
+ # In levanter's implementation, we have a shared embedding matrix for both the word
137
+ # embeddings and the sense embeddings
138
+ state_dict[with_prefix(prefix, "backpack.word_embeddings.weight")] = state_dict[
139
+ with_prefix(prefix, "backpack.gpt2_model.wte.weight")
140
+ ]
141
+ state_dict[with_prefix(prefix, "backpack.position_embeddings.weight")] = state_dict[
142
+ with_prefix(prefix, "backpack.gpt2_model.wpe.weight")
143
+ ]
144
+ return state_dict
145
+ ```
146
+
147
+ Similarly, to load weights from the state dict, you might need to implement `from_state_dict`. This function
148
+ takes in a state dict and the module with the updated weights. You can use the `with_prefix()` helper function
149
+ to join the prefix to the keys of the state dict.
150
+
151
+ ```python
152
+ def from_state_dict(self, state_dict: StateDict, prefix: Optional[str] = None) -> T:
153
+ ...
154
+
155
+
156
+ ```
157
+
158
+ ## API Reference
159
+
160
+ ::: haliax.state_dict
@@ -88,5 +88,6 @@ nav:
88
88
  - Partitioning: 'partitioning.md'
89
89
  - Higher Order Functions: 'hof.md'
90
90
  - FP8: 'fp8.md'
91
+ - Serialization: 'state-dict.md'
91
92
  - API Reference: 'api.md'
92
93
  - FAQ: 'faq.md'
@@ -26,6 +26,7 @@ dependencies = [
26
26
  "equinox>=0.10.6",
27
27
  "jaxtyping>=0.2.20",
28
28
  "jmp>=0.0.4",
29
+ "safetensors>=0.4.3"
29
30
  ]
30
31
  dynamic =[ "version" ]
31
32
 
@@ -68,3 +69,4 @@ src_paths = ["src", "tests"]
68
69
  [project.urls]
69
70
  "Homepage" = "https://github.com/stanford-crfm/haliax"
70
71
  "Bug Tracker" = "https://github.com/stanford-crfm/haliax/issues/"
72
+ "Documentation" = "https://haliax.readthedocs.io/en/latest/"
@@ -0,0 +1 @@
1
+ __version__ = "1.4.dev324"
@@ -14,6 +14,7 @@ import haliax.debug as debug
14
14
  import haliax.nn as nn
15
15
  import haliax.quantization as quantization
16
16
  import haliax.random as random
17
+ import haliax.state_dict as state_dict
17
18
  import haliax.tree_util as tree_util
18
19
  import haliax.util as util
19
20
 
@@ -890,6 +891,7 @@ __all__ = [
890
891
  "random",
891
892
  "tree_util",
892
893
  "nn",
894
+ "state_dict",
893
895
  "Axis",
894
896
  "AxisSpec",
895
897
  "AxisSelection",
@@ -9,6 +9,7 @@ import haliax
9
9
  from ..axis import Axis, AxisSelector, axis_name, eliminate_axes, rearrange_for_partial_order, union_axes
10
10
  from ..core import NamedArray
11
11
  from ..jax_utils import _jittable_dg_einsum
12
+ from ..quantization import DotGeneralOp
12
13
  from ..types import DTypeLike, PrecisionLike
13
14
  from ..util import ensure_tuple
14
15
  from .parsing import AliasTable, parse_einsum, raise_parse_error
@@ -19,8 +20,8 @@ def einsum(
19
20
  *arrays: NamedArray,
20
21
  precision: PrecisionLike = None,
21
22
  preferred_element_type: Optional[DTypeLike] = None,
22
- _dot_general=jax.lax.dot_general,
23
- **axis_aliases,
23
+ _dot_general: DotGeneralOp = jax.lax.dot_general,
24
+ **axis_aliases: AxisSelector,
24
25
  ) -> NamedArray:
25
26
  """Compute the tensor contraction of the input arrays according to Haliax's named variant of the Einstein summation
26
27
  convention.