haliax 1.4.dev412__tar.gz → 1.4.dev419__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.dev412 → haliax-1.4.dev419}/.agents/projects/api_parity.md +12 -12
- {haliax-1.4.dev412 → haliax-1.4.dev419}/AUTHORS.md +1 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/PKG-INFO +2 -1
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/api.md +96 -11
- haliax-1.4.dev419/docs/primer.md +183 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/pyproject.toml +1 -2
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/__about__.py +1 -1
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/__init__.py +51 -12
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/state_dict.py +1 -1
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/core.py +24 -4
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/fft.py +4 -1
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/__init__.py +18 -7
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/linear.py +1 -1
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/ops.py +2 -4
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/partitioning.py +101 -62
- haliax-1.4.dev419/src/haliax/poly.py +304 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/core_test.py +46 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_bitwise_ops.py +4 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_fft.py +5 -3
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_moe_linear.py +3 -2
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_nan_reductions.py +4 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_nn.py +18 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_partitioning.py +15 -27
- haliax-1.4.dev419/tests/test_poly_ops.py +134 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_utils.py +5 -2
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_visualize_sharding.py +5 -2
- haliax-1.4.dev419/uv.lock +1951 -0
- haliax-1.4.dev412/docs/primer.md +0 -114
- haliax-1.4.dev412/uv.lock +0 -1711
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.coveragerc +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.flake8 +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.github/workflows/run_tests.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.gitignore +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.playbooks/add-types.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.playbooks/wrap-non-named.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/AGENTS.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/CONTRIBUTORS.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/LICENSE +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/README.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/css/material.css +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/faq.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/fp8.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/index.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/indexing.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/matmul.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/nn.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/partitioning.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/rearrange.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/requirements.txt +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/scan.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/state-dict.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/tutorial.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/typing.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/docs/vmap.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/etc/license_header.txt +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/mkdocs.yml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/einsum.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/scan.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/field.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/haxtyping.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/jax_utils.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/pool.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/nn/scan.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/random.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/state_dict.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/types.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/util.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_attention.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_axis.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_conv.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_debug.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_dot.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_dtype_typing.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_field.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_hof.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_int8.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_namedarray_typing.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_ops.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_pool.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_random.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_scan.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_scatter_gather.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_state_dict.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev419}/tests/test_tree_util.py +0 -0
|
@@ -115,15 +115,15 @@ APIs that don't translate well to named tensors are intentionally omitted here.
|
|
|
115
115
|
- [ ] `permute_dims`
|
|
116
116
|
- [ ] `piecewise`
|
|
117
117
|
- [ ] `place`
|
|
118
|
-
- [
|
|
119
|
-
- [
|
|
120
|
-
- [
|
|
121
|
-
- [
|
|
122
|
-
- [
|
|
123
|
-
- [
|
|
124
|
-
- [
|
|
125
|
-
- [
|
|
126
|
-
- [
|
|
118
|
+
- [x] `poly`
|
|
119
|
+
- [x] `polyadd`
|
|
120
|
+
- [x] `polyder`
|
|
121
|
+
- [x] `polydiv`
|
|
122
|
+
- [x] `polyfit`
|
|
123
|
+
- [x] `polyint`
|
|
124
|
+
- [x] `polymul`
|
|
125
|
+
- [x] `polysub`
|
|
126
|
+
- [x] `polyval`
|
|
127
127
|
- [ ] `pow`
|
|
128
128
|
- [ ] `promote_types`
|
|
129
129
|
- [ ] `put`
|
|
@@ -134,7 +134,7 @@ APIs that don't translate well to named tensors are intentionally omitted here.
|
|
|
134
134
|
- [ ] `resize`
|
|
135
135
|
- [ ] `result_type`
|
|
136
136
|
- [ ] `rollaxis`
|
|
137
|
-
- [
|
|
137
|
+
- [x] `roots`
|
|
138
138
|
- [ ] `rot90`
|
|
139
139
|
- [ ] `select`
|
|
140
140
|
- [ ] `setdiff1d`
|
|
@@ -148,7 +148,7 @@ APIs that don't translate well to named tensors are intentionally omitted here.
|
|
|
148
148
|
- [ ] `tri`
|
|
149
149
|
- [ ] `tril_indices`
|
|
150
150
|
- [ ] `tril_indices_from`
|
|
151
|
-
- [
|
|
151
|
+
- [x] `trim_zeros`
|
|
152
152
|
- [ ] `triu_indices`
|
|
153
153
|
- [ ] `triu_indices_from`
|
|
154
154
|
- [ ] `union1d`
|
|
@@ -156,7 +156,7 @@ APIs that don't translate well to named tensors are intentionally omitted here.
|
|
|
156
156
|
- [ ] `unravel_index`
|
|
157
157
|
- [ ] `unstack`
|
|
158
158
|
- [ ] `unwrap`
|
|
159
|
-
- [
|
|
159
|
+
- [x] `vander`
|
|
160
160
|
- [ ] `vsplit`
|
|
161
161
|
- [ ] `vstack`
|
|
162
162
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haliax
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.dev419
|
|
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/
|
|
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
17
17
|
Requires-Python: >=3.10
|
|
18
18
|
Requires-Dist: aqtp>=0.8.2
|
|
19
19
|
Requires-Dist: equinox>=0.10.6
|
|
20
|
+
Requires-Dist: jax>=0.6.2
|
|
20
21
|
Requires-Dist: jaxtyping>=0.2.20
|
|
21
22
|
Requires-Dist: jmp>=0.0.4
|
|
22
23
|
Requires-Dist: safetensors>=0.4.3
|
|
@@ -6,19 +6,89 @@ arrays (see [haliax.zeros][] and [haliax.ones][]) as well as things like reducti
|
|
|
6
6
|
|
|
7
7
|
## Axis Types
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
If you already speak NumPy or `jax.numpy`, think of Haliax as swapping positional axes (`axis=0`) for named axes
|
|
10
|
+
(`axis="batch"`). The type hints in this section describe the different ways those named axes can be provided to the API.
|
|
11
|
+
They appear throughout the documentation and in signatures so that you can quickly tell which forms are accepted.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
This type is used when we want one or more axes and the sizes can be inferred from the inputs, for instance when
|
|
18
|
-
reducing an array.
|
|
13
|
+
| Name | Accepts | When to use it | Example |
|
|
14
|
+
| --- | --- | --- | --- |
|
|
15
|
+
| [`Axis`][haliax.Axis] | `Axis(name: str, size: int)` | Define a named dimension with an explicit size | `Batch = Axis("batch", 32)` |
|
|
16
|
+
| [`AxisSelector`][haliax.AxisSelector] | `Axis` or `str` | Refer to an existing axis whose size can be inferred from the arrays you pass in | `x.sum(axis="batch")` |
|
|
17
|
+
| [`AxisSpec`][haliax.AxisSpec] | `dict[str, int]`, `Axis`, or a sequence of `Axis` objects | Create or reshape arrays when the axis sizes must be provided | `hax.zeros((Batch, Feature))` |
|
|
18
|
+
| [`AxisSelection`][haliax.AxisSelection] | `dict[str, int | None]`, `AxisSpec`, or a sequence of `AxisSelector` values | Work with one or more existing axes (reductions, indexing helpers, flattening, …) | `x.sum(axis=("batch", Feature))` |
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
### Axis
|
|
21
|
+
|
|
22
|
+
An [`Axis`][haliax.Axis] is the fundamental building block: it is a tiny dataclass that stores a name and a size. You can
|
|
23
|
+
construct one directly or use [`haliax.make_axes`][] to generate several at a time.
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import haliax as hax
|
|
27
|
+
from haliax import Axis
|
|
28
|
+
|
|
29
|
+
Batch = Axis("batch", 32)
|
|
30
|
+
Feature = Axis("feature", 128)
|
|
31
|
+
x = hax.ones((Batch, Feature))
|
|
32
|
+
print(Batch.name, Batch.size)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Using `Axis` objects keeps array creation explicit and gives reusable handles you can share between different tensors.
|
|
36
|
+
Equality compares both the name and size so you get guardrails when wiring pieces together.
|
|
37
|
+
|
|
38
|
+
### AxisSelector
|
|
39
|
+
|
|
40
|
+
An [`AxisSelector`][haliax.AxisSelector] accepts either an `Axis` object or just the axis name as a string. It is used
|
|
41
|
+
whenever a function can read the axis size from one of its arguments. This mirrors how NumPy lets you pass `axis=0` when
|
|
42
|
+
reducing an array:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
total = x.sum(axis=Batch) # using the Axis handle
|
|
46
|
+
same_total = x.sum(axis="batch") # using only the name
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Strings are convenient when you only care about the name, but `Axis` objects still work so you can keep using the handles
|
|
50
|
+
you created earlier. If an axis with that name is missing, Haliax raises a `ValueError`.
|
|
51
|
+
|
|
52
|
+
### AxisSpec
|
|
53
|
+
|
|
54
|
+
An [`AxisSpec`][haliax.AxisSpec] is used when Haliax needs full size information to create or reshape an array. You can
|
|
55
|
+
provide a shape dictionary (sometimes called a "shape dict") that maps names to sizes, or a sequence of `Axis` objects:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
shape = {"batch": 32, "feature": 128}
|
|
59
|
+
y = hax.zeros(shape) # using a shape dict
|
|
60
|
+
z = hax.zeros((Batch, Feature)) # using the Axis objects directly
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Both forms describe the same layout. Python dictionaries preserve insertion order, so the ordering in a shape dict matches
|
|
64
|
+
the order that axes appear in the array. Sequences must contain `Axis` objects (not plain strings) because Haliax cannot
|
|
65
|
+
otherwise know the axis sizes.
|
|
66
|
+
|
|
67
|
+
### AxisSelection
|
|
68
|
+
|
|
69
|
+
[`AxisSelection`][haliax.AxisSelection] generalizes the previous aliases so you can talk about several axes at once. It
|
|
70
|
+
shows up in reductions, indexing helpers, axis-mapping utilities, and anywhere you might have written `axis=(0, 1)` in
|
|
71
|
+
NumPy. You may supply:
|
|
72
|
+
|
|
73
|
+
* a sequence mixing `Axis` objects and strings, e.g. `("batch", Feature)` when reducing two axes,
|
|
74
|
+
* an `AxisSpec`, which is handy when you already have a tuple of `Axis` objects, or
|
|
75
|
+
* a "partial shape dict" where the values are either sizes or `None` to indicate "any size". Dictionaries are useful when
|
|
76
|
+
you only care about a subset of axes or want to assert a particular size.
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
# Reduce over two axes using a tuple of selectors.
|
|
80
|
+
scalar = x.sum(axis=("batch", Feature))
|
|
81
|
+
|
|
82
|
+
# Ask for the axes by name and optionally pin sizes.
|
|
83
|
+
x.resolve_axis({"batch": None, "feature": None}) # returns {"batch": 32, "feature": 128}
|
|
84
|
+
|
|
85
|
+
from haliax.axis import selects_axis
|
|
86
|
+
assert selects_axis((Batch, "feature"), {"batch": None, "feature": 128})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Occasionally, an axis size can be inferred in some circumstances but not others. When this happens we still use
|
|
90
|
+
`AxisSelector` (or `AxisSelection` for multiple axes) but document the behavior in the docstring. A `RuntimeError` will be
|
|
91
|
+
raised if the size cannot be inferred.
|
|
22
92
|
|
|
23
93
|
::: haliax.Axis
|
|
24
94
|
::: haliax.AxisSelector
|
|
@@ -270,6 +340,21 @@ These are all more or less directly from JAX's NumPy API.
|
|
|
270
340
|
::: haliax.subtract
|
|
271
341
|
::: haliax.true_divide
|
|
272
342
|
|
|
343
|
+
### Polynomial Operations
|
|
344
|
+
|
|
345
|
+
::: haliax.poly
|
|
346
|
+
::: haliax.polyadd
|
|
347
|
+
::: haliax.polysub
|
|
348
|
+
::: haliax.polymul
|
|
349
|
+
::: haliax.polydiv
|
|
350
|
+
::: haliax.polyint
|
|
351
|
+
::: haliax.polyder
|
|
352
|
+
::: haliax.polyval
|
|
353
|
+
::: haliax.polyfit
|
|
354
|
+
::: haliax.roots
|
|
355
|
+
::: haliax.trim_zeros
|
|
356
|
+
::: haliax.vander
|
|
357
|
+
|
|
273
358
|
### Other Operations
|
|
274
359
|
|
|
275
360
|
::: haliax.bincount
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Haliax Primer
|
|
2
|
+
|
|
3
|
+
Haliax provides named tensors built on top of JAX. This primer is written for LLM agents and other downstream libraries and collects the core ideas for quick reference.
|
|
4
|
+
|
|
5
|
+
## Axes and Named Arrays
|
|
6
|
+
|
|
7
|
+
Arrays are indexed by `Axis` objects. You can define them explicitly or generate several with `make_axes`.
|
|
8
|
+
You may also specify shapes with a **shape dict**, mapping axis names to sizes.
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
import haliax as hax
|
|
12
|
+
from haliax import Axis
|
|
13
|
+
|
|
14
|
+
Batch = Axis("batch", 4)
|
|
15
|
+
Feature = Axis("feature", 8)
|
|
16
|
+
# or: Batch, Feature = hax.make_axes(batch=4, feature=8)
|
|
17
|
+
# using Axis objects
|
|
18
|
+
x = hax.zeros((Batch, Feature))
|
|
19
|
+
# or using a shape dict
|
|
20
|
+
shape = {"batch": 4, "feature": 8}
|
|
21
|
+
x = hax.zeros(shape)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Most functions accept either axes or shape dicts interchangeably.
|
|
25
|
+
|
|
26
|
+
A tensor with named axes is a [`NamedArray`][haliax.NamedArray]. Elementwise operations mirror `jax.numpy` but accept named axes.
|
|
27
|
+
|
|
28
|
+
### Ways to Describe Axes
|
|
29
|
+
|
|
30
|
+
If you're used to `axis=0` style code in NumPy or JAX, think of Haliax as swapping those positional indices for names
|
|
31
|
+
like `axis="batch"`. The API hints refer to a few helper aliases; this table shows how they map back to familiar
|
|
32
|
+
concepts:
|
|
33
|
+
|
|
34
|
+
| Name | Accepts | Typical use | Example |
|
|
35
|
+
| --- | --- | --- | --- |
|
|
36
|
+
| [`Axis`][haliax.Axis] | `Axis(name: str, size: int)` | Define a named dimension with a fixed size | `Batch = Axis("batch", 32)` |
|
|
37
|
+
| [`AxisSelector`][haliax.AxisSelector] | `Axis` or `str` | Refer to an existing axis when the size can be inferred from the argument | `x.sum(axis="batch")` |
|
|
38
|
+
| [`AxisSpec`][haliax.AxisSpec] | `dict[str, int]`, `Axis`, or a sequence of `Axis` objects | Supply complete shape information (array creation, reshaping) | `hax.zeros((Batch, Feature))` |
|
|
39
|
+
| [`AxisSelection`][haliax.AxisSelection] | `dict[str, int | None]`, `AxisSpec`, or a sequence of `AxisSelector` values | Work with one or more existing axes (reductions, indexing helpers, flattening, …) | `x.sum(axis=("batch", Feature))` |
|
|
40
|
+
|
|
41
|
+
The following sections expand on each alias with quick references and NumPy-style parallels.
|
|
42
|
+
|
|
43
|
+
#### `Axis`: reusable named dimensions
|
|
44
|
+
|
|
45
|
+
An [`Axis`][haliax.Axis] stores a `name` and a `size`. Create them directly or let
|
|
46
|
+
[`haliax.make_axes`][] build a handful at once. Because axes compare by both name and size, they act as reusable handles and
|
|
47
|
+
catch many wiring mistakes early.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
Batch = Axis("batch", 32)
|
|
51
|
+
Feature = Axis("feature", 128)
|
|
52
|
+
x = hax.ones((Batch, Feature))
|
|
53
|
+
print(Batch.name, Batch.size)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### `AxisSelector`: when the size is already known
|
|
57
|
+
|
|
58
|
+
Many functions already see the array whose axes you're referencing (e.g. reductions). In those cases you can pass either the
|
|
59
|
+
`Axis` object or simply the axis name as a string. Haliax resolves the name against the array, similar to `axis=0` in NumPy.
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
total = x.sum(axis=Batch) # use the Axis handle
|
|
63
|
+
same_total = x.sum(axis="batch") # or just the name
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
If you reference an axis name that isn't present, Haliax raises a `ValueError`.
|
|
67
|
+
|
|
68
|
+
#### `AxisSpec`: describing complete shapes
|
|
69
|
+
|
|
70
|
+
When Haliax needs explicit sizes—creating arrays, reshaping, broadcasting to a new axis—you provide an [`AxisSpec`][haliax.AxisSpec].
|
|
71
|
+
Shape dictionaries keep things close to standard Python, while sequences require actual `Axis` objects so the sizes stay explicit.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
shape = {"batch": 32, "feature": 128}
|
|
75
|
+
y = hax.zeros(shape) # using a shape dict
|
|
76
|
+
z = hax.zeros((Batch, Feature)) # or a sequence of Axis objects
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Python dictionaries preserve insertion order, so the layout in a shape dict matches the order of axes in the resulting array.
|
|
80
|
+
|
|
81
|
+
#### `AxisSelection`: several axes at once
|
|
82
|
+
|
|
83
|
+
[`AxisSelection`][haliax.AxisSelection] is the plural form used by reductions, indexing helpers, and flattening utilities. Supply a
|
|
84
|
+
tuple mixing `Axis` objects and strings, reuse an existing `AxisSpec`, or pass a partial shape dict where values are either
|
|
85
|
+
sizes or `None` for "any size".
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
scalar = x.sum(axis=("batch", Feature))
|
|
89
|
+
|
|
90
|
+
# Ask for the axes by name and optionally pin sizes.
|
|
91
|
+
x.resolve_axis({"batch": None, "feature": None}) # returns {"batch": 32, "feature": 128}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Partial shape dicts shine when you only care about a subset of axes or want assertions about their sizes. If the axis size
|
|
95
|
+
cannot be inferred from the provided arguments, Haliax raises a `RuntimeError`.
|
|
96
|
+
|
|
97
|
+
## Indexing and Broadcasting
|
|
98
|
+
|
|
99
|
+
Use axis names when slicing. Dictionaries are convenient for several axes:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
first = x["batch", 0]
|
|
103
|
+
sub = x["batch", 1:3]
|
|
104
|
+
# or with a dict
|
|
105
|
+
first = x[{"batch": 0}]
|
|
106
|
+
sub = x[{"batch": slice(1, 3)}]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Axes broadcast by matching names. `broadcast_axis` adds a new axis to an array:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
row = hax.arange(Feature)
|
|
113
|
+
outer = row.broadcast_axis(Batch) * hax.arange(Batch)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
See [Indexing and Slicing](indexing.md) and [Broadcasting](broadcasting.md) for details.
|
|
117
|
+
|
|
118
|
+
## Rearranging Axes
|
|
119
|
+
|
|
120
|
+
`rearrange` changes axis order and can merge or split axes using einops‑style syntax. It is useful when interfacing with positional APIs.
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# transpose features and batch
|
|
124
|
+
x_t = hax.rearrange(x, "batch feature -> feature batch")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
More examples appear in [Rearrange](rearrange.md).
|
|
128
|
+
|
|
129
|
+
## Matrix Multiplication
|
|
130
|
+
|
|
131
|
+
`dot` contracts over named axes while preserving order independence.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
Weight = Axis("weight", 8)
|
|
135
|
+
w = hax.ones((Feature, Weight))
|
|
136
|
+
prod = hax.dot(x, w, axis=Feature)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
For more complex contractions use [`einsum`][haliax.einsum]. See [Matrix Multiplication](matmul.md).
|
|
140
|
+
|
|
141
|
+
## Scans and Folds
|
|
142
|
+
|
|
143
|
+
Use [`scan`][haliax.scan] or [`fold`][haliax.fold] to apply a function along an axis with optional gradient checkpointing.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
Time = Axis("time", 10)
|
|
147
|
+
sequence = hax.ones((Time, Feature))
|
|
148
|
+
|
|
149
|
+
def add(prev, cur):
|
|
150
|
+
return prev + cur
|
|
151
|
+
|
|
152
|
+
result = hax.fold(add, Time)(hax.zeros((Feature,)), sequence)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
See [Scan and Fold](scan.md) for checkpointing policies and stacked modules.
|
|
156
|
+
|
|
157
|
+
## Partitioning
|
|
158
|
+
|
|
159
|
+
Arrays and modules can be distributed across devices by mapping named axes to mesh axes:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
with hax.axis_mapping({"batch": "data"}):
|
|
163
|
+
sharded = hax.shard(x)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The [Partitioning](partitioning.md) guide explains how to set up device meshes and shard arrays.
|
|
167
|
+
|
|
168
|
+
## Typing Support
|
|
169
|
+
|
|
170
|
+
Type annotations use `haliax.haxtyping` which extends `jaxtyping`:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
import haliax.haxtyping as ht
|
|
174
|
+
|
|
175
|
+
def f(t: ht.Float[hax.NamedArray, "batch feature"]):
|
|
176
|
+
...
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
See [Typing](typing.md) for matching runtime checks and dtype-aware annotations.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
This primer highlights common patterns. The [cheatsheet](cheatsheet.md) lists many additional conversions from JAX to Haliax.
|
|
@@ -21,8 +21,7 @@ classifiers = [
|
|
|
21
21
|
"Intended Audience :: Science/Research",
|
|
22
22
|
]
|
|
23
23
|
dependencies = [
|
|
24
|
-
|
|
25
|
-
# jax = {version = ">=0.4.19,<0.5.0"}
|
|
24
|
+
"jax >= 0.6.2",
|
|
26
25
|
"equinox>=0.10.6",
|
|
27
26
|
"jaxtyping>=0.2.20",
|
|
28
27
|
"jmp>=0.0.4",
|
|
@@ -8,11 +8,8 @@ from typing import Optional, Sequence
|
|
|
8
8
|
|
|
9
9
|
import jax
|
|
10
10
|
import jax.numpy as jnp
|
|
11
|
+
from jax.typing import DTypeLike
|
|
11
12
|
|
|
12
|
-
try:
|
|
13
|
-
from jax.typing import DTypeLike
|
|
14
|
-
except ImportError:
|
|
15
|
-
from jax._src.typing import DTypeLike
|
|
16
13
|
|
|
17
14
|
import haliax.debug as debug
|
|
18
15
|
import haliax.nn as nn
|
|
@@ -96,6 +93,22 @@ from .ops import (
|
|
|
96
93
|
bincount,
|
|
97
94
|
where,
|
|
98
95
|
)
|
|
96
|
+
|
|
97
|
+
from .poly import (
|
|
98
|
+
poly,
|
|
99
|
+
polyadd,
|
|
100
|
+
polysub,
|
|
101
|
+
polymul,
|
|
102
|
+
polydiv,
|
|
103
|
+
polyint,
|
|
104
|
+
polyder,
|
|
105
|
+
polyval,
|
|
106
|
+
polyfit,
|
|
107
|
+
roots,
|
|
108
|
+
trim_zeros,
|
|
109
|
+
vander,
|
|
110
|
+
)
|
|
111
|
+
|
|
99
112
|
from .fft import (
|
|
100
113
|
fft,
|
|
101
114
|
fftfreq,
|
|
@@ -108,7 +121,7 @@ from .fft import (
|
|
|
108
121
|
rfft,
|
|
109
122
|
rfftfreq,
|
|
110
123
|
)
|
|
111
|
-
from .partitioning import auto_sharded, axis_mapping, fsdp, named_jit, shard, shard_with_axis_mapping
|
|
124
|
+
from .partitioning import auto_sharded, axis_mapping, fsdp, named_jit, set_mesh, shard, shard_with_axis_mapping
|
|
112
125
|
from .specialized_fns import top_k
|
|
113
126
|
from .types import Scalar
|
|
114
127
|
from .util import is_named_array
|
|
@@ -715,7 +728,9 @@ def nanmean(
|
|
|
715
728
|
where: Optional[NamedArray] = None,
|
|
716
729
|
dtype: Optional[DTypeLike] = None,
|
|
717
730
|
) -> NamedArray:
|
|
718
|
-
return wrap_reduction_call(
|
|
731
|
+
return wrap_reduction_call(
|
|
732
|
+
jnp.nanmean, array, axis, where, single_axis_only=False, supports_where=True, dtype=dtype
|
|
733
|
+
)
|
|
719
734
|
|
|
720
735
|
|
|
721
736
|
def nanmin(
|
|
@@ -734,7 +749,9 @@ def nanprod(
|
|
|
734
749
|
where: Optional[NamedArray] = None,
|
|
735
750
|
dtype: Optional[DTypeLike] = None,
|
|
736
751
|
) -> NamedArray:
|
|
737
|
-
return wrap_reduction_call(
|
|
752
|
+
return wrap_reduction_call(
|
|
753
|
+
jnp.nanprod, array, axis, where, single_axis_only=False, supports_where=True, dtype=dtype
|
|
754
|
+
)
|
|
738
755
|
|
|
739
756
|
|
|
740
757
|
def nanstd(
|
|
@@ -745,7 +762,9 @@ def nanstd(
|
|
|
745
762
|
ddof: int = 0,
|
|
746
763
|
dtype: Optional[DTypeLike] = None,
|
|
747
764
|
) -> NamedArray:
|
|
748
|
-
return wrap_reduction_call(
|
|
765
|
+
return wrap_reduction_call(
|
|
766
|
+
jnp.nanstd, array, axis, where, single_axis_only=False, supports_where=True, dtype=dtype, ddof=ddof
|
|
767
|
+
)
|
|
749
768
|
|
|
750
769
|
|
|
751
770
|
def nansum(
|
|
@@ -755,7 +774,9 @@ def nansum(
|
|
|
755
774
|
where: Optional[NamedArray] = None,
|
|
756
775
|
dtype: Optional[DTypeLike] = None,
|
|
757
776
|
) -> NamedArray:
|
|
758
|
-
return wrap_reduction_call(
|
|
777
|
+
return wrap_reduction_call(
|
|
778
|
+
jnp.nansum, array, axis, where, single_axis_only=False, supports_where=True, dtype=dtype
|
|
779
|
+
)
|
|
759
780
|
|
|
760
781
|
|
|
761
782
|
def nanvar(
|
|
@@ -766,7 +787,9 @@ def nanvar(
|
|
|
766
787
|
ddof: int = 0,
|
|
767
788
|
dtype: Optional[DTypeLike] = None,
|
|
768
789
|
) -> NamedArray:
|
|
769
|
-
return wrap_reduction_call(
|
|
790
|
+
return wrap_reduction_call(
|
|
791
|
+
jnp.nanvar, array, axis, where, single_axis_only=False, supports_where=True, dtype=dtype, ddof=ddof
|
|
792
|
+
)
|
|
770
793
|
|
|
771
794
|
|
|
772
795
|
# "Normalization" functions that use an axis but don't change the shape
|
|
@@ -807,14 +830,17 @@ def sort(a: NamedArray, axis: AxisSelector) -> NamedArray:
|
|
|
807
830
|
return wrap_axiswise_call(jnp.sort, a, axis, single_axis_only=True)
|
|
808
831
|
|
|
809
832
|
|
|
810
|
-
def argsort(a: NamedArray, axis: AxisSelector) -> NamedArray:
|
|
833
|
+
def argsort(a: NamedArray, axis: AxisSelector | None, *, stable: bool = False) -> NamedArray:
|
|
811
834
|
"""
|
|
812
835
|
Named version of [jax.numpy.argsort](https://jax.readthedocs.io/en/latest/_autosummary/jax.numpy.argsort.html).
|
|
813
836
|
|
|
814
837
|
If `axis` is None, the returned array will be a 1D array of indices that would sort the flattened array,
|
|
815
838
|
identical to `jax.numpy.argsort(a.array)`.
|
|
839
|
+
|
|
840
|
+
Args:
|
|
841
|
+
stable: If ``True``, ensures that the indices of equal elements preserve their relative order.
|
|
816
842
|
"""
|
|
817
|
-
return wrap_axiswise_call(jnp.argsort, a, axis, single_axis_only=True)
|
|
843
|
+
return wrap_axiswise_call(jnp.argsort, a, axis, single_axis_only=True, stable=stable)
|
|
818
844
|
|
|
819
845
|
|
|
820
846
|
# elemwise binary ops
|
|
@@ -1226,6 +1252,18 @@ __all__ = [
|
|
|
1226
1252
|
"clip",
|
|
1227
1253
|
"tril",
|
|
1228
1254
|
"triu",
|
|
1255
|
+
"poly",
|
|
1256
|
+
"polyadd",
|
|
1257
|
+
"polysub",
|
|
1258
|
+
"polymul",
|
|
1259
|
+
"polydiv",
|
|
1260
|
+
"polyint",
|
|
1261
|
+
"polyder",
|
|
1262
|
+
"polyval",
|
|
1263
|
+
"polyfit",
|
|
1264
|
+
"roots",
|
|
1265
|
+
"trim_zeros",
|
|
1266
|
+
"vander",
|
|
1229
1267
|
"fft",
|
|
1230
1268
|
"ifft",
|
|
1231
1269
|
"hfft",
|
|
@@ -1311,4 +1349,5 @@ __all__ = [
|
|
|
1311
1349
|
"NamedArrayAxes",
|
|
1312
1350
|
"NamedArrayAxesSpec",
|
|
1313
1351
|
"Named",
|
|
1352
|
+
"set_mesh",
|
|
1314
1353
|
]
|
|
@@ -197,7 +197,7 @@ def from_state_dict(tree: T, state_dict: StateDict, prefix: Optional[str] = None
|
|
|
197
197
|
array = state_dict[prefix]
|
|
198
198
|
|
|
199
199
|
if isinstance(array, np.ndarray):
|
|
200
|
-
mesh =
|
|
200
|
+
mesh = jax.sharding.get_abstract_mesh()
|
|
201
201
|
# TODO: modernize this
|
|
202
202
|
if jax.device_count() > 1: # this happens with the default mesh
|
|
203
203
|
pspec = partitioning.pspec_for_axis(tree.axes)
|
|
@@ -623,8 +623,8 @@ class NamedArray(metaclass=NamedArrayMeta):
|
|
|
623
623
|
def argmin(self, axis: Optional[AxisSelector]) -> "NamedArray": # pragma: no cover
|
|
624
624
|
return haliax.argmin(self, axis=axis)
|
|
625
625
|
|
|
626
|
-
def argsort(self, axis: AxisSelector) -> "NamedArray": # pragma: no cover
|
|
627
|
-
return haliax.argsort(self, axis=axis)
|
|
626
|
+
def argsort(self, axis: AxisSelector | None, *, stable: bool = False) -> "NamedArray": # pragma: no cover
|
|
627
|
+
return haliax.argsort(self, axis=axis, stable=stable)
|
|
628
628
|
|
|
629
629
|
def astype(self, dtype) -> "NamedArray": # pragma: no cover
|
|
630
630
|
return NamedArray(self.array.astype(dtype), self.axes)
|
|
@@ -1183,6 +1183,26 @@ def index(array: NamedArray, slices: Mapping[AxisSelector, NamedIndex]) -> Named
|
|
|
1183
1183
|
def _compute_new_axes_and_slices_for_index(
|
|
1184
1184
|
array, slices
|
|
1185
1185
|
) -> tuple[AxisSpec, list[py_slice | dslice | jnp.ndarray | int | list[int]]]:
|
|
1186
|
+
def _is_integer_like_scalar_index(value: Any) -> bool:
|
|
1187
|
+
if isinstance(value, (int, np.integer)):
|
|
1188
|
+
return True
|
|
1189
|
+
if not is_jax_array_like(value):
|
|
1190
|
+
return False
|
|
1191
|
+
shape = getattr(value, "shape", None)
|
|
1192
|
+
if shape != ():
|
|
1193
|
+
return False
|
|
1194
|
+
dtype = getattr(value, "dtype", None)
|
|
1195
|
+
if dtype is None:
|
|
1196
|
+
return False
|
|
1197
|
+
return jnp.issubdtype(dtype, jnp.integer)
|
|
1198
|
+
|
|
1199
|
+
def _coerce_integer_like_index(value: Any):
|
|
1200
|
+
if isinstance(value, np.integer):
|
|
1201
|
+
return int(value)
|
|
1202
|
+
if type(value) is np.ndarray and value.shape == () and jnp.issubdtype(value.dtype, jnp.integer):
|
|
1203
|
+
return int(value.item())
|
|
1204
|
+
return value
|
|
1205
|
+
|
|
1186
1206
|
ordered_slices: list = [py_slice(None, None, None)] * len(array.axes) # type: ignore
|
|
1187
1207
|
kept_axes = [True] * len(array.axes)
|
|
1188
1208
|
array_slice_indices = []
|
|
@@ -1205,8 +1225,8 @@ def _compute_new_axes_and_slices_for_index(
|
|
|
1205
1225
|
kept_axes[axis_index] = False
|
|
1206
1226
|
array_slice_indices.append(axis_index)
|
|
1207
1227
|
index_axis_names.add(orig_axis.name)
|
|
1208
|
-
elif
|
|
1209
|
-
ordered_slices[axis_index] = slice_
|
|
1228
|
+
elif _is_integer_like_scalar_index(slice_):
|
|
1229
|
+
ordered_slices[axis_index] = _coerce_integer_like_index(slice_)
|
|
1210
1230
|
kept_axes[axis_index] = False
|
|
1211
1231
|
elif isinstance(slice_, NamedArray):
|
|
1212
1232
|
ordered_slices[axis_index] = slice_
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# Copyright 2025 The Levanter Authors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
1
5
|
"""Named wrappers around :mod:`jax.numpy.fft`.
|
|
2
6
|
|
|
3
7
|
These functions mirror the behaviour of their :mod:`jax.numpy.fft` counterparts
|
|
@@ -43,7 +47,6 @@ import jax.numpy.fft as jfft
|
|
|
43
47
|
from .axis import Axis, AxisSelector, AxisSelection
|
|
44
48
|
from .core import NamedArray
|
|
45
49
|
|
|
46
|
-
|
|
47
50
|
AxisSizeLike = int | Axis | None
|
|
48
51
|
AxisMapping = Mapping[AxisSelector, AxisSizeLike]
|
|
49
52
|
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
import numbers
|
|
7
|
+
|
|
6
8
|
import jax.nn as jnn
|
|
7
9
|
import jax.numpy as jnp
|
|
8
10
|
|
|
@@ -64,16 +66,25 @@ def one_hot(x: NamedArray | int, class_axis: Axis, *, dtype=None) -> NamedArray:
|
|
|
64
66
|
# Disabling this to prevent a crash in XLA on GPU
|
|
65
67
|
# return hax.auto_sharded(hax.named(array, x.axes + (class_axis,)))
|
|
66
68
|
return hax.named(array, x.axes + (class_axis,))
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
|
|
70
|
+
x_array = jnp.asarray(x)
|
|
71
|
+
if x_array.ndim != 0:
|
|
72
|
+
raise TypeError("one_hot expects a scalar integer or NamedArray, " f"but got array with shape {x_array.shape}")
|
|
73
|
+
|
|
74
|
+
if isinstance(x, numbers.Integral):
|
|
69
75
|
assert class_axis.size > x >= -class_axis.size
|
|
76
|
+
else:
|
|
77
|
+
if not (jnp.issubdtype(x_array.dtype, jnp.integer) or jnp.issubdtype(x_array.dtype, jnp.bool_)):
|
|
78
|
+
raise TypeError(
|
|
79
|
+
"one_hot expects an integer scalar or NamedArray, " f"but got value with dtype {x_array.dtype}"
|
|
80
|
+
)
|
|
70
81
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
one = 1
|
|
83
|
+
if dtype is not None:
|
|
84
|
+
one = dtype(one)
|
|
74
85
|
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
array = jnp.zeros(class_axis.size, dtype=dtype).at[x_array].set(one)
|
|
87
|
+
return hax.auto_sharded(haliax.named(array, class_axis))
|
|
77
88
|
|
|
78
89
|
|
|
79
90
|
__all__ = [
|
|
@@ -251,7 +251,7 @@ def _gmm(lhs, rhs, group_sizes, out_axes, sharded=False, ar=False):
|
|
|
251
251
|
else:
|
|
252
252
|
gmm_fn = shard_map(
|
|
253
253
|
partial(gmm_sharded, ar=ar),
|
|
254
|
-
mesh=
|
|
254
|
+
mesh=jax.sharding.get_abstract_mesh(),
|
|
255
255
|
in_specs=(
|
|
256
256
|
hax.partitioning.pspec_for_axis(lhs.axes),
|
|
257
257
|
hax.partitioning.pspec_for_axis(rhs.axes),
|