perf(reg_split): compact the ConstantSplit split-stencil scatter (DelaunayNN 12x on A100) - #537
Merged
Conversation
…e-row supplement + NaN overflow guard (#536) The JAX path of `pixel_splitted_regularization_matrix_from` scattered the full padded `(4P, K, K)` outer product. For the natural-neighbor `DelaunayNN` mesh `K = 33` while the real occupied width is at most ~11, so ~97% of the 6.5M scattered entries were padding, at a cost quadratic in the padded width. It now scatters only the first `SPLIT_REG_COMPACT_WIDTH = 12` columns of every row and supplements the `SPLIT_REG_WIDE_ROW_BUDGET = 256` widest rows with the head x tail / tail x head / tail x tail blocks the compact pass did not cover, in one masked scatter. The result is exact: padded columns contribute mapping 0 / weight 0, so a row of size <= 12 is reproduced bit-for-bit by the compact pass alone, and wider rows are supplemented at full width rather than dropped. Beyond the budget the matrix is poisoned with NaN, matching the Sibson cap convention (NaN weights -> NaN likelihood -> the sample is discarded), instead of returning a silently truncated H. When `K <= compact_width` (the `Delaunay` mesh's `K = 4`, and the adapt-split family) the compaction is a no-op and the function performs today's single scatter with no supplement and no guard. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011xsh8KqgiHWTfPGgWEYMQw
This was referenced Sep 8, 2026
Collaborator
Author
|
Workspace PRs (merge after this one, library-first gate):
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The JAX path of
pixel_splitted_regularization_matrix_fromscattered the full(4P, K, K)outer product of the split stencil. For the natural-neighbourDelaunayNNmesh the stencil tables are padded toK = 33(
SIBSON_MAX_NEIGHBORS32 + 1 self column) while the real occupied width on aproduction HST cell is min 1 / median 5 / p99 9 / max 11 — so ~97% of the 6.5M
scattered entries were padding, at a cost quadratic in the padded width. On the
A100 this single scatter was the largest remaining block of the DelaunayNN
params -> Hprefix.This PR scatters only the first
kc = min(K, 12)columns and supplements the256 widest rows with the blocks the compact pass did not cover. The result is
exact, not approximate: padded columns carry mapping
0/ weight0, so arow whose occupied size is
<= kcis reproduced bit-for-bit by the compact passalone, and the wide rows get the head x tail, tail x head and tail x tail blocks
back in one masked
.at[].add.K <= 12callers (theDelaunaymesh'sK = 4,and the adapt-split family) take today's single scatter unchanged, with no
supplement and no guard.
Design
SPLIT_REG_COMPACT_WIDTH = 12. Width waschosen from the measured cost curve, not guessed — see the width sweep below.
SPLIT_REG_WIDE_ROW_BUDGET = 256. Rows areselected by
jax.lax.top_kon the integersplitted_sizes, which is notdifferentiated through, so the weights stay fully differentiable. The
supplement costs
W * (K**2 - kc**2)~ 0.24M entries, an order of magnitudebelow the 6.5M it replaces.
kcthan the budget holds, thematrix is poisoned with NaN rather than silently truncated. This is the same
convention the Sibson natural-neighbour caps already use
(
mesh/interpolator/sibson.py:neighbor_overflow/failedset theinterpolation weights to NaN) — the likelihood evaluates to NaN and the sample
is discarded by the sampler, never returning a silently wrong
H.ensemble geometries (4800 split rows each) sees a max of 50 rows wider than 12
and a mean of 2.8 — a ~5x margin to the 256 budget. The widest single stencil
in that ensemble is 21 natural neighbours (99.9th pct 11, 99.99th pct 15).
A100 A/B (jobs 342334-342338, same node, same window)
params -> Hprefix, vmap 16 (ms/call)params -> Hprefix, unbatched (ms)Numerics: the pinned likelihood
29144.581944is bit-identical on both legsand
pinned_drift: []. The pre-registered witness (assembly < 3 ms,params -> H< 11 ms) is met with margin.Why width 12, and why not the alternatives
Investigation jobs 342331/342332 priced every candidate on the same real HST
tables before the design was fixed:
Compact-width sweep (vmap 16, real HST tables):
Width 12 is 17x on GPU and 5.8x on CPU over the uncompacted scatter, so no
backend gate is needed.
API Changes
No breaking changes.
pixel_splitted_regularization_matrix_fromgains twooptional keyword arguments,
compact_widthandwide_row_budget, defaulting tothe new module constants
SPLIT_REG_COMPACT_WIDTH = 12andSPLIT_REG_WIDE_ROW_BUDGET = 256; both are ignored on the NumPy path. Everyexisting call site is unchanged.
One new behaviour on the JAX path: a geometry with more than 256 split rows
wider than 12 columns now yields a NaN regularization matrix (hence a NaN
likelihood, discarded by the sampler) instead of a silently narrower one. This
is the existing Sibson cap convention and is never reached on the audited
ensemble (max 50 wide rows of a 256 budget). The NumPy path is unchanged.
See full details below.
Test Plan
pytest test_autoarray/inversion -q— 507 passedpytest test_autoarray— 1468 passedtest_autoarray/inversion/regularizations/test_pixel_splitted_jax.py(8 tests): compact-vs-full parity on padded tables,
K <= kcno-op path,wide-row supplement exactness, NaN-on-overflow, NumPy/JAX agreement.
autolens_workspace_testscripts/misc/jax_assertions/delaunay_nn.pycompaction parity section — PASS.
scripts/misc/jax_assertions/delaunay_nn_caps.pyover 101ensemble geometries: max 50 / mean 2.8 wide rows of 4800, budget 256.
pinned_drift: [].scripts/imaging/jax_grad/delaunay.pyandscripts/imaging/jax_likelihood/delaunay.py(bothreg.AdaptSpliton theJAX path, i.e. the changed function) run clean on this branch.
Links
autolens_profiling/results/notes/delaunay_nn_constant_split_assembly.mdFull API Changes (for automation & release notes)
Added
autoarray.inversion.regularization.regularization_util.SPLIT_REG_COMPACT_WIDTH— module constant,12; the number of stencil columns scattered for every row on the JAX path.autoarray.inversion.regularization.regularization_util.SPLIT_REG_WIDE_ROW_BUDGET— module constant,256; the number of widest rows given a full-width supplementary scatter on the JAX path.Changed Signature
regularization_util.pixel_splitted_regularization_matrix_from(regularization_weights, splitted_mappings, splitted_sizes, splitted_weights, xp=np, compact_width=SPLIT_REG_COMPACT_WIDTH, wide_row_budget=SPLIT_REG_WIDE_ROW_BUDGET)— two new optional keyword arguments; no existing argument added, removed, renamed or re-defaulted.Changed Behaviour
regularization_util.pixel_splitted_regularization_matrix_from(JAX path only) — the(4P, K, K)scatter is replaced by a compact(4P, kc, kc)scatter plus a top-wide_row_budgetfull-width supplement. Output is bit-identical for every geometry within budget. On overflow (more thanwide_row_budgetrows wider thancompact_width) the returned matrix is NaN, following themesh/interpolator/sibson.pycap convention, rather than silently truncated.K <= compact_widthcallers (Delaunaymesh,K = 4) are unaffected. The NumPy path (pixel_splitted_regularization_matrix_np_from) is unchanged.Migration
Generated by the PyAutoLabs agent workflow.
🤖 Generated with Claude Code
https://claude.ai/code/session_011xsh8KqgiHWTfPGgWEYMQw