You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit d43e1ac
Browse filesBrowse the repository at this point in the historyBrowse files
perf(numba): FFT the mapper x linear-func block of the curvature matrix (#505)
The mapper x linear-func block of `F` was 70-85 % of F on every profiled cell
(0.953 s of 1.275 s at HST resolution) and did not scale with the source mesh,
only with image pixels. The cost was the dense sliding window inside
`curvature_matrix_off_diags_via_mapper_and_linear_func_curvature_vector_from`:
for every one of the 60 linear-func columns it expanded the noise-weighted
curvature weights onto the native grid and ran an `ny x nx x ky x kx` correlation
in numba.
That correlation is exactly a convolution with the PSF reversed along both axes,
so it now runs through the existing batched FFT convolver:
- `Convolver.reversed_kernel` (new, cached) is the same convolver with its kernel
reversed, reusing the preloaded `ConvolverState` geometry rebuilt for the
reversed kernel. Cached because a dataset's PSF outlives the `Inversion` that
is rebuilt for every likelihood evaluation, so the reversed kernel's FFT
geometry is built once per fit rather than once per evaluation.
- `InversionImagingSparseNumba._blurred_curvature_weights_from` correlates a
linear func's curvature weights through it, once per linear func rather than
once per (mapper, linear func) pair, with the weights zero outside the mask
(no blurring mapping matrix) exactly as the sliding window had them.
- `curvature_matrix_off_diags_via_mapper_and_blurred_curvature_weights_from`
(new) is the scatter half of the old kernel: the genuinely sparse, irregular
accumulation onto source pixels, which stays in numba.
The old dense kernel and `convolve_with_kernel_native` are kept, unused by the
inversion, as the reference the new path is asserted against in the tests.
The numpy convolution path is `scipy.signal.convolve(..., mode="same")`, whose
`(k - 1) // 2` "same" offset matches the kernel's `k // 2` centre for both odd
and even kernel widths, and which spawns no thread pool (the profiling campaign
runs one process per core).
Tests:
- `test_inversion_imaging_util.py` asserts the FFT block equals the dense kernel
(rel 1e-6) on a small masked grid, parametrized over the file's existing
asymmetric, non-square `KERNELS_ODD`; a control run without the reversal fails
on all four. It also asserts `reversed_kernel` is the reversed kernel and is
cached.
- `test_curvature_matrix_func_list_blocks.py` gains an inversion-level test of
`_curvature_matrix_mapper_func_blocks_from` against the dense kernel with an
asymmetric PSF, which also pins that the block's transpose is written (the
global mirror having been removed in the previous commit). A control run
without the reversal fails.
`pytest test_autoarray`: 1296 passed (1290 + 6 new).
Seconds per evaluation, `OMP_NUM_THREADS=1 AUTOARRAY_NUMBA_OPERATED_MEMO=0`,
n_repeats 10 (autolens_profiling breakdown cells):
| cell | eval | F | mapper x l-func |
|---------------------|-------------|-------------|-----------------|
| hst bilinear | 1.738 -> 0.819 | 1.275 -> 0.387 | 0.953 -> 0.0629 |
| euclid bilinear | 0.444 -> 0.273 | 0.284 -> 0.0889 | 0.198 -> 0.0224 |
| hst Delaunay-1250 | 1.455 -> 0.754 | 1.055 -> 0.241 | 0.899 -> 0.0612 |
| hst rectangular RTU | 8.501 -> 7.058 | 1.250 -> 0.335 | 0.929 -> 0.0630 |
i.e. 15x on the block, 3.3x on F and 2.1x on the whole HST evaluation. Pinned
log-likelihoods PASSED on all three pinned cells; F itself agrees with the
sliding-window result to 3e-18 relative, and the hst figure of merit moves from
27661.910133664103 to 27661.91013366411 (9e-18 relative, well inside the
harness rtol of 1e-4).
Step 2 of #505.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fr6iJ5T1RDARWfxttCuGkK
0 commit comments