HEAL-SWIN-nnx
A Flax NNX port of
HEAL-SWIN (a HEALPix-native Swin Transformer U-Net),
plus the standard flat-grid Swin Transformer it shares code with. Pure
JAX/Flax; no PyTorch import anywhere in src/. The port reached verified
torch-parity (git tag parity-verified holds that state) and then diverged
deliberately — both models are now Swin V2-only (cosine attention,
post-norm); the HEALPix model additionally defaults to rotary positional
embeddings and seam-exact shifted windows.
Install
uv sync
Usage
import jax.numpy as jnp
from flax import nnx
from heal_swin_nnx import HealSwin, HealSwinParams
params = HealSwinParams(nside=16, in_channels=3, out_channels=5,
embed_dim=96, depths=(2, 2, 6, 2), num_heads=(3, 6, 12, 24))
model = HealSwin(params, rngs=nnx.Rngs(0))
x = jnp.ones((2, params.npix, params.in_channels)) # channels-last: (B, N, C)
y = model(x) # (B, params.npix, params.out_channels)
HealSwinParams is pure, serializable data — json.dumps(dataclasses.asdict(params))
works, so a run's exact configuration can be logged and compared. Notable
defaults: shift_strategy="nest_grid_shift_exact", pos_embed="rope_mixed".
Positional encoding
pos_embed selects one of "none", "rel_bias" (flat relative-position bias
table), "rope_axial", or "rope_mixed" (rope-vit-style rotary embeddings
computed on intra-window coordinates; "rope_mixed" additionally learns
per-head rotation frequencies). RoPE requires head dims divisible by 4.
HealSwinParams defaults to "rope_mixed"; SwinParams defaults to
"rel_bias".
Flat-grid model
The flat-grid counterpart mirrors this shape: SwinParams(img_size=(H, W), ...)
SwinUnet, with inputs/outputs as(B, H, W, C). Both models expose their encoder (HealSwinEncoder/SwinEncoder, returning(tokens, skips)) and decoder (HealSwinDecoder/SwinDecoder) standalone, so the encoder can be used without ever building decoder parameters.
Public API: HealSwin, HealSwinEncoder, HealSwinDecoder, HealSwinParams,
SwinUnet, SwinEncoder, SwinDecoder, SwinParams, Buffer (the
nnx.Variable subclass used for non-trainable index/mask state, excluded from
nnx.Param filters).
Examples
The spherical GRF simulation-based-inference example (HealSwin encoder +
gensbi Flux1 flow matching) lives in
GenSBI-examples under
examples/sbi-benchmarks/spherical_grf/.
Full sphere and partial coverage
Models cover the full sphere by default (all 12 HEALPix base pixels). Experiments that only see part of the sky select the base pixels they cover — e.g. a ground-based south-pole telescope observing the four southern faces:
from heal_swin_nnx import HealSwinParams
params = HealSwinParams(nside=256, in_channels=1, out_channels=1,
base_pixels=(8, 9, 10, 11)) # south polar cap
Inputs are the concatenation of the selected faces' NEST-ordered pixels. Shift strategies:
nest_roll— 1D roll on the NEST sequence (cheapest, coarsest).nest_grid_shift— the reference HEAL-SWIN hierarchical grid shift; face-seam windows that glue geometrically wrong edges are attention-masked. Its index math requires the deepest stage to hold a full window (bottlenecknside² ≥ window_size);HealSwinParamsrejects configs that bottleneck below that. The other three strategies handle a unit bottleneck.nest_grid_shift_exact— seam-exact variant: window content crosses face seams with the correct pixels and orientation wherever the two faces' local frames align (all polar-to-equatorial seams). Attention masking remains at the 8 pinch points, at the 90°-rotated south-south seams, and at coverage borders for partial-sky models.ring_shift— shift along HEALPix iso-latitude rings; exact on the full sphere.
Strategy cost
scripts/bench_strategies.py times each strategy two ways — the shift op in
isolation and a full HealSwin forward+backward step — so you can pick a
strategy on geometry, not guesswork:
uv run python scripts/bench_strategies.py # full sphere, nside 16 and 64
Numbers below are from one CPU run (jax 0.10.2, full sphere, window_size=4,
batch=2); treat them as ratios, not absolutes. fwd+bwd is the timed
forward+backward; build is the one-time construction cost, paid once when the
model is built and done host-side in NumPy/healpy.
Shift op alone (a gather forward + its scatter backward), channels=96:
| strategy | fwd+bwd n16 | fwd+bwd n64 | build n16 | build n64 |
|---|---|---|---|---|
nest_roll |
0.5 ms | 26.6 ms | 11 ms | 16 ms |
nest_grid_shift |
1.3 ms | 45.4 ms | 30 ms | 270 ms |
nest_grid_shift_exact |
1.4 ms | 45.9 ms | 788 ms | 19.1 s |
ring_shift |
1.4 ms | 46.3 ms | 7 ms | 128 ms |
Full model (embed_dim=48, depths=(2,2,2), num_heads=(2,4,8)):
| strategy | fwd+bwd n16 | fwd+bwd n64 | build n16 | build n64 |
|---|---|---|---|---|
nest_roll |
111 ms | 806 ms | 178 ms | 213 ms |
nest_grid_shift |
112 ms | 841 ms | 198 ms | 415 ms |
nest_grid_shift_exact |
113 ms | 819 ms | 562 ms | 9.7 s |
ring_shift |
128 ms | 815 ms | 183 ms | 347 ms |
Takeaways:
- Per-step compute barely depends on the strategy. In the full model all four land within ~4% at nside 64 and ~13% at nside 16 — the shift is a thin slice of a Swin block, dwarfed by attention and MLPs. Choose the strategy for geometric fidelity; it costs almost nothing at run time.
- The three index strategies are the same runtime op.
nest_grid_shift,nest_grid_shift_exactandring_shiftare each a singlejnp.takegather over a precomputed index buffer, so in isolation they time within ~2% of one another.nest_rollis a contiguousjnp.rolland runs ~1.7–2.5× cheaper on CPU (no scatter/gather) — a gap that mostly washes out once attention dominates. - The real divergence is one-time build cost.
nest_roll(just a mask) andring_shift(healpy round-trips) are cheap;nest_grid_shiftis cheap; butnest_grid_shift_exact's seam geometry is expensive and scales steeply withnside(~0.8 s at 16 → ~19 s at 64 per shifter). It is still paid only once at construction — negligible against a real training run, but noticeable when building many small models (tests, quick sweeps).
On GPU the run-time gaps shrink further (gather/scatter and roll are all cheap on-device); build cost is host-side and unchanged.
Tests
uv run pytest tests/ -q
Covers: ground-truth geometry checks against healpy adjacency
(test_topology.py, test_seam_geometry.py); permutation/round-trip
invariants for shifting and windowing (test_shifting.py,
test_windowing.py); RoPE property tests — coordinate-frame round-trips and
rotation-table invariants (test_rope.py); param validation and
serialization (test_params.py); buffer/param separation
(test_buffers.py); and JAX-native behavior — jit/eager equivalence, batch
independence, nnx.remat matching non-remat, standalone encoder, and all
HEALPix shift strategies (test_model.py).
Design docs
docs/superpowers/specs/2026-07-12-healswin-nnx-port-design.md— original port design spec (module surface, config shape, buffer strategy, shift-strategy semantics).docs/superpowers/plans/2026-07-12-healswin-nnx-port.md— the task-by-task implementation plan the port followed.docs/superpowers/specs/2026-07-12-config-cleanup-design.md— design spec for the config unification, cleanup, and RoPE work that followed.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file heal_swin_nnx-0.1.1.tar.gz.
File metadata
- Download URL: heal_swin_nnx-0.1.1.tar.gz
- Upload date:
- Size: 26.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
727609b95143d4f13055c96ecef73fb4d369446749da0e81418351c7e6e389c6
|
|
| MD5 |
a28d27276088feba5428cc3c1ec11171
|
|
| BLAKE2b-256 |
b2f45e457e1e2928872ee51e1874a1c360f8080ca8f95ccb0a785bc8c1343ce8
|
File details
Details for the file heal_swin_nnx-0.1.1-py3-none-any.whl.
File metadata
- Download URL: heal_swin_nnx-0.1.1-py3-none-any.whl
- Upload date:
- Size: 36.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac1fa08f34e77734b2e3b0edd6ac8c1ec5fd0c3b807b31057fe7d112d1f74c82
|
|
| MD5 |
061c6f709d22ff7723a387614bd97ed0
|
|
| BLAKE2b-256 |
55511c6e6aaedc794f1cd4d2612bfee7262a2740b410e043b1111cf92c5238a1
|