haliax 1.4.dev348__tar.gz → 1.4.dev352__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.dev348 → haliax-1.4.dev352}/PKG-INFO +1 -1
- haliax-1.4.dev352/src/haliax/__about__.py +1 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/state_dict.py +2 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/core.py +20 -2
- haliax-1.4.dev352/tests/test_scatter_gather.py +165 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_state_dict.py +24 -0
- haliax-1.4.dev348/src/haliax/__about__.py +0 -1
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.coveragerc +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.flake8 +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.github/workflows/run_tests.yaml +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.gitignore +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/LICENSE +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/README.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/api.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/css/material.css +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/faq.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/fp8.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/index.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/indexing.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/matmul.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/nn.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/partitioning.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/rearrange.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/requirements.txt +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/scan.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/state-dict.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/tutorial.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/vmap.md +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/mkdocs.yml +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/pyproject.toml +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/__init__.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/einsum.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/scan.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/jax_utils.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/__init__.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/linear.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/pool.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/scan.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/ops.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/partitioning.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/random.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/state_dict.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/types.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/util.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/core_test.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_attention.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_axis.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_conv.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_debug.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_dot.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_hof.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_int8.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_nn.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_ops.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_partitioning.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_pool.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_random.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_scan.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_tree_util.py +0 -0
- {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haliax
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.dev352
|
|
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.dev352"
|
|
@@ -215,6 +215,8 @@ def from_state_dict(tree: T, state_dict: StateDict, prefix: Optional[str] = None
|
|
|
215
215
|
raise ValueError("Cannot extract a leaf value from a state dict without a prefix")
|
|
216
216
|
# TODO: add "strict" flag so we can return None in cases where it's just missing
|
|
217
217
|
return jnp.array(state_dict[prefix])
|
|
218
|
+
elif tree is None:
|
|
219
|
+
return None
|
|
218
220
|
else:
|
|
219
221
|
if prefix is None:
|
|
220
222
|
return tree
|
|
@@ -931,6 +931,7 @@ def _compute_new_axes_and_slices_for_index(
|
|
|
931
931
|
ordered_slices: list = [py_slice(None, None, None)] * len(array.axes) # type: ignore
|
|
932
932
|
kept_axes = [True] * len(array.axes)
|
|
933
933
|
array_slice_indices = []
|
|
934
|
+
index_axis_names = set()
|
|
934
935
|
|
|
935
936
|
for axis, slice_ in slices.items():
|
|
936
937
|
axis_index = array._lookup_indices(axis)
|
|
@@ -946,6 +947,8 @@ def _compute_new_axes_and_slices_for_index(
|
|
|
946
947
|
ordered_slices[axis_index] = slice_
|
|
947
948
|
array_slice_indices.append(axis_index)
|
|
948
949
|
kept_axes[axis_index] = False
|
|
950
|
+
for ax in slice_.axes:
|
|
951
|
+
index_axis_names.add(ax.name)
|
|
949
952
|
elif isinstance(slice_, list):
|
|
950
953
|
# we'll let JAX complain if this is wrong
|
|
951
954
|
ordered_slices[axis_index] = slice_
|
|
@@ -955,10 +958,17 @@ def _compute_new_axes_and_slices_for_index(
|
|
|
955
958
|
ordered_slices[axis_index] = slice_
|
|
956
959
|
kept_axes[axis_index] = False
|
|
957
960
|
elif slice_.ndim == 1:
|
|
958
|
-
|
|
959
|
-
|
|
961
|
+
target_axis = None
|
|
962
|
+
for i2, ax2 in enumerate(array.axes):
|
|
963
|
+
if i2 != axis_index and kept_axes[i2] and ax2.size == slice_.shape[0]:
|
|
964
|
+
target_axis = ax2
|
|
965
|
+
break
|
|
966
|
+
if target_axis is None:
|
|
967
|
+
target_axis = axis
|
|
968
|
+
ordered_slices[axis_index] = haliax.named(slice_, axis_name(target_axis))
|
|
960
969
|
kept_axes[axis_index] = False
|
|
961
970
|
array_slice_indices.append(axis_index)
|
|
971
|
+
index_axis_names.add(axis_name(target_axis))
|
|
962
972
|
else:
|
|
963
973
|
raise ValueError(
|
|
964
974
|
f"Only 0-d or 1-d unnamed arrays can be used for indexing. Got {slice_} for axis {axis}"
|
|
@@ -966,6 +976,14 @@ def _compute_new_axes_and_slices_for_index(
|
|
|
966
976
|
else:
|
|
967
977
|
raise ValueError(f"Only NamedArrays can be used for advanced indexing. Got {slice_} for axis {axis}")
|
|
968
978
|
|
|
979
|
+
# If any index array uses axes that are already present in the array and not removed,
|
|
980
|
+
# we need to explicitly advance-index those axes so numpy broadcasting works.
|
|
981
|
+
for i, ax in enumerate(array.axes):
|
|
982
|
+
if kept_axes[i] and ax.name in index_axis_names:
|
|
983
|
+
ordered_slices[i] = haliax.arange(ax)
|
|
984
|
+
array_slice_indices.append(i)
|
|
985
|
+
kept_axes[i] = False
|
|
986
|
+
|
|
969
987
|
# advanced indexing
|
|
970
988
|
if len(array_slice_indices) > 0:
|
|
971
989
|
# this requires broadcasting
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import jax
|
|
2
|
+
import jax.numpy as jnp
|
|
3
|
+
|
|
4
|
+
import haliax as hax
|
|
5
|
+
from haliax import Axis, dslice
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# -----------------------------------------------------------------------------
|
|
9
|
+
# Helper for reference via take_along_axis
|
|
10
|
+
# -----------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _ref_gather(src, axis, idx):
|
|
14
|
+
ax_num = src.axes.index(axis)
|
|
15
|
+
# broadcast idx to match src without the gathered axis
|
|
16
|
+
other_axes = tuple(ax for ax in src.axes if ax != axis)
|
|
17
|
+
broadcast_axes = other_axes
|
|
18
|
+
for ax in idx.axes:
|
|
19
|
+
if ax not in broadcast_axes:
|
|
20
|
+
broadcast_axes += (ax,)
|
|
21
|
+
idx_b = hax.broadcast_to(idx, broadcast_axes, enforce_no_extra_axes=False)
|
|
22
|
+
if idx_b.array.ndim == src.array.ndim - 1:
|
|
23
|
+
idx_arr = idx_b.array[..., None]
|
|
24
|
+
else:
|
|
25
|
+
idx_arr = idx_b.array
|
|
26
|
+
out = jnp.take_along_axis(src.array, idx_arr, axis=ax_num)
|
|
27
|
+
if idx_b.array.ndim == src.array.ndim - 1:
|
|
28
|
+
out = out.squeeze(ax_num)
|
|
29
|
+
return out
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ---------------------------- 1. single batched selector ----------------------
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_single_batched_selector():
|
|
36
|
+
B, S, V = Axis("batch", 4), Axis("seq", 3), Axis("vocab", 7)
|
|
37
|
+
x = hax.arange((B, S, V))
|
|
38
|
+
idx = hax.arange((B, S), dtype=jnp.int32) % V.size
|
|
39
|
+
out = x["vocab", idx]
|
|
40
|
+
assert out.axes == (B, S)
|
|
41
|
+
assert jnp.array_equal(out.array, _ref_gather(x, V, idx))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ---------------------------- 2. selector adds new axis -----------------------
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_selector_adds_new_axis():
|
|
48
|
+
B, S, V, T = Axis("batch", 2), Axis("seq", 3), Axis("vocab", 5), Axis("step", 4)
|
|
49
|
+
logits = hax.arange((B, S, V))
|
|
50
|
+
idx = hax.arange((B, T), dtype=jnp.int32) % V.size
|
|
51
|
+
out = logits["vocab", idx]
|
|
52
|
+
assert set(out.axes) == {B, S, T}
|
|
53
|
+
ref = jnp.transpose(_ref_gather(logits, V, idx), (0, 2, 1))
|
|
54
|
+
assert jnp.array_equal(out.array, ref)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ------------------------ 3. two contiguous selector arrays -------------------
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_two_contiguous_selectors():
|
|
61
|
+
B, X, Y = Axis("batch", 3), Axis("x", 5), Axis("y", 7)
|
|
62
|
+
a = hax.arange((B, X, Y))
|
|
63
|
+
ix = hax.arange((B,), dtype=jnp.int32) % X.size
|
|
64
|
+
iy = hax.arange((B,), dtype=jnp.int32) % Y.size
|
|
65
|
+
out = a["x", ix, "y", iy]
|
|
66
|
+
assert out.axes == (B,)
|
|
67
|
+
ref = a.array[jnp.arange(3), ix.array, iy.array]
|
|
68
|
+
assert jnp.array_equal(out.array, ref)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ------------------ 4. non-contiguous selectors → axes to front --------------
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_noncontig_selectors():
|
|
75
|
+
B, X, Z, Y = Axis("batch", 2), Axis("x", 4), Axis("z", 6), Axis("y", 5)
|
|
76
|
+
a = hax.arange((B, X, Z, Y))
|
|
77
|
+
ix = hax.arange((B,), dtype=jnp.int32) % X.size
|
|
78
|
+
iy = hax.arange((B,), dtype=jnp.int32) % Y.size
|
|
79
|
+
out = a["x", ix, "y", iy]
|
|
80
|
+
assert out.axes == (B, Z)
|
|
81
|
+
ref = a.array[jnp.arange(2), ix.array, :, iy.array]
|
|
82
|
+
assert jnp.array_equal(out.array, ref)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ----------------- 5. integer elimination + selector --------------------------
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_mixed_int_and_selector():
|
|
89
|
+
B, C, V = Axis("batch", 3), Axis("channel", 2), Axis("vocab", 6)
|
|
90
|
+
x = hax.arange((B, C, V))
|
|
91
|
+
idx = hax.arange((B,), dtype=jnp.int32) % V.size
|
|
92
|
+
out = x["channel", 1, "vocab", idx]
|
|
93
|
+
assert out.axes == (B,)
|
|
94
|
+
ref = x.array[:, 1, :][jnp.arange(3), idx.array]
|
|
95
|
+
assert jnp.array_equal(out.array, ref)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_dslice_with_selector():
|
|
99
|
+
B, S, V = Axis("batch", 2), Axis("seq", 5), Axis("vocab", 10)
|
|
100
|
+
x = hax.arange((B, S, V))
|
|
101
|
+
idx = (hax.arange((B, S), dtype=jnp.int32) + 2) % 4
|
|
102
|
+
shard = V.resize(4)
|
|
103
|
+
x_shard = x["vocab", dslice(0, shard)]
|
|
104
|
+
out = x_shard["vocab", idx]
|
|
105
|
+
assert out.axes == (B, S)
|
|
106
|
+
ref = x.array[:, :, :4][jnp.arange(B.size)[:, None], jnp.arange(S.size)[None, :], idx.array]
|
|
107
|
+
assert jnp.array_equal(out.array, ref)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_scalar_eliminates_axis():
|
|
111
|
+
B, S, V = Axis("batch", 2), Axis("seq", 3), Axis("vocab", 4)
|
|
112
|
+
x = hax.arange((B, S, V))
|
|
113
|
+
out = x["seq", 1]
|
|
114
|
+
assert out.axes == (B, V)
|
|
115
|
+
assert jnp.array_equal(out.array, x.array[:, 1, :])
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# ----------------- 9. plain ndarray selector sugar ----------------------------
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_plain_ndarray_selector():
|
|
122
|
+
B, V = Axis("batch", 3), Axis("vocab", 5)
|
|
123
|
+
x = hax.arange((B, V))
|
|
124
|
+
idx = jnp.array([0, 2, 4], dtype=jnp.int32)
|
|
125
|
+
out = x["vocab", idx]
|
|
126
|
+
assert out.axes == (B,)
|
|
127
|
+
assert jnp.array_equal(out.array, x.array[jnp.arange(3), idx])
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# ----------------- 10. two selectors needing broadcast ------------------------
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_multiselector_broadcast():
|
|
134
|
+
B, S, V = Axis("batch", 2), Axis("seq", 3), Axis("vocab", 6)
|
|
135
|
+
a = hax.arange((B, S, V))
|
|
136
|
+
idx1 = hax.arange((B, S), dtype=jnp.int32) % V.size
|
|
137
|
+
out = a["vocab", idx1]
|
|
138
|
+
assert out.axes == (B, S)
|
|
139
|
+
assert jnp.array_equal(out.array, _ref_gather(a, V, idx1))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
# ----------------- 11. scatter-ADD via .at[…].add -----------------------------
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_scatter_add():
|
|
146
|
+
B, S, V = Axis("batch", 2), Axis("seq", 3), Axis("vocab", 5)
|
|
147
|
+
x = hax.zeros((B, S, V))
|
|
148
|
+
idx = hax.arange((B, S), dtype=jnp.int32) % V.size
|
|
149
|
+
ones = hax.ones((B, S))
|
|
150
|
+
y = x.at[{V: idx}].add(ones)
|
|
151
|
+
ref = jnp.zeros((2, 3, 5)).at[jnp.arange(2)[:, None], jnp.arange(3)[None, :], idx.array].add(1.0)
|
|
152
|
+
assert jnp.array_equal(y.array, ref)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# ----------------- 12. scatter-SET via .at[…].set -----------------------------
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_scatter_set():
|
|
159
|
+
B, V = Axis("batch", 2), Axis("vocab", 6)
|
|
160
|
+
x = hax.zeros((B, V))
|
|
161
|
+
idx = hax.named(jnp.array([1, 4]), B)
|
|
162
|
+
val = hax.ones(B) * 9
|
|
163
|
+
y = x.at[{V: idx}].set(val)
|
|
164
|
+
ref = jnp.zeros((2, 6)).at[jnp.arange(2), idx.array].set(9)
|
|
165
|
+
assert jnp.array_equal(y.array, ref)
|
|
@@ -175,3 +175,27 @@ def test_stacked_layer_norm():
|
|
|
175
175
|
new_norms = unflatten_modules_from_export(norms_flat, norms2)
|
|
176
176
|
|
|
177
177
|
assert norms == new_norms
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_linear_doesnt_read_bias_if_it_didnt_have_bias():
|
|
181
|
+
H = hax.Axis("H", 10)
|
|
182
|
+
W = hax.Axis("W", 20)
|
|
183
|
+
D = hax.Axis("D", 30)
|
|
184
|
+
B = hax.Axis("B", 40)
|
|
185
|
+
|
|
186
|
+
linear = hax.nn.Linear.init((H, W), (D, B), key=jax.random.PRNGKey(0), use_bias=False, out_first=True)
|
|
187
|
+
|
|
188
|
+
flat_linear = linear.flatten_for_export()
|
|
189
|
+
|
|
190
|
+
flat_state_dict = to_state_dict(flat_linear)
|
|
191
|
+
|
|
192
|
+
assert "bias" not in flat_state_dict
|
|
193
|
+
flat_state_dict["bias"] = jnp.zeros((D.size * B.size,)) # add a dummy bias
|
|
194
|
+
|
|
195
|
+
# now unflatten it
|
|
196
|
+
linear2 = Linear.init((H, W), (D, B), key=jax.random.PRNGKey(1), use_bias=False, out_first=True)
|
|
197
|
+
flinear2 = linear2.flatten_for_export()
|
|
198
|
+
flinear2 = from_state_dict(flinear2, flat_state_dict)
|
|
199
|
+
new_linear = flinear2.unflatten_from_export(linear2)
|
|
200
|
+
|
|
201
|
+
assert linear == new_linear
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.4.dev348"
|
|
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
|