Skip to content

feat(fluo): FISTA (non-negative) reconstruction for 3D fluorescence#563

Draft
talonchandler wants to merge 1 commit into
mainfrom
feature/fluor-fista
Draft

feat(fluo): FISTA (non-negative) reconstruction for 3D fluorescence#563
talonchandler wants to merge 1 commit into
mainfrom
feature/fluor-fista

Conversation

@talonchandler

Copy link
Copy Markdown
Collaborator

Summary

Adds reconstruction_algorithm: FISTA to 3D fluorescence reconstructions. FISTA solves

```
min 0.5 ||Hx - y||^2 + 0.5 lambda ||x||^2 s.t. x >= 0
```

via accelerated proximal gradient with a ReLU prox at every iteration, guaranteeing a non-negative reconstruction. Shares regularization_strength with the existing Tikhonov path.

Config example

```yaml
reconstruction_dimension: 3
input_channel_names: [GFP]
fluorescence:
transfer_function:
yx_pixel_size: 0.1
z_pixel_size: 0.25
wavelength_emission: 0.532
index_of_refraction_media: 1.3
numerical_aperture_detection: 1.2
apply_inverse:
reconstruction_algorithm: FISTA # NEW
regularization_strength: 5.0e-3 # shared L2 with Tikhonov
FISTA_max_iter: 100 # NEW
FISTA_rel_change_tol: 1.0e-3 # NEW
```

Full file at benchmarks/configs/fluor_3d_beads_fista.yml.

Motivation

Standard TLS / Tikhonov fluorescence reconstructions produce non-physical negative voxels (~50% in dynacell mantis A549 SEC61 ER and hummingbird A549 G3BP1 stress granule data) regardless of regularization choice. FISTA removes the negatives by construction at the cost of ~30-100x more wall time (still well under a minute per 100-iter, 512^2 lateral FOV on CPU).

Scope

  • Only 3D fluorescence (recon_dim=3). 2D fluorescence (singular-system path) explicitly raises NotImplementedError for FISTA for now.
  • Phase / birefringence settings untouched. The FISTA option lives on a new ApplyInverseSettings subclass in waveorder/api/fluorescence.py rather than the shared FourierApplyInverseSettings, so phase / birefringence schemas stay clean.

Changes

  • waveorder/api/fluorescence.py: new ApplyInverseSettings(FourierApplyInverseSettings) widens the algorithm Literal and adds FISTA_max_iter / FISTA_rel_change_tol. Apply-inverse dispatcher filters FISTA-only kwargs before calling the 2D entry-point and rejects 2D FISTA with a clear message.
  • waveorder/models/isotropic_fluorescent_thick_3d.py: FISTA branch with constant step size 1 / L, L = max(|OTF|^2) + lambda. Two FFTs per iteration (FFT(z), IFFT(residual_fft * conj(OTF))), early stop on ||x_{k+1} - x_k|| / ||x_k|| < FISTA_rel_change_tol.
  • benchmarks/configs/fluor_3d_beads_fista.yml: example config.

Tested

Smoke test on simulate(...) phantom in 3D: Tikhonov and FISTA both reconstruct the bead within a few counts of the true intensity; FISTA stays strictly non-negative. 2D FISTA correctly raises NotImplementedError.

```
phantom range: 0.0 1.0
data range: 10.07 10.55
Tikhonov out: min=9.57 max=10.90 frac<0=0.000
FISTA out: min=9.49 max=10.80 frac<0=0.000
OK: FISTA in 2D raised: FISTA reconstruction is currently only implemented for 3D fluorescence
```

Follow-ups (not in this PR)

  • 2D FISTA in isotropic_fluorescent_thin_3d.apply_inverse_transfer_function (different forward model — singular-system convolution).
  • Per-voxel Poisson-with-offset model for low-SNR data.

Test plan

  • Tikhonov path produces same results as before (regression).
  • FISTA on a simulated 3D phantom converges and stays non-negative.
  • 2D FISTA raises NotImplementedError.

Adds reconstruction_algorithm: FISTA as a third option (alongside
Tikhonov and TV) for 3D fluorescence reconstructions. FISTA solves

    min  0.5 ||Hx - y||^2 + 0.5 lambda ||x||^2    s.t.  x >= 0

via accelerated proximal gradient with a ReLU prox, guaranteeing a
non-negative reconstruction. Shares regularization_strength with
Tikhonov.

Why: TLS reconstructions on dynacell (mantis A549 SEC61, hummingbird
A549 G3BP1) produce ~50 percent non-physical negative voxels regardless
of regularization choice. FISTA removes the negatives at the cost of
extra iterations (~30-100x TLS wall time for ~100 iters).

Changes:
- waveorder/api/fluorescence.py: new ApplyInverseSettings subclass of
  FourierApplyInverseSettings widens the algorithm Literal to include
  FISTA and adds FISTA_max_iter / FISTA_rel_change_tol. 2D fluorescence
  raises NotImplementedError for FISTA (singular-system path doesn't
  yet support it).
- waveorder/models/isotropic_fluorescent_thick_3d.py: adds the FISTA
  branch with constant step size 1/L where L = max(|OTF|^2) + lambda.
  Same FFT pair count as Tikhonov per iteration; early-stop on
  relative change.

Example config: benchmarks/configs/fluor_3d_beads_fista.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant