Overview
Phase 2 of the multi-start gradient v2 promotion (autolens_workspace_developer#101). Builds on Phase 1 (PyAutoFit#1398, merged) — the per-start jax.vmaped optimizer state. Adds restart-on-death (resurrection) to af.AbstractMultiStartGradient: each step, any start whose objective went non-finite is redrawn fresh (params from the start band + its per-start optimizer state reinitialised), leaving alive starts untouched. On likelihoods with hard non-finite regions (pixelized sources) every trajectory dies within ~25–50 steps and apply_if_finite alone latches the start at the cliff edge; resurrection keeps the population alive and converts the pixelized landscape from unsearchable to searchable (adam −51201 → +1718 over 3000 steps, job 330598).
Plan
- Add a
resurrect: bool = False search knob (default off → existing MGE-cell behaviour and results are byte-for-byte unchanged; resurrection is only load-bearing on inversion-heavy landscapes).
- In the fit loop, after computing per-start objectives: if
resurrect and any start is non-finite, redraw those starts' params from (start_lower_limit, start_upper_limit) and reinit their vmapped optimizer state, merging into the alive population via a boolean mask (jnp.where over the state pytree).
- Track a
n_resurrections diagnostic through search_internal (resume-safe) and samples_info.
- Honest caveat in docstring/PR: even with resurrection Nautilus still wins the pixelized cell decisively; this makes gradient MAP viable there, not competitive.
Detailed implementation plan
Affected Repositories
- PyAutoFit (primary)
- autofit_workspace_test (JAX validation, follow-on)
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./PyAutoFit |
main (Phase 1 merged) |
clean |
Suggested branch: feature/multistart-resurrection
Implementation Steps
autofit/non_linear/search/mle/multi_start_gradient/search.py — add resurrect: bool = False constructor arg (store + docstring).
- Add
_reinit_dead_starts(self, params, opt_state, dead_idx, model, optimizer, jax, jnp, rng): copy params into a writable np.array (jax arrays are read-only), redraw dead rows from the start band via model.vector_from_unit_vector, jax.vmap(optimizer.init) fresh state, merge dead rows via a jnp.where mask over the vmapped state pytree (jax.tree.map). Mask size = params.shape[0] (broad-start collection may yield < n_starts).
_fit loop: compute alive = np.isfinite(foms); select best from alive-only (unchanged); if self.resurrect and not alive.all(), reinit dead starts (grads for dead rows are the old non-finite ones — apply_if_finite on the fresh per-start state zeroes them for one step, so redrawn params wait one step, matching the reference). Initialise resurrect_rng and n_resurrections on both the fresh and resume paths.
- Persist
n_resurrections in search_internal and surface resurrect + n_resurrections in samples_info.
- Unit tests (numpy-only):
resurrect default False + dict round-trip; _reinit_dead_starts mask logic on plain numpy arrays.
autofit_workspace_test — extend/adds a JAX validation exercising resurrect=True on a landscape with non-finite regions (or assert the knob is inert when off).
Key Files
autofit/non_linear/search/mle/multi_start_gradient/search.py
test_autofit/non_linear/search/mle/test_multi_start_gradient.py
- Reference (read-only):
autolens_workspace_developer/searches_minimal/pix_lr_free.py (PIX_RESURRECT, reinit_starts), lr_free_findings.md (Phase 2).
Original Prompt
Click to expand starting prompt
(draft/feature/autofit/multistart_resurrection_restart_on_death.md — the Phase-2 prompt, filed at split time.)
Generated by the PyAutoLabs agent workflow.
Overview
Phase 2 of the multi-start gradient v2 promotion (autolens_workspace_developer#101). Builds on Phase 1 (PyAutoFit#1398, merged) — the per-start
jax.vmaped optimizer state. Adds restart-on-death (resurrection) toaf.AbstractMultiStartGradient: each step, any start whose objective went non-finite is redrawn fresh (params from the start band + its per-start optimizer state reinitialised), leaving alive starts untouched. On likelihoods with hard non-finite regions (pixelized sources) every trajectory dies within ~25–50 steps andapply_if_finitealone latches the start at the cliff edge; resurrection keeps the population alive and converts the pixelized landscape from unsearchable to searchable (adam −51201 → +1718 over 3000 steps, job 330598).Plan
resurrect: bool = Falsesearch knob (default off → existing MGE-cell behaviour and results are byte-for-byte unchanged; resurrection is only load-bearing on inversion-heavy landscapes).resurrectand any start is non-finite, redraw those starts' params from(start_lower_limit, start_upper_limit)and reinit their vmapped optimizer state, merging into the alive population via a boolean mask (jnp.whereover the state pytree).n_resurrectionsdiagnostic throughsearch_internal(resume-safe) andsamples_info.Detailed implementation plan
Affected Repositories
Branch Survey
Suggested branch:
feature/multistart-resurrectionImplementation Steps
autofit/non_linear/search/mle/multi_start_gradient/search.py— addresurrect: bool = Falseconstructor arg (store + docstring)._reinit_dead_starts(self, params, opt_state, dead_idx, model, optimizer, jax, jnp, rng): copy params into a writablenp.array(jax arrays are read-only), redraw dead rows from the start band viamodel.vector_from_unit_vector,jax.vmap(optimizer.init)fresh state, merge dead rows via ajnp.wheremask over the vmapped state pytree (jax.tree.map). Mask size =params.shape[0](broad-start collection may yield <n_starts)._fitloop: computealive = np.isfinite(foms); select best from alive-only (unchanged); ifself.resurrect and not alive.all(), reinit dead starts (grads for dead rows are the old non-finite ones —apply_if_finiteon the fresh per-start state zeroes them for one step, so redrawn params wait one step, matching the reference). Initialiseresurrect_rngandn_resurrectionson both the fresh and resume paths.n_resurrectionsinsearch_internaland surfaceresurrect+n_resurrectionsinsamples_info.resurrectdefault False + dict round-trip;_reinit_dead_startsmask logic on plain numpy arrays.autofit_workspace_test— extend/adds a JAX validation exercisingresurrect=Trueon a landscape with non-finite regions (or assert the knob is inert when off).Key Files
autofit/non_linear/search/mle/multi_start_gradient/search.pytest_autofit/non_linear/search/mle/test_multi_start_gradient.pyautolens_workspace_developer/searches_minimal/pix_lr_free.py(PIX_RESURRECT,reinit_starts),lr_free_findings.md(Phase 2).Original Prompt
Click to expand starting prompt
(draft/feature/autofit/multistart_resurrection_restart_on_death.md — the Phase-2 prompt, filed at split time.)
Generated by the PyAutoLabs agent workflow.