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.
- {haliax-1.4.dev321 → haliax-1.4.dev324}/PKG-INFO +3 -2
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/indexing.md +23 -2
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/matmul.md +1 -1
- haliax-1.4.dev324/docs/state-dict.md +160 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/mkdocs.yml +1 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/pyproject.toml +2 -0
- haliax-1.4.dev324/src/haliax/__about__.py +1 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/__init__.py +2 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/einsum.py +3 -2
- haliax-1.4.dev324/src/haliax/_src/state_dict.py +449 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/core.py +6 -2
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/jax_utils.py +1 -1
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/linear.py +7 -9
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/pool.py +9 -9
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/scan.py +109 -4
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/partitioning.py +4 -2
- haliax-1.4.dev324/src/haliax/state_dict.py +60 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/types.py +12 -1
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_scan.py +31 -0
- haliax-1.4.dev324/tests/test_state_dict.py +129 -0
- haliax-1.4.dev321/src/haliax/__about__.py +0 -1
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.coveragerc +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.flake8 +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.github/workflows/run_tests.yaml +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.gitignore +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/LICENSE +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/README.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/api.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/css/material.css +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/faq.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/fp8.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/hof.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/index.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/nn.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/partitioning.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/rearrange.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/requirements.txt +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/docs/tutorial.md +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/__init__.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/ops.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/random.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/util.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/core_test.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_attention.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_axis.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_conv.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_debug.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_dot.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_hof.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_nn.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_ops.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_partitioning.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_pool.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_random.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev321 → haliax-1.4.dev324}/tests/test_tree_util.py +0 -0
- {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.
|
|
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.
|
|
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][]
|
|
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
|
|
@@ -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.
|