haliax 1.4.dev369__tar.gz → 1.4.dev372__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.dev369 → haliax-1.4.dev372}/.github/workflows/run_tests.yaml +3 -4
- {haliax-1.4.dev369 → haliax-1.4.dev372}/AGENTS.md +3 -3
- {haliax-1.4.dev369 → haliax-1.4.dev372}/PKG-INFO +1 -1
- haliax-1.4.dev372/src/haliax/__about__.py +1 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/scan.py +60 -1
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_scan.py +55 -0
- haliax-1.4.dev372/uv.lock +1711 -0
- haliax-1.4.dev369/src/haliax/__about__.py +0 -1
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.coveragerc +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.flake8 +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.gitignore +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.playbooks/add-types.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/LICENSE +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/README.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/api.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/css/material.css +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/faq.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/fp8.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/index.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/indexing.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/matmul.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/nn.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/partitioning.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/rearrange.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/requirements.txt +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/scan.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/state-dict.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/tutorial.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/typing.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/docs/vmap.md +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/mkdocs.yml +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/pyproject.toml +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/__init__.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/einsum.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/scan.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/state_dict.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/core.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/haxtyping.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/jax_utils.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/__init__.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/linear.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/nn/pool.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/ops.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/partitioning.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/random.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/state_dict.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/types.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/util.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/core_test.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_attention.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_axis.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_conv.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_debug.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_dot.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_dtype_typing.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_hof.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_int8.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_namedarray_typing.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_nn.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_ops.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_partitioning.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_pool.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_random.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_scatter_gather.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_state_dict.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_tree_util.py +0 -0
- {haliax-1.4.dev369 → haliax-1.4.dev372}/tests/test_utils.py +0 -0
|
@@ -15,9 +15,8 @@ jobs:
|
|
|
15
15
|
python-version: 3.10.11
|
|
16
16
|
- name: Install dependencies
|
|
17
17
|
run: |
|
|
18
|
-
python -m pip install
|
|
19
|
-
|
|
20
|
-
pip install -e .[dev]
|
|
18
|
+
python -m pip install uv
|
|
19
|
+
uv sync
|
|
21
20
|
- name: Test with pytest
|
|
22
21
|
run: |
|
|
23
|
-
XLA_FLAGS=--xla_force_host_platform_device_count=8 PYTHONPATH=tests:src:. pytest tests
|
|
22
|
+
XLA_FLAGS=--xla_force_host_platform_device_count=8 PYTHONPATH=tests:src:. uv run pytest tests
|
|
@@ -12,11 +12,11 @@ repository. Follow these notes when implementing new features or fixing bugs.
|
|
|
12
12
|
floating point tests, add that to the list.
|
|
13
13
|
* **Playbooks.** Sometimes, there are repeatable tasks (e.g. porting models) for which we follow a standard set of steps.
|
|
14
14
|
Please reference `.playbooks/` to see what playbooks are available, or see the list below. If you want to add a playbook
|
|
15
|
-
write a markdown doc named e.g. `.playbooks/
|
|
15
|
+
write a markdown doc named e.g. `.playbooks/add-types.md` and add a pointer to it in the list below.
|
|
16
16
|
|
|
17
17
|
## Playbook
|
|
18
18
|
|
|
19
|
-
- Adding Haliax-style tensor typing annotations are described in @.playbooks/add-
|
|
19
|
+
- Adding Haliax-style tensor typing annotations are described in @.playbooks/add-types.md
|
|
20
20
|
|
|
21
21
|
## Code Style
|
|
22
22
|
|
|
@@ -44,7 +44,7 @@ repository. Follow these notes when implementing new features or fixing bugs.
|
|
|
44
44
|
|
|
45
45
|
## Testing
|
|
46
46
|
|
|
47
|
-
* Tests are executed with `pytest`. The default workflow runs `uv run pytest tests`.
|
|
47
|
+
* Tests are executed with `pytest`. The default workflow runs ` XLA_FLAGS=--xla_force_host_platform_device_count=8 PYTHONPATH=tests:src:. uv run pytest tests`.
|
|
48
48
|
* In general, never relax tolerances in floating point tests unless specifically discussed with the
|
|
49
49
|
team. Use `assert_allclose` with appropriate tolerances for numerical comparisons. We typically use
|
|
50
50
|
1e-4 for more complex modules, and 1e-5 for simpler ones.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haliax
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.dev372
|
|
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.dev372"
|
|
@@ -2,7 +2,7 @@ import dataclasses
|
|
|
2
2
|
import functools
|
|
3
3
|
import re
|
|
4
4
|
import warnings
|
|
5
|
-
from typing import Any, Dict, Generic, Optional, Protocol, Sequence, Type, TypeVar, cast
|
|
5
|
+
from typing import Any, Callable, Dict, Generic, Optional, Protocol, Sequence, Type, TypeVar, cast, overload, ParamSpec
|
|
6
6
|
|
|
7
7
|
import equinox as eqx
|
|
8
8
|
import jax
|
|
@@ -20,8 +20,21 @@ from ..axis import Axis
|
|
|
20
20
|
|
|
21
21
|
M = TypeVar("M", bound=eqx.Module)
|
|
22
22
|
M_co = TypeVar("M_co", bound=eqx.Module, covariant=True)
|
|
23
|
+
M_contra = TypeVar("M_contra", bound=eqx.Module, contravariant=True)
|
|
23
24
|
S = TypeVar("S", bound=eqx.Module)
|
|
24
25
|
T = TypeVar("T")
|
|
26
|
+
CarryT = TypeVar("CarryT")
|
|
27
|
+
OutputT_co = TypeVar("OutputT_co", covariant=True)
|
|
28
|
+
P = ParamSpec("P")
|
|
29
|
+
|
|
30
|
+
class FoldFunction(Protocol[M_contra, CarryT]):
|
|
31
|
+
def __call__(self, module: M_contra, carry: CarryT) -> CarryT:
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ScanFunction(Protocol[M_contra, CarryT, OutputT_co]):
|
|
36
|
+
def __call__(self, module: M_contra, carry: CarryT) -> tuple[CarryT, OutputT_co]:
|
|
37
|
+
...
|
|
25
38
|
|
|
26
39
|
|
|
27
40
|
class ModuleInit(Protocol[M_co]):
|
|
@@ -384,6 +397,52 @@ class Stacked(ModuleWithStateDictSerialization, Generic[M]):
|
|
|
384
397
|
|
|
385
398
|
return do_fold(init, *args, **kwargs)
|
|
386
399
|
|
|
400
|
+
@overload
|
|
401
|
+
def fold_via(self, fn: FoldFunction[M, CarryT]) -> Callable[[CarryT], CarryT]:
|
|
402
|
+
...
|
|
403
|
+
|
|
404
|
+
@overload
|
|
405
|
+
def fold_via(self, fn: Callable[[M, CarryT], CarryT]) -> Callable[[CarryT], CarryT]:
|
|
406
|
+
...
|
|
407
|
+
|
|
408
|
+
def fold_via(self, fn: Callable[..., CarryT]):
|
|
409
|
+
"""Return a function that folds over the stack using ``fn``.
|
|
410
|
+
|
|
411
|
+
``fn`` should take a block and a carry and return a new carry. The
|
|
412
|
+
returned function mirrors :func:`haliax.fold` over the block axis.
|
|
413
|
+
"""
|
|
414
|
+
|
|
415
|
+
def do_block(carry: CarryT, block: M) -> CarryT:
|
|
416
|
+
return fn(block, carry)
|
|
417
|
+
|
|
418
|
+
def do_fold(init: CarryT) -> CarryT:
|
|
419
|
+
return haliax.fold(do_block, self.Block, remat=self.gradient_checkpointing)(init, self.stacked)
|
|
420
|
+
|
|
421
|
+
return do_fold
|
|
422
|
+
|
|
423
|
+
@overload
|
|
424
|
+
def scan_via(self, fn: ScanFunction[M, CarryT, OutputT_co]) -> Callable[[CarryT], tuple[CarryT, OutputT_co]]:
|
|
425
|
+
...
|
|
426
|
+
|
|
427
|
+
@overload
|
|
428
|
+
def scan_via(self, fn: Callable[[M, CarryT], tuple[CarryT, OutputT_co]]) -> Callable[[CarryT], tuple[CarryT, OutputT_co]]:
|
|
429
|
+
...
|
|
430
|
+
|
|
431
|
+
def scan_via(self, fn: Callable[..., tuple[CarryT, OutputT_co]]):
|
|
432
|
+
"""Return a function that scans over the stack using ``fn``.
|
|
433
|
+
|
|
434
|
+
``fn`` should take a block and a carry and return ``(carry, output)``.
|
|
435
|
+
Semantics match :func:`haliax.scan` over the block axis.
|
|
436
|
+
"""
|
|
437
|
+
|
|
438
|
+
def do_block(carry: CarryT, block: M) -> tuple[CarryT, OutputT_co]:
|
|
439
|
+
return fn(block, carry)
|
|
440
|
+
|
|
441
|
+
def do_scan(init: CarryT) -> tuple[CarryT, OutputT_co]:
|
|
442
|
+
return haliax.scan(do_block, self.Block, remat=self.gradient_checkpointing)(init, self.stacked)
|
|
443
|
+
|
|
444
|
+
return do_scan
|
|
445
|
+
|
|
387
446
|
def vmap(self, init, *extra_args, **extra_kwargs):
|
|
388
447
|
"""Apply each block independently using :func:`haliax.vmap`.
|
|
389
448
|
|
|
@@ -309,3 +309,58 @@ def test_checkpoint_carries(name, policy, expected_scan_shapes, check_offloading
|
|
|
309
309
|
|
|
310
310
|
assert target is not None, f"Could not find named value for {name}"
|
|
311
311
|
assert found_saved, f"Could not find offloaded value for {name}"
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def test_fold_via():
|
|
315
|
+
class Module(eqx.Module):
|
|
316
|
+
w: hax.NamedArray
|
|
317
|
+
|
|
318
|
+
def __call__(self, x):
|
|
319
|
+
return x + self.w
|
|
320
|
+
|
|
321
|
+
def intermediate(self, x):
|
|
322
|
+
return x + 2 * self.w
|
|
323
|
+
|
|
324
|
+
@staticmethod
|
|
325
|
+
def init(named):
|
|
326
|
+
return Module(w=named)
|
|
327
|
+
|
|
328
|
+
Block = hax.Axis("block", 3)
|
|
329
|
+
E = hax.Axis("E", 5)
|
|
330
|
+
|
|
331
|
+
named = hax.random.uniform(jax.random.PRNGKey(0), (Block, E))
|
|
332
|
+
m = Stacked.init(Block, Module)(named=named)
|
|
333
|
+
|
|
334
|
+
x = hax.random.uniform(jax.random.PRNGKey(1), (E,))
|
|
335
|
+
result = m.fold_via(Module.intermediate)(x)
|
|
336
|
+
|
|
337
|
+
expected = x + 2 * hax.sum(named, Block)
|
|
338
|
+
assert hax.all(hax.isclose(result, expected))
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def test_scan_via():
|
|
342
|
+
class Module(eqx.Module):
|
|
343
|
+
w: hax.NamedArray
|
|
344
|
+
|
|
345
|
+
def with_output(self, x):
|
|
346
|
+
out = x + self.w
|
|
347
|
+
return out, 2 * self.w
|
|
348
|
+
|
|
349
|
+
@staticmethod
|
|
350
|
+
def init(named):
|
|
351
|
+
return Module(w=named)
|
|
352
|
+
|
|
353
|
+
Block = hax.Axis("block", 4)
|
|
354
|
+
E = hax.Axis("E", 6)
|
|
355
|
+
|
|
356
|
+
named = hax.random.uniform(jax.random.PRNGKey(0), (Block, E))
|
|
357
|
+
m = Stacked.init(Block, Module)(named=named)
|
|
358
|
+
|
|
359
|
+
x = hax.random.uniform(jax.random.PRNGKey(1), (E,))
|
|
360
|
+
carry, outs = m.scan_via(Module.with_output)(x)
|
|
361
|
+
|
|
362
|
+
expected_carry = x + hax.sum(named, Block)
|
|
363
|
+
expected_outs = 2 * named
|
|
364
|
+
|
|
365
|
+
assert hax.all(hax.isclose(carry, expected_carry))
|
|
366
|
+
assert hax.all(hax.isclose(outs, expected_outs))
|