Geometry is the prior: adaptive representations for physics-faithful inversion¶
nefi solves inverse problems by optimizing a field — a parameterization \(x = f_\theta\) of the
unknown — through a hard, differentiable forward operator \(F\). This page is about the first half of
that sentence. Its thesis, distilled from the two papers nefi generalizes, is simple:
The representation is the geometric prior. Choosing how the unknown is parameterized decides which image-space updates gradient descent can make, how fast each spatial frequency converges, and what the reconstruction can and cannot contain. Each physical system therefore calls for a representation whose geometry matches the unknown and whose spectral filter matches the operator's decay — and when we do not know which, the measurement itself can tell us.
The code lives in two packages:
nefi.fields.geometric— a family of representations: composite (background ⊕ anomaly), layered (stratified media), explicit shapes, coordinate warps, Fourier bases and Fourier-domain preconditioning;nefi.fields.adaptive— the adaptivity: residual- and operator-driven annealing, capacity growth, measurement-driven model selection, and a spectral match report that explains, in words, whether a representation fits a system.
1. What the two papers teach¶
| NeTMY (NV relaxometry, arXiv 2605.13988) | NeFTY (thermal tomography, arXiv 2603.11045) | |
|---|---|---|
| unknown | sparse spin sources \(\rho \ge 0\) (2-D) | piecewise-constant defects in a (layered) bulk, \(\alpha \in [\alpha_{\min}, \alpha_{\max}]\) (3-D) |
| operator decay | \(\lvert\widehat{G_{az}}\rvert^2 \le C (1+k)^m e^{-k z_0}\) (Lemma 1) | \(\sigma_n \lesssim n^{-1/3}\) (Prop. 2), noise amplified by \(1/\sigma_n\) (Cor. 1) |
| representation | coordinate MLP, gated softplus head (Eq. 5), annealed Fourier features, multiscale | coordinate MLP, bounded sigmoid head (Eq. 6), annealed Fourier features |
| explicit prior | \(\ell_1\) + anisotropic TV (Eq. 3) | isotropic TV (Eq. 22) |
| failure analysed | free-density solvers center-collapse (P2)+(P3), §5.3 | grids ring at interfaces, PINNs collapse; spurious back-face artifacts for shallow defects (App. G.7) |
Both papers use one representation each and tune it to one geometry: the gate lets NeTMY drive the background to zero so that points can emerge; the sigmoid bracket plus TV lets NeFTY carve piecewise-constant regions. Neither paper represents what is actually known about its scenes — that NeFTY's bulk is stratified (App. E.1: three to four strata along \(z\)), that defects are compact bodies with smooth boundaries, that sensitivity decays with depth (App. B.4) — except through a generic MLP plus penalties. That gap is what this package fills.
2. The filtering view¶
Lemma 2 (NeTMY, App. D.6). A first-order step \(\theta \leftarrow \theta - \eta \nabla_\theta L(f_\theta)\) realizes, to leading order, the image-space update
\(G_\theta\) is positive semidefinite and projects every update onto the span of the Jacobian columns \(\psi_p = \partial f_\theta / \partial \theta_p\): \((G_\theta g)(r) = \sum_p \psi_p(r)\langle \psi_p, g\rangle\) (Eq. 34), with \(\operatorname{rank} G_\theta \le \min(|\Omega|, P)\) (Eq. 35). The representation filters the raw gradient:
| representation | \(G_\theta\) | consequence |
|---|---|---|
free grid (GridField) |
\(I\) | executes \(\nabla_x L\) verbatim — center bias (P2), noise at all frequencies |
| MLP + annealed Fourier features | smooth kernel, band \(B_\beta \sim 2^{k_\beta}\pi\) (Eq. 37) | low-pass early, richer later |
Fourier basis (FourierBasisField) |
\(\Phi\Phi^\top\), an ideal projector | hard bandwidth, no noise above the cutoff |
| Gaussian splats | rank \(\le K(2d + C)\), localized | moves primitives, cannot fill dense regions |
| composite \(x = c(f_1,\dots,f_n)\) | \(\sum_i D_i G_i D_i^\top\), \(D_i = \partial c/\partial f_i\) | each component contributes its own filter |
| warp \(x(u) = f(\varphi(u))\) | \(G_f(\varphi(u), \varphi(u'))\) | local bandwidth \(B\,\lvert\varphi'(u)\rvert\): stretch where you need detail |
| spectral preconditioner \(x = P f_\theta\) | \(P\, G_\theta P^\top\) | reshapes the per-frequency step (below) |
| shapes / layers / level sets | columns concentrated on interfaces | moves boundaries, not pixels |
Per-frequency dynamics. Linearize the data term around the solution of a translation-invariant problem with operator transfer \(a(\nu)\) (amplitude sensitivity \(\sigma_F(\nu) = |a(\nu)|\)) and representation transfer \(g(\nu)\). The error at frequency \(\nu\) evolves as
Two things decide whether a representation fits a system:
- Band. The data constrain frequency \(\nu\) only if the signal it carries exceeds the noise, \(\sigma_F(\nu)\,|\hat x(\nu)| \gtrsim \sigma_\varepsilon\) (a Picard condition; NeFTY Cor. 1 is its negative: above that band the pseudo-inverse amplifies noise by \(1/\sigma_n\)). A representation whose pass band is narrower than the resolvable band is over-bandlimited (it cannot express what the data resolve); one whose pass band is wider is under-bandlimited (it moves unconstrained frequencies and fits noise unless something — annealing, TV, early stopping — stops it).
- Conditioning. Within the resolvable band, the spread of \(g\,\sigma_F^2\) sets how uniformly detail converges. A grid inherits the operator's decay (\(g \equiv 1\)); an MLP adds its spectral bias (implicit regularization, slower fine detail); a spectral preconditioner with \(g \approx 1/\max(\sigma_F, \text{floor})\) flattens it (a floored Gauss–Newton step).
nefi.fields.adaptive.match_report(field, problem) measures both — \(g\) from rows \(G_\theta e_i\)
(a vjp then a jvp through the field, Fourier-transformed and radially averaged over random
pixels), \(\sigma_F\) from rows \(J^\top J e_i\) — and states the verdict in words (§5).
3. Decision guide¶
Frequencies are in cycles per unit normalized coordinate (each axis spans \([-1,1]\); a grid of
\(n\) cells has Nyquist \(n/4\)). Instance names refer to nefi.instances.
| geometry of the unknown | representation | annealing / curriculum | regularizers | example instances |
|---|---|---|---|---|
| sparse point-like sources | NeuralField + GatedSoftplus (NeTMY) — or AnomalyField(FourierBasisField, gated NeuralField, mode="add") when a smooth background is present |
annealed Fourier features, multiscale (NeTMY Tab. 6); ResidualDrivenAnnealing for unknown difficulty |
\(\ell_1\) + anisotropic TV | nv_relaxometry, poisson_source, deconvolution (sparse scenes) |
| piecewise-constant defects in a homogeneous bulk | NeuralField + Bounded (NeFTY), or AnomalyField(constant background, level set / StarShapeField, mode="blend", inclusion_bounds=...) |
frequency annealing over the first 25 % (NeFTY Tab. 5); level-set sharpening via progress | isotropic TV; ContourRegularizer (perimeter) |
thermal_tomography (homogeneous), eit, sparse_view_ct |
| stratified media ⊕ defects (laminates, geology) | LayerCakeField = LayeredField ⊕ gated anomaly (mode="add", contrast=-1); mode="blend" with a StarShapeField anomaly for compact voids |
progress_map={"background": ("fast", 0.5), "anomaly": ("delay", 0.1)} — layers first, defects second |
small TV; render="area" gives sub-voxel interfaces |
thermal_tomography (layered), wave_fwi, darcy_flow |
| few compact inclusions with smooth boundaries | StarShapeField (2-D, or 3-D extruded) / PolygonField; capacity pool + GrowCapacity when the count is unknown |
sharpness \(\varepsilon\)(progress) geometric decay | ContourRegularizer(perimeter, smoothness) |
eit, diffraction_tomography, holography |
| smooth background + localized anomaly | AnomalyField(FourierBasisField, gated NeuralField, support=...) with a sensitivity-based support prior |
background "full", anomaly delayed; GrowCapacity on the Fourier shells |
TV / \(\ell_1\) on the anomaly | current_density, reaction_diffusion, poisson_source |
| sensitivity decaying with depth (surface data of volumes) | WarpedField(inner, log_depth(...)), depth_stretch(γ<1) or sensitivity_warp(sensitivity_map(problem)) |
OperatorAwareAnnealing with operator_spectrum |
depth-aware TV weight | thermal_tomography (App. G.7 failure mode), nv_relaxometry (standoff \(z_0\)) |
| radial / axisymmetric systems | WarpedField(inner, polar(embed="circle")) / cylindrical(...) (inner field takes ndim + 1 inputs) |
as for the inner field | — | diffraction_tomography, holography |
| deformations of a known template | DeformableField(template) (identity-initialized displacement) |
freeze the template: Stage(freeze=("inner.",)) |
WarpRegularizer(smoothness, folding) |
registration-type problems |
| broadband / textured fields | NeuralField at full progress, GridField + Tikhonov/TV, SpectralPreconditionedField to equalize convergence |
OperatorAwareAnnealing to cap the band at the noise level |
Tikhonov / TV | deconvolution, wave_fwi (smooth velocity models) |
| known operator spectrum, slow convergence | SpectralPreconditionedField.from_operator(inner, op, domain, floor=...) |
pick the floor from match_report (\(\nu_{\text{data}}\)) |
as for the inner field | deconvolution, sparse_view_ct |
When in doubt: build two or three candidates and let select_representation decide (§4.3).
Binary and level-set representations after the fact. The two-phase rows of this table can
also be applied to a finished reconstruction: nefi.solve.refine.refine_edges (or
inst.refine(result, measurement)) swaps the representation of one field for a multi-phase level
set (LevelSetHead generalized to k nested phases over one φ, with cell-averaged Heavisides for
sub-voxel interfaces and optional free phases whose interiors stay smooth), a Cahn–Hilliard
double-well or a binarizing Binary-prior head swap, initializes it from the smooth field and runs
a short second stage under the same operator and data. Its report puts the data fit before and
after next to IoU / Edge-F1, refuses refinements the data do not support, and comes with a
continue control (the same budget without a prior) to separate the prior's gain from mere extra
optimization. See Edge refinement for the numbers on the 3-D instances.
Learning rates of geometric parameters. Geometric representations mix a few physical scalars
(layer values and thicknesses, shape centers and radii, inclusion values) with network weights;
the two often want different step sizes. OptimConfig(lr_mult={prefix: factor}) builds optimizer
parameter groups by qualified name (field.<name> / operator.<name>, longest prefix wins), and
every stage's schedule is scaled per group. Useful prefixes:
| field | parameter prefixes (inside a problem) |
|---|---|
LayeredField |
field.thickness_logit, field.layer_values, field.interface_model., field.value_model. |
LayerCakeField / AnomalyField |
field.background. (the layered medium), field.anomaly., field.inclusion, field.contrast |
StarShapeField |
field.center, field.radius_raw, field.coef (Fourier descriptors), field.inside, field.outside, field.depth_center, field.half_height_raw |
PolygonField |
field.vertices, field.inside, field.outside |
FourierBasisField |
field.coef |
Treat the factors as hyperparameters (and compare them with select_representation): on the
example of §5, a uniform learning rate of 4·10⁻² for the whole LayerCakeField (30.9 dB) beat a
10⁻² network rate with 4–8× on field.background. (26–29 dB), because the gated anomaly network
also benefits from the larger step.
4. The adaptive tools¶
4.1 Annealing that listens to the data¶
The papers anneal on a clock: \(\beta = K\,t/T\) per stage (NeTMY Eq. 27) or over the first
\(T_{FA}\) steps (NeFTY Eq. 21). nefi.fields.adaptive offers three alternatives; all drive
solver.progress_override (composite fields map the global progress per component).
ResidualDrivenAnnealing(patience, delta)— earn your frequencies. Opens the next band only when the data loss plateaus: the windowed improvement overpatiencesteps falls below \(\max(\delta, \text{rate\_fraction}\cdot\text{peak})\), where peak is the best windowed improvement at the current level (diminishing returns — scale-free, because a tanh MLP with few open bands keeps improving slowly forever). It never opens a band once \(\text{RMSE} \le \tau\sigma\) (Morozov's discrepancy principle at the stage resolution;stop_at_noise=Trueends the stage there), and ramps each new band in overramp_stepswith plateau detection paused — switching a band on abruptly feeds the untrained first-layer weights of its features and injects a random high-frequency perturbation, the shock the cosine gate of NeTMY App. D.2 exists to avoid (an integer staircase of levels loses ~6 dB against the smooth clock ontoy1d).max_steps_per_leveladds a clock for fixed budgets.OperatorAwareAnnealing(sensitivity_spectrum, noise_level)— opens frequency \(\nu\) only when \(\sigma_F(\nu)\,|\hat x(\nu)| \ge \text{margin}\cdot\sigma_\varepsilon\): the current field's radial spectrum (Hann-windowed) is extrapolated above the open band by a power law, multiplied by the operator sensitivity (aSpectrumfromoperator_spectrumor any 1-D radial profile), and compared with the per-mode noise (scaled to coarse stages).signal="data"instead fixes the cutoff from the measurement spectrum (a data-driven Picard rule).BandwidthSchedule([(t, B), ...])— prescribe the open bandwidth in physical terms;bandwidth_to_progress/progress_to_bandwidthconvert for any annealedFourierFeaturesencoding orFourierBasisField.
Illustrative single-seed numbers on toy1d (64 points, blur σ = 0.02, 1 % noise):
| schedule | budget | PSNR [dB] (bumps / mixed / spikes) | note |
|---|---|---|---|
| fixed clock (β over the whole stage) | 2000 steps | 32.4 / 27.2 / 21.5 | |
ResidualDrivenAnnealing(patience=25, ramp_steps=50, rate_fraction=0.25) |
2000 steps | 37.1 / 28.0 / 20.5 | ends at progress 0.5 on bumps |
… with stop_at_noise=True |
stops at 711 / 676 / 2000 | 37.7 / 27.9 / 20.5 | 2.8× fewer steps |
| fixed clock | 400 steps | 21.7 (bumps) | |
OperatorAwareAnnealing(signal="field" / "data") |
400 steps | 25.2 / 26.2 (bumps) | target band ≈ 5–6 cycles/unit |
Holding each level fixed for 300 steps on the same data shows why: levels 3–4 (≈ 4–8 cycles/unit, where the data spectrum meets the noise floor) reach the noise level with the best PSNR (38.5 dB); opening all six bands overfits (34.5 dB). The operator-aware target (≈ 5 cycles/unit) lands in that window.
4.2 Capacity growth¶
Representations with a capacity pool implement can_grow() / grow(hint):
FourierBasisField opens the next shell of modes, LayeredField activates the next layer (the new
layer inherits its neighbour's value, so the field is unchanged at the moment of growth),
StarShapeField / PolygonField activate the next pooled shape — placed at the extremum of the
field-space data gradient \(\Delta v\cdot\partial L/\partial x\) (a topological-derivative
heuristic). All pooled parameters exist from the start, so the optimizer the solver builds at
stage start already owns them. GrowCapacity performs, on each plateau, the next action of its
order (grow a module, open an annealing band) — the representation-level analogue of early
stopping: stay in a small, well-conditioned subspace until the data demand more — and, like the
annealing ladder, adds nothing once the residual is at the noise floor (\(\text{RMSE} \le
\tau\sigma\)). On a blurred two-disk scene (48², 1 % noise) a pool of three star shapes starting
empty gives births at steps 15 and 49, each placed on one of the disks by the gradient hint, and
reaches IoU 0.99.
4.3 Let the measurement choose: select_representation¶
There is no training set, but the measurement has many entries and a physics-faithful forward
model predicts every entry. Hold out a random subset (via Measurement.mask), fit each candidate
on the rest (short budgets suffice to rank), and score the forward prediction on the held-out
entries:
from nefi.fields.adaptive import select_representation, RepresentationEnsemble
report = select_representation(
lambda field: InverseProblem(domain, field, operator, losses, measurement),
{"neural": make_neural, "layer_cake": make_layer_cake, "grid": make_grid},
holdout=0.1, seed=0, budget_scale=0.2,
curricula={"grid": grid_curriculum}, # per-candidate learning rates
)
print(report.table()) # ranked: val MSE, train MSE, val/σ², time
ensemble = RepresentationEnsemble.from_report(report) # softmax(−(s − s_min)/s_min) weights
The held-out error estimates the prediction risk \(\mathbb E\lVert F(\hat x) - F(x^\star)\rVert^2 +
\sigma^2\): under-regularized representations (free grids, all bands open) fit noise and predict
held-out entries poorly; over-regularized ones cannot express the unknown. With a known noise
level the report also shows \(\text{val MSE}/\sigma^2\) — ≈ 1 means the representation predicts
unseen data to the noise floor. Coarse curriculum stages average only observed training
entries (fractional mask weights), so held-out values never leak into the fit; group_axes
holds out whole sensor pixels across frames; n_folds=k gives k-fold CV. Candidates that fail are
reported with score ∞ instead of aborting the selection.
RepresentationEnsemble averages fitted candidates with weights from their held-out losses
(relative temperature by default: a candidate with twice the best loss gets \(e^{-1}\) of its
weight) and its spread() is a cheap model-uncertainty map.
5. The match report in practice¶
examples/geometric_representations.py builds a 2-D defect in a two-layer medium (top 1.0 over
an undulating interface, bottom 0.55, elliptical defect 0.1; Gaussian blur of ≈ 1.7 cells, 2 %
noise, data simulated on a 2× finer grid). All four candidates get 600 steps (two-stage
multiscale) and the same losses (MSE + isotropic TV \(2\cdot10^{-4}\)):
| representation | params | PSNR [dB] | defect IoU | match verdict | \(\nu_{\text{rep}}\) | \(\nu_{\text{data}}\) | held-out val/σ² |
|---|---|---|---|---|---|---|---|
NeuralField (6 octaves) |
11 777 | 29.2 | 0.93 | over-bandlimited | 1.05 | 4.77 | 2.37 |
GridField + TV |
2 304 | 31.0 | 0.97 | under-bandlimited | 11.3 | 4.77 | 1.15 |
LayerCakeField (layers ⊕ gated anomaly) |
2 926 | 30.9 | 0.96 | matched | 4.41 | 4.77 | 1.01 |
CompositeField (Fourier background ⊕ level-set blend) |
2 946 | 27.0 | 0.72 | over-bandlimited | 1.95 | 4.77 | 1.88 |
The layered representation is the only one whose update-kernel pass band matches what the data resolve; it recovers the physical parameters (layer values 1.04 / 0.552 vs 1.0 / 0.55, mean interface depth 0.449 vs 0.450) with 2 926 parameters, and held-out cross-validation picks it — predicting unseen entries at the noise floor. Total-variation-regularized pixels are a strong baseline for piecewise-constant images under mild blur (the match report flags the grid as under-bandlimited, and TV is what keeps it in check); the Fourier background cannot hold the sharp layer boundary (over-bandlimited) and pushes the error into the defect indicator. A typical report reads:
Representation vs. operator at the noise level (LayerCakeField, progress=1.00, grid 48×48, 6 probes):
- the data resolve frequencies up to ν_data ≈ 4.77 cycles/unit [data spectrum vs noise floor ...]
- the representation passes frequencies up to ν_rep ≈ 4.41 cycles/unit (90% of a white gradient's
realized update energy through G_θ = J_θ J_θᵀ lies below it; NeTMY Lemma 2).
- verdict: MATCHED (ν_rep/ν_data = 0.92): the pass band of G_θ coincides with the data-resolvable band.
- conditioning on the resolvable band: κ(g·σ_F²) = 1.11e+03 vs κ(σ_F²) = 50.6 for a free grid ...
Definitions used by the report: \(\nu_{\text{rep}}\) is the radius holding 90 % of the energy of \(G_\theta\) applied to a white gradient (the DC ring is excluded — a bias parameter adds an \(N\)-fold constant column); \(\nu_{\text{data}}\) is where the Hann-windowed data power spectrum falls to \((1+\text{margin})\sigma^2\) after half-octave smoothing (when the measurement lives on the field grid), or the band where \(\sigma_F^2 |\hat x|^2 \ge \text{margin}\cdot\sigma^2\) under a power-law prior otherwise. Sanity checks in the test-suite: a grid's transfer is exactly 1; a 6-mode Fourier basis concentrates its energy below its \(\sqrt2\cdot 5/4\) corner frequency; the measured \(\sigma_F\) of a Gaussian blur matches \(e^{-2\pi^2\sigma^2\nu^2}\) to ~1 %.
6. Writing a new geometric representation¶
A representation is a Field: it maps normalized coordinates to raw channels, and Heads turn
those into named physical fields. About fifteen lines are enough:
import torch
from torch import nn
from nefi.fields import Field, Heads
from nefi.registry import register
@register("field", "slab")
class SlabField(Field):
"""A slab of value v_in between two learnable depths, v_out elsewhere (depth axis -1)."""
def __init__(self, heads=None, top=-0.3, bottom=0.3, eps_start=0.2, eps_end=0.01):
super().__init__(heads or Heads({"x": "identity"}))
self.z = nn.Parameter(torch.tensor([top, bottom]))
self.v = nn.Parameter(torch.tensor([0.0, 1.0])) # outside, inside (raw)
self.eps = lambda p: eps_start * (eps_end / eps_start) ** p
def raw(self, coords, progress=1.0): # (*shape, ndim) -> (*shape, n_in)
u, e = coords[..., -1], self.eps(progress)
chi = torch.sigmoid((u - self.z[0]) / e) * torch.sigmoid((self.z[1] - u) / e)
return (self.v[0] + (self.v[1] - self.v[0]) * chi).unsqueeze(-1)
The contract and the conventions that make a representation a good citizen:
raw(coords, progress)returns(*coords.shape[:-1], heads.n_in)for any point set (take a fast path on tensor-product grids —nefi.fields.geometric.interp_grid,grid_axes); coordinates are cell-centered in \([-1,1]\).progress ∈ [0, 1]is the continuation parameter: open bands, sharpen interfaces (anneal_value,smooth_step), and give progress 1 its final meaning — the solver evaluates the result at the last progress used.on_stage_start(stage, domain)— resample grids, propagate to children.reset_parameters()— restore the initial state (multi-restart); composites must delegate to their children explicitly (the default skips sub-Fields).- Parameters exist from the start. The solver builds its optimizer at stage start; to grow,
keep a pool and unmask it (
can_grow()/grow(hint)), ideally without changing the field. - Stay forward-differentiable. Diagnostics and
match_reportcompute \(G_\theta e_i\) withtorch.func.vjp+jvp; avoid ops without forward-mode rules (e.g.grid_sample— useinterp_grid), and never name a method_apply(it isnn.Module's device-move hook). - Check the filter.
representation_spectrum(field, domain)andmatch_report(field, problem)tell you, before any benchmark, what your parameterization will do to the gradient.
7. Limitations and open questions¶
- Shapes are star-shaped (2-D Fourier descriptors, 3-D by extrusion); topology changes (merging, holes), spherical-harmonic 3-D shapes and a principled death step are not implemented — the capacity pool only grows.
LayeredFieldinterfaces are single-valued height functions over the lateral coordinates (no overturned folds or pinch-outs below zero thickness; thicknesses are strictly positive).- A free-form neural indicator in
mode="blend"can swap roles with the layers; prefer compact shape anomalies there, or an additive gated anomaly. - The match report assumes approximate translation invariance and isotropy (radial spectra of
kernel rows away from the boundary). For strongly space-variant operators (surface-only heat
data) read \(\sigma_F\) as an average and use lateral
axes=spectra; radial averaging hides anisotropic null spaces (sparse-view CT's missing angles report as fully resolvable). Operators without forward-mode AD (e.g.grid_sample-based Radon transforms) fall back to double-backward or finite-difference Jacobian-vector products (exact for linear operators). - Spectra of non-periodic data use a Hann window; interference ripples of multi-object spectra
are smoothed over half-octaves. Both are heuristics with documented knobs (
margin,energy,tol). - Representations mixing network weights with geometric scalars are sensitive to learning
rates; per-group multipliers (
OptimConfig(lr_mult=...), §3) help, but good factors are problem-dependent — no automatic rule is provided yet.