haliax 1.4.dev412__tar.gz → 1.4.dev413__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.dev413}/PKG-INFO +1 -1
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/api.md +83 -13
- haliax-1.4.dev413/docs/primer.md +183 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/__about__.py +1 -1
- haliax-1.4.dev412/docs/primer.md +0 -114
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.agents/projects/api_parity.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.coveragerc +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.flake8 +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.github/workflows/run_tests.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.gitignore +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.playbooks/add-types.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.playbooks/wrap-non-named.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/AGENTS.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/AUTHORS.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/CONTRIBUTORS.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/LICENSE +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/README.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/css/material.css +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/faq.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/fp8.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/index.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/indexing.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/matmul.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/nn.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/partitioning.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/rearrange.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/requirements.txt +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/scan.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/state-dict.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/tutorial.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/typing.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/docs/vmap.md +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/etc/license_header.txt +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/mkdocs.yml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/pyproject.toml +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/__init__.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/einsum.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/scan.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/state_dict.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/core.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/fft.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/field.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/haxtyping.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/jax_utils.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/__init__.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/linear.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/pool.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/nn/scan.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/ops.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/partitioning.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/random.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/state_dict.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/types.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/util.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/core_test.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_attention.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_axis.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_bitwise_ops.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_conv.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_debug.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_dot.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_dtype_typing.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_fft.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_field.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_hof.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_int8.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_moe_linear.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_namedarray_typing.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_nan_reductions.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_nn.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_ops.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_partitioning.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_pool.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_random.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_scan.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_scatter_gather.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_state_dict.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_tree_util.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_utils.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/tests/test_visualize_sharding.py +0 -0
- {haliax-1.4.dev412 → haliax-1.4.dev413}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haliax
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.dev413
|
|
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/
|
|
@@ -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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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.
|
|
12
|
+
|
|
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
|
+
|
|
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
|
|
@@ -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.
|
haliax-1.4.dev412/docs/primer.md
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
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
|
-
## Indexing and Broadcasting
|
|
29
|
-
|
|
30
|
-
Use axis names when slicing. Dictionaries are convenient for several axes:
|
|
31
|
-
|
|
32
|
-
```python
|
|
33
|
-
first = x["batch", 0]
|
|
34
|
-
sub = x["batch", 1:3]
|
|
35
|
-
# or with a dict
|
|
36
|
-
first = x[{"batch": 0}]
|
|
37
|
-
sub = x[{"batch": slice(1, 3)}]
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Axes broadcast by matching names. `broadcast_axis` adds a new axis to an array:
|
|
41
|
-
|
|
42
|
-
```python
|
|
43
|
-
row = hax.arange(Feature)
|
|
44
|
-
outer = row.broadcast_axis(Batch) * hax.arange(Batch)
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
See [Indexing and Slicing](indexing.md) and [Broadcasting](broadcasting.md) for details.
|
|
48
|
-
|
|
49
|
-
## Rearranging Axes
|
|
50
|
-
|
|
51
|
-
`rearrange` changes axis order and can merge or split axes using einops‑style syntax. It is useful when interfacing with positional APIs.
|
|
52
|
-
|
|
53
|
-
```python
|
|
54
|
-
# transpose features and batch
|
|
55
|
-
x_t = hax.rearrange(x, "batch feature -> feature batch")
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
More examples appear in [Rearrange](rearrange.md).
|
|
59
|
-
|
|
60
|
-
## Matrix Multiplication
|
|
61
|
-
|
|
62
|
-
`dot` contracts over named axes while preserving order independence.
|
|
63
|
-
|
|
64
|
-
```python
|
|
65
|
-
Weight = Axis("weight", 8)
|
|
66
|
-
w = hax.ones((Feature, Weight))
|
|
67
|
-
prod = hax.dot(x, w, axis=Feature)
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
For more complex contractions use [`einsum`][haliax.einsum]. See [Matrix Multiplication](matmul.md).
|
|
71
|
-
|
|
72
|
-
## Scans and Folds
|
|
73
|
-
|
|
74
|
-
Use [`scan`][haliax.scan] or [`fold`][haliax.fold] to apply a function along an axis with optional gradient checkpointing.
|
|
75
|
-
|
|
76
|
-
```python
|
|
77
|
-
Time = Axis("time", 10)
|
|
78
|
-
sequence = hax.ones((Time, Feature))
|
|
79
|
-
|
|
80
|
-
def add(prev, cur):
|
|
81
|
-
return prev + cur
|
|
82
|
-
|
|
83
|
-
result = hax.fold(add, Time)(hax.zeros((Feature,)), sequence)
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
See [Scan and Fold](scan.md) for checkpointing policies and stacked modules.
|
|
87
|
-
|
|
88
|
-
## Partitioning
|
|
89
|
-
|
|
90
|
-
Arrays and modules can be distributed across devices by mapping named axes to mesh axes:
|
|
91
|
-
|
|
92
|
-
```python
|
|
93
|
-
with hax.axis_mapping({"batch": "data"}):
|
|
94
|
-
sharded = hax.shard(x)
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
The [Partitioning](partitioning.md) guide explains how to set up device meshes and shard arrays.
|
|
98
|
-
|
|
99
|
-
## Typing Support
|
|
100
|
-
|
|
101
|
-
Type annotations use `haliax.haxtyping` which extends `jaxtyping`:
|
|
102
|
-
|
|
103
|
-
```python
|
|
104
|
-
import haliax.haxtyping as ht
|
|
105
|
-
|
|
106
|
-
def f(t: ht.Float[hax.NamedArray, "batch feature"]):
|
|
107
|
-
...
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
See [Typing](typing.md) for matching runtime checks and dtype-aware annotations.
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
This primer highlights common patterns. The [cheatsheet](cheatsheet.md) lists many additional conversions from JAX to Haliax.
|
|
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
|
|
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
|