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.
Files changed (107) hide show
  1. {haliax-1.4.dev348 → haliax-1.4.dev352}/PKG-INFO +1 -1
  2. haliax-1.4.dev352/src/haliax/__about__.py +1 -0
  3. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/state_dict.py +2 -0
  4. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/core.py +20 -2
  5. haliax-1.4.dev352/tests/test_scatter_gather.py +165 -0
  6. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_state_dict.py +24 -0
  7. haliax-1.4.dev348/src/haliax/__about__.py +0 -1
  8. {haliax-1.4.dev348 → haliax-1.4.dev352}/.coveragerc +0 -0
  9. {haliax-1.4.dev348 → haliax-1.4.dev352}/.flake8 +0 -0
  10. {haliax-1.4.dev348 → haliax-1.4.dev352}/.github/workflows/publish_dev.yaml +0 -0
  11. {haliax-1.4.dev348 → haliax-1.4.dev352}/.github/workflows/run_pre_commit.yaml +0 -0
  12. {haliax-1.4.dev348 → haliax-1.4.dev352}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
  13. {haliax-1.4.dev348 → haliax-1.4.dev352}/.github/workflows/run_tests.yaml +0 -0
  14. {haliax-1.4.dev348 → haliax-1.4.dev352}/.gitignore +0 -0
  15. {haliax-1.4.dev348 → haliax-1.4.dev352}/.pre-commit-config.yaml +0 -0
  16. {haliax-1.4.dev348 → haliax-1.4.dev352}/.readthedocs.yaml +0 -0
  17. {haliax-1.4.dev348 → haliax-1.4.dev352}/CONTRIBUTING.md +0 -0
  18. {haliax-1.4.dev348 → haliax-1.4.dev352}/LICENSE +0 -0
  19. {haliax-1.4.dev348 → haliax-1.4.dev352}/README.md +0 -0
  20. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/api.md +0 -0
  21. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/broadcasting.md +0 -0
  22. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/cheatsheet.md +0 -0
  23. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/css/material.css +0 -0
  24. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/css/mkdocstrings.css +0 -0
  25. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/faq.md +0 -0
  26. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/data_parallel_mesh.png +0 -0
  27. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/data_parallel_mesh_replicated.png +0 -0
  28. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_1d.png +0 -0
  29. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_1d_zero.png +0 -0
  30. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d.png +0 -0
  31. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
  32. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
  33. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
  34. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
  35. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/figures/device_mesh_2d_zero.png +0 -0
  36. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/fp8.md +0 -0
  37. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/index.md +0 -0
  38. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/indexing.md +0 -0
  39. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/matmul.md +0 -0
  40. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/nn.md +0 -0
  41. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/partitioning.md +0 -0
  42. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/rearrange.ipynb +0 -0
  43. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/rearrange.md +0 -0
  44. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/requirements.txt +0 -0
  45. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/scan.md +0 -0
  46. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/state-dict.md +0 -0
  47. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/tutorial.md +0 -0
  48. {haliax-1.4.dev348 → haliax-1.4.dev352}/docs/vmap.md +0 -0
  49. {haliax-1.4.dev348 → haliax-1.4.dev352}/mkdocs.yml +0 -0
  50. {haliax-1.4.dev348 → haliax-1.4.dev352}/pyproject.toml +0 -0
  51. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/__init__.py +0 -0
  52. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/__init__.py +0 -0
  53. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/compile_utils.py +0 -0
  54. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/dot.py +0 -0
  55. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/einsum.py +0 -0
  56. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/fp8.py +0 -0
  57. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/parsing.py +0 -0
  58. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/rearrange.py +0 -0
  59. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/scan.py +0 -0
  60. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/_src/util.py +0 -0
  61. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/axis.py +0 -0
  62. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/debug.py +0 -0
  63. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/hof.py +0 -0
  64. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/jax_utils.py +0 -0
  65. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/__init__.py +0 -0
  66. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/activations.py +0 -0
  67. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/attention.py +0 -0
  68. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/conv.py +0 -0
  69. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/dropout.py +0 -0
  70. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/embedding.py +0 -0
  71. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/linear.py +0 -0
  72. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/loss.py +0 -0
  73. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/mlp.py +0 -0
  74. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/normalization.py +0 -0
  75. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/pool.py +0 -0
  76. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/nn/scan.py +0 -0
  77. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/ops.py +0 -0
  78. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/partitioning.py +0 -0
  79. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/quantization.py +0 -0
  80. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/random.py +0 -0
  81. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/specialized_fns.py +0 -0
  82. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/state_dict.py +0 -0
  83. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/tree_util.py +0 -0
  84. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/types.py +0 -0
  85. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/util.py +0 -0
  86. {haliax-1.4.dev348 → haliax-1.4.dev352}/src/haliax/wrap.py +0 -0
  87. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/core_test.py +0 -0
  88. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_attention.py +0 -0
  89. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_axis.py +0 -0
  90. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_conv.py +0 -0
  91. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_debug.py +0 -0
  92. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_dot.py +0 -0
  93. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_einsum.py +0 -0
  94. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_fp8.py +0 -0
  95. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_hof.py +0 -0
  96. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_int8.py +0 -0
  97. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_nn.py +0 -0
  98. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_ops.py +0 -0
  99. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_parsing.py +0 -0
  100. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_partitioning.py +0 -0
  101. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_pool.py +0 -0
  102. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_random.py +0 -0
  103. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_rearrange.py +0 -0
  104. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_scan.py +0 -0
  105. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_specialized_fns.py +0 -0
  106. {haliax-1.4.dev348 → haliax-1.4.dev352}/tests/test_tree_util.py +0 -0
  107. {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.dev348
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
- # we allow this if it's a 1-d array, in which case we treat it as sugar for NamedArray(slice_, sliced-axis)
959
- ordered_slices[axis_index] = haliax.named(slice_, axis_name(axis))
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