Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

gaussianization tutorial

Part 6 — Continuous-time Gaussianization

Parts 3–5 built Gaussianization out of a finite stack of bijectors — rotate, Gaussianize the margins, repeat. Take that stack to its infinite-depth limit and the discrete composition becomes an ordinary differential equation: a learned vector field x˙=fθ(t,x)\dot x = f_\theta(t, x) whose flow transports the data distribution to N(0,I)\mathcal{N}(0, I) along a continuous path. This part is the bridge between the explicit-Jacobian flows of Parts 4–5 and the stochastic, score-based Gaussianizers of Part 9 (diffusion). It is built on gauss_flows (FFJORD / neural-ODE bijections) with diffrax doing the integration.

The defining move is the instantaneous change of variables: where a discrete layer adds logdetJ\log|\det J|, a continuous flow integrates the trace of the Jacobian along the trajectory,

dlogpt(xt)dt=tr ⁣(xfθ(t,xt)),\frac{\mathrm{d}\log p_t(x_t)}{\mathrm{d}t} = -\operatorname{tr}\!\big(\partial_x f_\theta(t, x_t)\big),

so the log-density is a line integral and the vector field needs no architectural invertibility constraint at all.

Notebooks

#notebookmaster listwhat you take away
00FFJORD on two moons6.1the instantaneous change of variables; train a CNF; data ⇄ N(0,I)\mathcal{N}(0,I) transport
01Hutchinson trace estimator6.2O(d)O(d) exact trace → O(1)O(1) stochastic estimate; bias/variance; when each wins
02Matrix-exponential neural flow6.3linear ODE x˙=Ax\dot x = Ax with closed-form $\log
03Latent ODE on spirals6.4encode → latent ODE → decode; Gaussianization on the latent state

The headline: the trace, not the determinant

A discrete coupling layer earns a free log-det by being triangular (Part 5). A continuous flow earns it differently: the log-density change is the trace of the Jacobian integrated over time, and the trace is cheap to estimate even when the full Jacobian is not. Notebook 01 is the crux — the exact trace costs O(d)O(d) Jacobian-vector products per ODE step, and Hutchinson’s estimator trades that for an O(1)O(1) stochastic probe, which is what makes free-form continuous flows scale past toy dimensions.

Threads

Running

Continuous flows need the FlowJax + diffrax stack (not the rbig env of the earlier parts). Notebooks are paired (jupytext, py:percent) and set jax_enable_x64:

cd projects/gaussianization
PATH="$GF_VENV/bin:$PATH" "$GF_VENV/bin/jupyter" nbconvert --to notebook \
  --execute --inplace notebooks/06_continuous_time/0*.ipynb \
  --ExecutePreprocessor.timeout=1800

where $GF_VENV is a virtualenv with gauss_flows, flowjax, diffrax, matfree, optax, interpax (for the latent-ODE notebook’s path interpolation), and a Jupyter stack. FFJORD training solves an ODE per sample, so these are the slowest notebooks in the curriculum — a couple of minutes each.