Type at least 2 letters. Enter opens the first result, Esc closes.

    Generative Models · Lesson 4 · Models with an exact likelihood

    Normalizing flows: change of variables, coupling, autoregressive and continuous flows

    Intermediate 90 min 5 interactive figures 3 videos Colab notebook

    Before this lesson: lesson 01 (maximum likelihood) and lesson 03 (MADE, used inside MAF and IAF). From other tracks: change of variables for densities and Jacobians (calculus), Hutchinson's trace estimator (calculus), and the determinant (linear algebra). Time: about 90 minutes, plus the notebook.


    Why this matters #

    Flows are the second family with an exact likelihood, after autoregressive models (lesson 03). Unlike AR models, a coupling flow samples in one pass. Flows are standard tools for density estimation and variational inference (flexible posteriors), for simulation-based inference (MAF and neural spline flows estimate posteriors of simulator parameters), and for sampling physical systems (Boltzmann generators). The continuous version matters even more today: the probability-flow ODE of diffusion models and the ODE learned by flow matching (lesson 10) are continuous flows, and the instantaneous change of variables of this lesson is how you compute their exact log-likelihood.

    1. Predict first #

    2. The picture #

    One affine map in 1D #

    Let z∼N(0,1)z \sim \mathcal N(0, 1) and x=az+bx = az + b with a≠0a \ne 0. An interval of length ℓ\ell in zz-space becomes an interval of length ∣a∣ℓ|a|\ell in xx-space, and it holds the same probability. The same mass on a longer interval means a lower density, so the density is divided by ∣a∣|a|:

    pX(x)=pZ ⁣(x−ba)1∣a∣.p_X(x) = p_Z\!\left(\frac{x - b}{a}\right) \frac{1}{|a|}.

    Now write f(x)=(x−b)/af(x) = (x - b)/a for the map from data to base. Then ∣f′(x)∣=1/∣a∣|f'(x)| = 1/|a|, and the formula reads: the density of xx is the base density at f(x)f(x), times ∣f′(x)∣|f'(x)|.

    A curved map. The same holds point by point for any increasing map ff: near xx, the map looks like a line with slope f′(x)f'(x). Where ff is steep, a small interval of xx covers a large interval of zz, so it collects a lot of probability: the density of xx is high. Where ff is flat, the density of xx is low.

    Interactive figure: loading…

    Drag the yellow knots of the map z=f(x)z = f(x). The aqua curve on the left is the base density N(0,1)\mathcal N(0, 1) along the zz axis. The top chart shows the model density pX(x)=φ(f(x)) f′(x)p_X(x) = \varphi(f(x))\,f'(x) in orange, and a histogram of samples x=f−1(z)x = f^{-1}(z) with z∼N(0,1)z \sim \mathcal N(0, 1). The yellow probe interval and its image on the zz axis hold the same probability. Notice that the area under pXp_X stays 1, and that the bumps appear where the map is steep.

    Quick check

    z∼N(0,1)z \sim \mathcal N(0, 1) and x=−2z+1x = -2z + 1. What is pX(1)p_X(1)? (φ\varphi is the standard normal density, φ(0)≈0.399\varphi(0) \approx 0.399.)

    A flow is many such maps #

    A normalizing flow makes ff a composition of invertible layers with learnable parameters: f=fK∘⋯∘f1f = f_K \circ \dots \circ f_1. It is used in two directions.

    • Density direction (data →\to base, ff): compute z=f(x)z = f(x) and add up the log⁡∣det⁡J∣\log|\det J| of each layer. This gives log⁡pX(x)\log p_X(x), and the training loss.
    • Sampling direction (base →\to data, f−1f^{-1}): draw z∼N(0,I)z \sim \mathcal N(0, I) and invert the layers in reverse order.

    In this track, ff always goes from data to base, z=f(x)z = f(x). The review by Papamakarios et al. names the sampling map TT, with x=T(u)x = T(u): it is the same object seen from the other side, T=f−1T = f^{-1} and u=zu = z.

    The design problem. Each layer must be (1) invertible, (2) cheap in log⁡∣det⁡J∣\log|\det J| (a general D×DD \times D determinant costs O(D3)O(D^3)), and (3) expressive. There are two answers. Make the Jacobian triangular (coupling and autoregressive layers), or make the flow continuous in time, where the log-determinant becomes an integral of a trace.

    Coupling layers bend space one coordinate at a time #

    An affine coupling layer keeps half of the coordinates and uses them to shift and scale the other half. In 2D: keep x1x_1; replace x2x_2 by x2es(x1)+t(x1)x_2 e^{s(x_1)} + t(x_1). The next layer keeps x2x_2 and changes x1x_1. Each layer is simple, but a stack of them can bend a Gaussian into a curved, skewed shape, and the density stays exact.

    Interactive figure: loading…

    Add layers and move the sliders of s(u)=Atanh⁡(Bu)s(u) = A\tanh(Bu) and t(u)=Csin⁡(u)t(u) = C\sin(u). The orange heat map is the exact model density pXp_X. The aqua curves are the straight grid lines of the base space, carried to data space by the sampling map f−1f^{-1}: where they crowd together, the density is high. Drag the yellow point: each layer adds its own log-determinant, which is just ss of the kept coordinate. The grid sum of the density stays 1.

    3. Definitions and main results #

    3.1 The change-of-variables formula #

    Theorem (change of variables). Let f:RD→RDf: \R^D \to \R^D be a bijection, with ff and f−1f^{-1} continuously differentiable, and let z=f(x)z = f(x) have density pZp_Z. Then

    pX(x)=pZ(f(x)) ∣det⁡Jf(x)∣,Jf(x)=∂f∂x(x).p_X(x) = p_Z\big(f(x)\big)\,\big|\det J_f(x)\big|, \qquad J_f(x) = \frac{\partial f}{\partial x}(x).

    Why this is true. A small box around xx with volume dVdV is mapped to a small parallelogram around f(x)f(x) with volume ∣det⁡Jf(x)∣ dV|\det J_f(x)|\,dV (the determinant is the volume factor of the linear map Jf(x)J_f(x)). Both hold the same probability: pX(x) dV=pZ(f(x)) ∣det⁡Jf(x)∣ dVp_X(x)\,dV = p_Z(f(x))\,|\det J_f(x)|\,dV.

    Proof.

    1. 1D, ff increasing: FX(x)=P(X≤x)=P(Z≤f(x))=FZ(f(x))F_X(x) = P(X \le x) = P(Z \le f(x)) = F_Z(f(x)). Differentiate: pX(x)=pZ(f(x)) f′(x)p_X(x) = p_Z(f(x))\,f'(x).
    2. 1D, ff decreasing: FX(x)=P(Z≥f(x))=1−FZ(f(x))F_X(x) = P(Z \ge f(x)) = 1 - F_Z(f(x)), so pX(x)=−pZ(f(x)) f′(x)p_X(x) = -p_Z(f(x))\,f'(x). Both cases give pZ(f(x)) ∣f′(x)∣p_Z(f(x))\,|f'(x)|.
    3. DD dimensions: for every set AA, P(X∈A)=P(Z∈f(A))=∫f(A)pZ(z) dz=∫ApZ(f(x)) ∣det⁡Jf(x)∣ dxP(X \in A) = P(Z \in f(A)) = \int_{f(A)} p_Z(z)\,dz = \int_A p_Z(f(x))\,|\det J_f(x)|\,dx, by the substitution z=f(x)z = f(x) of multivariable calculus.
    4. A density is fixed by its integrals over all sets, so the integrand is pXp_X. ■\blacksquare

    The calculus lesson on change of variables gives the substitution rule of step 3 in full.

    Composition. Let f=fK∘⋯∘f1f = f_K \circ \dots \circ f_1, with z0=xz_0 = x, zk=fk(zk−1)z_k = f_k(z_{k-1}) and z=zKz = z_K. The chain rule gives Jf=JfK⋯Jf1J_f = J_{f_K} \cdots J_{f_1}, and the determinant of a product is the product of the determinants. So

    log⁡pX(x)=log⁡pZ(zK)+∑k=1Klog⁡∣det⁡Jfk(zk−1)∣.\log p_X(x) = \log p_Z(z_K) + \sum_{k=1}^{K} \log\big|\det J_{f_k}(z_{k-1})\big| .

    Training minimizes the mean of −log⁡pX(x)-\log p_X(x) over the data: maximum likelihood, the same as minimizing KL(pdata ∥ pX)\mathrm{KL}(p_{\text{data}} \,\|\, p_X). You never form JfJ_f itself; each layer reports its own log-determinant.

    The other direction. In the sampling direction, x=f−1(z)x = f^{-1}(z) and log⁡pX(x)=log⁡pZ(z)−log⁡∣det⁡Jf−1(z)∣\log p_X(x) = \log p_Z(z) - \log|\det J_{f^{-1}}(z)|: the sign flips, because Jf−1(z)=Jf(x)−1J_{f^{-1}}(z) = J_f(x)^{-1}. Check with x=2zx = 2z: the data are more spread out than the base, so the density must go down, and indeed log⁡pX(x)=log⁡pZ(z)−log⁡2\log p_X(x) = \log p_Z(z) - \log 2.

    3.2 Affine coupling layers (RealNVP and Glow) #

    Split x=(xA,xB)x = (x_A, x_B). Let ss and tt be any networks from xAx_A to vectors of the size of xBx_B, and ⊙\odot the elementwise product. The affine coupling layer (RealNVP; Dinh et al. 2017) is

    yA=xA,yB=xB⊙exp⁡(s(xA))+t(xA).y_A = x_A, \qquad y_B = x_B \odot \exp\big(s(x_A)\big) + t(x_A).
    1. Jacobian. yAy_A does not depend on xBx_B, so the upper-right block is 0. Each yB,jy_{B,j} depends on xBx_B only through xB,jx_{B,j}, so the lower-right block is diagonal:
    J=(I0∂yB/∂xAdiag⁡(es(xA))).J = \begin{pmatrix} I & 0 \\ \partial y_B/\partial x_A & \operatorname{diag}\big(e^{s(x_A)}\big) \end{pmatrix}.
    1. Log-determinant. The matrix is block lower triangular, so its determinant is the product of the diagonal entries: log⁡∣det⁡J∣=∑jsj(xA)\log|\det J| = \sum_j s_j(x_A). The cost is O(D)O(D). The block ∂yB/∂xA\partial y_B/\partial x_A, which holds all the derivatives of the networks, never enters.
    2. Inverse. xA=yAx_A = y_A and xB=(yB−t(yA))⊙exp⁡(−s(yA))x_B = \big(y_B - t(y_A)\big) \odot \exp\big(-s(y_A)\big). It needs only forward passes of ss and tt, so ss and tt never have to be inverted: they can be arbitrary networks.
    3. Stacking. One layer leaves xAx_A unchanged, so the roles of AA and BB alternate (or the coordinates are permuted) between layers. The product of the layer Jacobians is a full matrix, but its log-determinant is still the sum of the layer terms.

    In practice the log-scale is bounded, for example s=tanh⁡(sraw)s = \tanh(s_{\text{raw}}) or a soft clamp, so each factor esje^{s_j} stays in a safe range early in training.

    Quick check

    Which part of the Jacobian of an affine coupling layer never enters log⁡∣det⁡J∣\log|\det J|?

    Glow (Kingma and Dhariwal 2018) adds two layers for feature maps of size H×WH \times W with cc channels:

    • Actnorm: a per-channel scale scs_c and bias, initialized on the first batch so that each channel has zero mean and unit variance. Log-determinant: HW∑clog⁡∣sc∣HW \sum_c \log|s_c|.
    • Invertible 1×11 \times 1 convolution: the same c×cc \times c matrix WW mixes the channels at every pixel. The Jacobian of the whole layer is block diagonal with HWHW copies of WW, so log⁡∣det⁡J∣=HWlog⁡∣det⁡W∣\log|\det J| = HW \log|\det W|. With the LU form W=PL(U+diag⁡(s))W = PL(U + \operatorname{diag}(s)) (PP a fixed permutation, LL unit lower triangular, UU strictly upper triangular), log⁡∣det⁡W∣=∑ilog⁡∣si∣\log|\det W| = \sum_i \log|s_i|: cost O(c)O(c) instead of O(c3)O(c^3). It generalizes the fixed permutation between coupling layers.

    3.3 Autoregressive flows (MAF and IAF) #

    An affine autoregressive layer transforms coordinate ii with a shift μi\mu_i and a log-scale αi\alpha_i. Both come from one MADE network (lesson 03) with two outputs per dimension.

    MAF (masked autoregressive flow; Papamakarios et al. 2017) works in the density direction:

    ui=(xi−μi(x<i)) e−αi(x<i).u_i = \big(x_i - \mu_i(x_{<i})\big)\,e^{-\alpha_i(x_{<i})}.
    1. Jacobian. uiu_i depends on x1,…,xix_1, \dots, x_i only, so ∂u/∂x\partial u/\partial x is lower triangular with diagonal entries e−αie^{-\alpha_i}. Hence log⁡∣det⁡∂u/∂x∣=−∑iαi(x<i)\log|\det \partial u/\partial x| = -\sum_i \alpha_i(x_{<i}).
    2. Density: one pass. All μi,αi\mu_i, \alpha_i depend on the observed xx, so one MADE pass gives all of them.
    3. Sampling: DD passes. The inverse is xi=uieαi(x<i)+μi(x<i)x_i = u_i e^{\alpha_i(x_{<i})} + \mu_i(x_{<i}), and x<ix_{<i} must be known before xix_i. This is the ancestral sampling of lesson 03. An AR model with Gaussian conditionals is exactly a one-layer MAF.

    IAF (inverse autoregressive flow; Kingma et al. 2016) works in the sampling direction. Its parameters depend on the base variables:

    xi=ui eαi(u<i)+μi(u<i).x_i = u_i\, e^{\alpha_i(u_{<i})} + \mu_i(u_{<i}).
    1. Sampling: one pass, because uu is known.
    2. Density of its own samples: one pass. log⁡q(x)=log⁡N(u;0,I)−∑iαi(u<i)\log q(x) = \log \mathcal N(u; 0, I) - \sum_i \alpha_i(u_{<i}), and uu is kept from the sampling step.
    3. Density of an outside xx: DD passes. Recovering uiu_i needs u<iu_{<i} first.
    Interactive figure: loading…

    Choose a flow and a task, then press Next pass. One MADE pass computes μi\mu_i and αi\alpha_i for all ii at once, but entry ii is valid only when the network inputs 1,…,i−11, \dots, i - 1 are known. Entries that became valid in the last pass are yellow. Try all four cases: MAF density and IAF sampling finish in one pass; MAF sampling and IAF density need D=4D = 4 passes.

    Flow log⁡p\log p of a data point Sampling Typical use
    Coupling (RealNVP, Glow) 1 pass 1 pass images, audio (WaveGlow); needs many layers
    MAF 1 pass DD passes density estimation, simulation-based inference
    IAF DD passes (own samples: 1) 1 pass VAE posteriors; fast students (Parallel WaveNet)
    Continuous (FFJORD) ODE solve + trace ODE solve free-form vector field; cost = number of evaluations

    A coupling layer is an autoregressive layer with only two blocks: block BB is conditioned on block AA, and AA on nothing. That is why it is fast in both directions, and less expressive per layer.

    Quick check

    You want a flexible posterior q(z∣x)q(z \mid x) inside a VAE. The ELBO needs samples z∼qz \sim q and log⁡q(z∣x)\log q(z \mid x) of those same samples. Which flow fits best?

    3.4 Continuous flows: the instantaneous change of variables #

    A continuous normalizing flow (CNF) defines the map by an ordinary differential equation

    dxdt=f(x(t),t),t∈[0,T].\frac{dx}{dt} = f\big(x(t), t\big), \qquad t \in [0, T].

    Any network ff that is Lipschitz in xx (and continuous in tt) works. The solution map is invertible (solve the ODE backwards in time), and ff needs no special structure: no triangular Jacobian, no coupling.

    Picture: one Euler step. The step xt+h=xt+h f(xt,t)x_{t+h} = x_t + h\,f(x_t, t) has Jacobian I+hJI + hJ, with J=∂f/∂xJ = \partial f/\partial x, and log⁡det⁡(I+hJ)=htr⁡(J)+O(h2)\log\det(I + hJ) = h \operatorname{tr}(J) + O(h^2). The change of variables for this small step gives log⁡pt+h(xt+h)=log⁡pt(xt)−htr⁡(J)+O(h2)\log p_{t+h}(x_{t+h}) = \log p_t(x_t) - h\operatorname{tr}(J) + O(h^2). Now let h→0h \to 0.

    Theorem (instantaneous change of variables; Chen et al. 2018). If x(t)x(t) solves x˙=f(x,t)\dot x = f(x, t) and ptp_t is the density of x(t)x(t), then

    ddtlog⁡pt(x(t))=−tr⁡ ⁣(∂f∂x(x(t),t))=−(∇⋅f)(x(t),t).\frac{d}{dt}\log p_t\big(x(t)\big) = -\operatorname{tr}\!\left(\frac{\partial f}{\partial x}\big(x(t), t\big)\right) = -(\nabla \cdot f)\big(x(t), t\big).

    The trace of the Jacobian is the divergence ∇⋅f=∑i∂fi/∂xi\nabla \cdot f = \sum_i \partial f_i/\partial x_i: the rate at which the flow expands volume. Expanding volume lowers the density along the path.

    Proof (from the continuity equation)
    1. Probability mass moves with the flow, so ptp_t solves the continuity equation ∂tpt+∇⋅(ptf)=0\partial_t p_t + \nabla \cdot (p_t f) = 0.
    2. Along a trajectory, the total derivative is ddtpt(x(t))=∂tpt+∇pt⋅f\frac{d}{dt}p_t(x(t)) = \partial_t p_t + \nabla p_t \cdot f (chain rule, with x˙=f\dot x = f).
    3. Expand ∇⋅(ptf)=∇pt⋅f+pt ∇⋅f\nabla \cdot (p_t f) = \nabla p_t \cdot f + p_t\,\nabla \cdot f and insert step 1 into step 2: ddtpt(x(t))=−∇pt⋅f−pt ∇⋅f+∇pt⋅f=−pt ∇⋅f\frac{d}{dt}p_t(x(t)) = -\nabla p_t \cdot f - p_t\,\nabla \cdot f + \nabla p_t \cdot f = -p_t\,\nabla \cdot f.
    4. Divide by ptp_t: ddtlog⁡pt(x(t))=−∇⋅f=−tr⁡(∂f/∂x)\frac{d}{dt}\log p_t(x(t)) = -\nabla \cdot f = -\operatorname{tr}(\partial f/\partial x). ■\blacksquare

    Integrate from the data at t=0t = 0 to the base at t=Tt = T:

    log⁡p0(x(0))=log⁡pT(x(T))+∫0Ttr⁡ ⁣(∂f∂x(x(t),t))dt.\log p_0\big(x(0)\big) = \log p_T\big(x(T)\big) + \int_0^T \operatorname{tr}\!\left(\frac{\partial f}{\partial x}\big(x(t), t\big)\right) dt .

    One ODE solver call integrates the state xx and the accumulated trace together. Training a CNF by maximum likelihood needs gradients through the solver (backpropagation through the solver steps, or the adjoint method of Chen et al. 2018).

    Interactive figure: loading…

    Move the time tt, or press Play. A linear field dx/dt=Axdx/dt = Ax (violet arrows) moves samples of p0=N(0,I)p_0 = \mathcal N(0, I); the aqua points and the grey ellipses (1 and 2 standard deviations) show ptp_t, which stays Gaussian, so everything is exact. The readouts compare the change of log-density along the magenta path, computed from the Gaussian formula, with −ttr⁡A-t \operatorname{tr} A. Drag the start point and try the presets: the two numbers always agree, and a rotation (tr⁡A=0\operatorname{tr} A = 0) keeps the density along every path.

    Hutchinson's estimator (FFJORD). The exact trace needs DD backward passes, one per diagonal entry of ∂f/∂x\partial f/\partial x. For any random vector ε\varepsilon with E[εε⊤]=I\mathbb E[\varepsilon\varepsilon^\top] = I (Rademacher ±1\pm 1 entries, or Gaussian),

    tr⁡(J)=E[ε⊤Jε],\operatorname{tr}(J) = \mathbb E\big[\varepsilon^\top J \varepsilon\big],

    because E[ε⊤Jε]=∑i,jJij E[εiεj]=∑iJii\mathbb E[\varepsilon^\top J \varepsilon] = \sum_{i,j} J_{ij}\,\mathbb E[\varepsilon_i \varepsilon_j] = \sum_i J_{ii}. The product ε⊤J\varepsilon^\top J is one vector-Jacobian product: one backward pass per probe, whatever DD is. FFJORD (Grathwohl et al. 2019) uses this estimator and keeps the same ε\varepsilon for a whole ODE solve, so the dynamics stay deterministic inside the solver. Two facts to remember. The estimate of log⁡p\log p is unbiased, but its exponential is not an unbiased estimate of pp (Jensen's inequality). And the variance of one probe is 2∥Js∥F22\|J_s\|_F^2 for Gaussian probes and 2∑i≠j(Js)ij22\sum_{i \ne j} (J_s)_{ij}^2 for Rademacher probes, with Js=(J+J⊤)/2J_s = (J + J^\top)/2: Rademacher probes add no noise from the diagonal. The calculus lesson proves the variance formulas.

    Interactive figure: loading…

    Choose a Jacobian and a number of probes SS. The histograms show 2000 estimates of the trace with Gaussian and Rademacher probes; the black line is the true trace. The lower chart shows the variance against SS on log scales, with the formulas as dashed lines. Notice that both estimators are centered on the truth, that the variance falls like 1/S1/S, and that Rademacher probes are exact for a diagonal Jacobian.

    Quick check

    J=(213−1)J = \begin{pmatrix} 2 & 1 \\ 3 & -1 \end{pmatrix} and ε\varepsilon has independent Rademacher entries (±1\pm 1 with probability 1/21/2). What is E[ε⊤Jε]\mathbb E[\varepsilon^\top J \varepsilon]?

    Diffusion models and flow matching are continuous flows. The probability-flow ODE of a diffusion model (lesson 09) is dxdt=f(x,t)−12g(t)2∇xlog⁡pt(x)\frac{dx}{dt} = f(x, t) - \tfrac12 g(t)^2 \nabla_x \log p_t(x), where ff and gg are the drift and the diffusion coefficient of the forward SDE (the letter ff has that meaning in lessons 07 to 15). It has the same marginals ptp_t as the diffusion process. With the learned score inserted, its right side is a vector field like the one above, so the formula of this subsection gives the exact log-likelihood of that ODE model, up to solver error and trace noise. Song et al. (2021) report the bits per dimension of diffusion models this way. Flow matching and rectified flow (lesson 10) train the same kind of continuous flow without simulating the ODE; after training, the same formula gives their likelihood.

    3.5 What flows cannot do #

    • No change of dimension. A flow is a bijection between RD\R^D and RD\R^D with a square Jacobian. A flow cannot map data to a smaller latent space, as a VAE does. If zz had fewer dimensions than xx, the samples f−1(z)f^{-1}(z) would lie on a lower-dimensional surface, which has zero volume in RD\R^D: there would be no density pXp_X at all.
    • Topology. A flow is a continuous bijection, and N(0,I)\mathcal N(0, I) is positive everywhere, so pX(x)=pZ(f(x)) ∣det⁡Jf(x)∣>0p_X(x) = p_Z(f(x))\,|\det J_f(x)| > 0 everywhere: the model can never put exactly zero density between two separated modes. To make the density small there, the sampling map f−1f^{-1} must stretch that region very strongly (huge ∣det⁡Jf−1∣|\det J_{f^{-1}}|), which needs very large derivatives and is hard to learn.
    Quick check

    Why can a normalizing flow not map 784-dimensional images to a 64-dimensional Gaussian latent?

    Answers to section 1. (1) O(1000)O(1000): the log-determinant is ∑jsj(xA)\sum_j s_j(x_A). The networks cost one forward pass; no determinant is ever computed. (2) MAF evaluates log⁡p(x)\log p(x) in one pass, because its parameters depend on the observed xx. IAF samples in one pass, because its parameters depend on the known base variables uu. Each needs DD passes in its other direction.

    4. Worked example #

    (a) Two coupling layers in 2D (density direction, base N(0,I)\mathcal N(0, I)), at x=(2,1)x = (2, 1).

    • Layer 1 keeps x1x_1, with s1(x1)=x1/2s_1(x_1) = x_1/2 and t1(x1)=−x1t_1(x_1) = -x_1. So s1(2)=1s_1(2) = 1, t1(2)=−2t_1(2) = -2, and y=(2, 1⋅e1−2)=(2, 0.7183)y = (2,\ 1 \cdot e^1 - 2) = (2,\ 0.7183). Log-determinant: s1(2)=1s_1(2) = 1.
    • Layer 2 keeps y2y_2, with s2(y2)=−y2/2s_2(y_2) = -y_2/2 and t2(y2)=1t_2(y_2) = 1. So s2(0.7183)=−0.3591s_2(0.7183) = -0.3591 and z=(2e−0.3591+1, 0.7183)=(2.3966, 0.7183)z = (2e^{-0.3591} + 1,\ 0.7183) = (2.3966,\ 0.7183). Log-determinant: −0.3591-0.3591.
    • Base: log⁡N(z;0,I)=−log⁡2π−12(2.39662+0.71832)=−1.8379−12(5.7435+0.5159)=−1.8379−3.1297=−4.9676\log \mathcal N(z; 0, I) = -\log 2\pi - \tfrac12(2.3966^2 + 0.7183^2) = -1.8379 - \tfrac12(5.7435 + 0.5159) = -1.8379 - 3.1297 = -4.9676.
    • Result: log⁡pX(x)=−4.9676+1−0.3591=−4.3267\log p_X(x) = -4.9676 + 1 - 0.3591 = -4.3267.

    The layer Jacobians are triangular, J1=(100.35912.7183)J_1 = \begin{pmatrix} 1 & 0 \\ 0.3591 & 2.7183 \end{pmatrix} (lower) and J2=(0.6983−0.698301)J_2 = \begin{pmatrix} 0.6983 & -0.6983 \\ 0 & 1 \end{pmatrix} (upper), but their product J2J1=(0.4475−1.89810.35912.7183)J_2 J_1 = \begin{pmatrix} 0.4475 & -1.8981 \\ 0.3591 & 2.7183 \end{pmatrix} has no zero entry. Still, det⁡(J2J1)=2.7183⋅0.6983=1.8981=e0.6409\det(J_2 J_1) = 2.7183 \cdot 0.6983 = 1.8981 = e^{0.6409}, and 0.6409=1−0.35910.6409 = 1 - 0.3591.

    Inverse. Undo layer 2 first: y2=z2=0.7183y_2 = z_2 = 0.7183 and y1=(z1−1) ey2/2=1.3966⋅1.4321=2y_1 = (z_1 - 1)\,e^{y_2/2} = 1.3966 \cdot 1.4321 = 2. Then undo layer 1: x1=y1=2x_1 = y_1 = 2 and x2=(y2+x1) e−x1/2=2.7183⋅0.3679=1x_2 = (y_2 + x_1)\,e^{-x_1/2} = 2.7183 \cdot 0.3679 = 1.

    (b) A one-layer MAF is a Gaussian AR model. Take μ1=0\mu_1 = 0 and α1=log⁡2\alpha_1 = \log 2 (so x1∼N(0,22)x_1 \sim \mathcal N(0, 2^2)), and μ2(x1)=x12\mu_2(x_1) = x_1^2, α2=0\alpha_2 = 0 (so x2∣x1∼N(x12,1)x_2 \mid x_1 \sim \mathcal N(x_1^2, 1), a "banana" shape). At x=(2,3)x = (2, 3):

    • one pass: u=((2−0)/2, (3−4)/1)=(1,−1)u = \big((2 - 0)/2,\ (3 - 4)/1\big) = (1, -1), log-determinant −α1−α2=−log⁡2-\alpha_1 - \alpha_2 = -\log 2;
    • log⁡p(x)=log⁡N(u;0,I)−log⁡2=−2.8379−0.6931=−3.5310\log p(x) = \log \mathcal N(u; 0, I) - \log 2 = -2.8379 - 0.6931 = -3.5310;
    • chain-rule check: log⁡N(2;0,4)+log⁡N(3;4,1)=−2.1121−1.4189=−3.5310\log \mathcal N(2; 0, 4) + \log \mathcal N(3; 4, 1) = -2.1121 - 1.4189 = -3.5310.

    Sampling from u=(0.5,0.2)u = (0.5, 0.2) takes two passes: first x1=2⋅0.5=1x_1 = 2 \cdot 0.5 = 1, then x2=0.2+12=1.2x_2 = 0.2 + 1^2 = 1.2.

    (c) A linear continuous flow. f(x)=Axf(x) = Ax with A=(−120−0.5)A = \begin{pmatrix} -1 & 2 \\ 0 & -0.5 \end{pmatrix} and T=1T = 1. Here tr⁡(∂f/∂x)=tr⁡A=−1.5\operatorname{tr}(\partial f/\partial x) = \operatorname{tr} A = -1.5 everywhere, so log⁡p0(x(0))=log⁡p1(x(1))−1.5\log p_0(x(0)) = \log p_1(x(1)) - 1.5. Check with the discrete formula: the flow map is x(1)=eAx(0)x(1) = e^{A}x(0), and log⁡∣det⁡eA∣=tr⁡A=−1.5\log|\det e^{A}| = \operatorname{tr} A = -1.5 (Jacobi's formula det⁡eA=etr⁡A\det e^A = e^{\operatorname{tr} A}). The flow shrinks volume, so the density grows along each path, by the factor e1.5≈4.48e^{1.5} \approx 4.48. This is the "worked example" preset of the figure above.

    Hutchinson by hand: the four Rademacher probes ε=(±1,±1)\varepsilon = (\pm 1, \pm 1) give ε⊤Aε=0.5,−3.5,−3.5,0.5\varepsilon^\top A \varepsilon = 0.5, -3.5, -3.5, 0.5 for (1,1),(1,−1),(−1,1),(−1,−1)(1, 1), (1, -1), (-1, 1), (-1, -1). The mean is −1.5=tr⁡A-1.5 = \operatorname{tr} A, and the variance is 4=(A12+A21)24 = (A_{12} + A_{21})^2: with Rademacher probes, only the off-diagonal entries add noise.

    5. In code #

    NumPy and SciPy check the hand computations: the coupling layers with a finite-difference Jacobian, the MAF against the chain rule, Glow's 1×11 \times 1 log-determinant, the instantaneous change of variables on a nonlinear 2D flow, and Hutchinson's estimator. For (d), with vector field ff, we integrate the Jacobian Φ(t)=∂x(t)/∂x(0)\Phi(t) = \partial x(t)/\partial x(0) of the flow map (it solves Φ˙=(∂f/∂x) Φ\dot\Phi = (\partial f/\partial x)\,\Phi) next to δ=−∫0ttr⁡(∂f/∂x) ds\delta = -\int_0^t \operatorname{tr}(\partial f/\partial x)\,ds, and compare δ\delta with −log⁡∣det⁡Φ∣-\log|\det \Phi|.

    import numpy as np
    from scipy.integrate import solve_ivp
    from scipy.stats import norm
    
    # (a) The two coupling layers of section 4, density direction x -> z
    def f(x):
        y = np.array([x[0], x[1] * np.exp(x[0] / 2) - x[0]])        # layer 1 keeps x1
        return np.array([y[0] * np.exp(-y[1] / 2) + 1, y[1]])       # layer 2 keeps y2
    
    x = np.array([2.0, 1.0])
    z = f(x)
    h = 1e-6                                                         # Jacobian by central differences
    J = np.column_stack([(f(x + h * e) - f(x - h * e)) / (2 * h) for e in np.eye(2)])
    logdet = np.linalg.slogdet(J)[1]
    print(z.round(4), J.round(4).tolist())     # [2.3966 0.7183] [[0.4475, -1.8981], [0.3591, 2.7183]]
    print(round(logdet, 4), round(norm.logpdf(z).sum() + logdet, 4))   # 0.6409 -4.3267
    
    # (b) The one-layer MAF of section 4 equals the chain rule p(x1) p(x2 | x1)
    x1, x2 = 2.0, 3.0
    u = np.array([(x1 - 0.0) / 2.0, (x2 - x1**2) / 1.0])          # mu1 = 0, sigma1 = 2; mu2 = x1^2, sigma2 = 1
    print(round(norm.logpdf(u).sum() - np.log(2.0), 4),
          round(norm.logpdf(x1, 0, 2) + norm.logpdf(x2, x1**2, 1), 4))  # -3.531 -3.531
    
    # (c) Glow's 1x1 convolution: the Jacobian is block diagonal with H*W copies of W
    c, H, W_ = 3, 4, 5
    Wmix = np.random.default_rng(0).normal(size=(c, c))
    Jc = np.kron(np.eye(H * W_), Wmix)                               # (60, 60), pixel by pixel
    print(round(np.linalg.slogdet(Jc)[1], 6), round(H * W_ * np.linalg.slogdet(Wmix)[1], 6))
    # -16.271734 -16.271734
    
    # (d) Instantaneous change of variables for dx/dt = tanh(Ax + b): integrate x, the Jacobian Phi
    #     of the flow map, and delta = -int tr(df/dx) dt together
    A, b = np.array([[0.5, -2.0], [1.0, -1.0]]), np.array([0.3, -0.2])
    def rhs(t, s):
        xs, Phi = s[:2], s[2:6].reshape(2, 2)
        Jf = np.diag(1 - np.tanh(A @ xs + b) ** 2) @ A               # df/dx
        return np.concatenate([np.tanh(A @ xs + b), (Jf @ Phi).ravel(), [-np.trace(Jf)]])
    s0 = np.concatenate([[1.0, -0.5], np.eye(2).ravel(), [0.0]])
    sol = solve_ivp(rhs, (0.0, 2.0), s0, rtol=1e-10, atol=1e-12)
    Phi, delta = sol.y[2:6, -1].reshape(2, 2), sol.y[6, -1]
    print(round(delta, 6), round(-np.log(abs(np.linalg.det(Phi))), 6))   # 0.213696 0.213696
    
    # (e) Hutchinson on the 2x2 matrix of section 4: all four Rademacher probes
    Alin = np.array([[-1.0, 2.0], [0.0, -0.5]])
    eps = np.array([[1, 1], [1, -1], [-1, 1], [-1, -1]])
    q = np.einsum("ni,ij,nj->n", eps, Alin, eps)
    print(q, q.mean(), q.var())                                      # [ 0.5 -3.5 -3.5  0.5] -1.5 4.0
    

    Check (d) is Liouville's formula det⁡Φ(t)=exp⁡∫0ttr⁡(∂f/∂x) ds\det \Phi(t) = \exp \int_0^t \operatorname{tr}(\partial f/\partial x)\,ds: the instantaneous change of variables seen from the Jacobian side.

    6. Where it shows up #

    • Images and audio. RealNVP and Glow use coupling layers; WaveGlow uses them for speech. On CIFAR-10, Glow reaches 3.35 bits per dimension; strong AR models (PixelCNN++: 2.92) and diffusion models do better (lesson 14 explains how such numbers are compared).
    • Variational inference. An IAF makes a VAE's q(z∣x)q(z \mid x) flexible: the VAE needs only samples from qq and log⁡q\log q of those samples. Parallel WaveNet distills a slow AR WaveNet into a fast IAF student.
    • Simulation-based inference. MAF and neural spline flows are standard conditional density estimators q(θ∣xobs)q(\theta \mid x_{\text{obs}}) for neural posterior estimation, where a simulator exists but its likelihood is not available.
    • Physics sampling. Boltzmann generators (Noé et al. 2019) and flows for lattice field theory sample with an exact density qq, then reweight by p/qp/q or add a Metropolis correction to remove the model's bias.
    • Continuous flows in ML for science. Rectified-flow and flow-matching models are CNFs, and diffusion models have the probability-flow ODE. The held-out log-likelihood from the instantaneous change of variables is a strictly proper score for comparing such models of, for example, ground motion or weather fields. Report it on a fixed data scale: if a model is trained on x′=x/σx' = x/\sigma in DD dimensions, then log⁡pX(x)=log⁡pX′(x/σ)−Dlog⁡σ\log p_X(x) = \log p_{X'}(x/\sigma) - D\log\sigma.

    7. Common mistakes #

    • Sign of the log-determinant. In the density direction, log⁡p(x)=log⁡pZ(f(x))+log⁡∣det⁡Jf(x)∣\log p(x) = \log p_Z(f(x)) + \log|\det J_f(x)| (add). In the sampling direction, log⁡p(x)=log⁡pZ(z)−log⁡∣det⁡Jf−1(z)∣\log p(x) = \log p_Z(z) - \log|\det J_{f^{-1}}(z)| (subtract). Check with x=2zx = 2z: the density must go down.
    • No alternation. Coupling layers with the same split keep xAx_A unchanged forever.
    • Unbounded scales. ese^{s} with a raw network output can overflow. Bound it (tanh⁡\tanh, a soft clamp) and initialize near the identity.
    • MAF sampling in one pass, or IAF density of data in one pass. Each needs DD sequential passes in its slow direction.
    • Forgetting preprocessing log-determinants. Scaling, logit transforms and dequantization change log⁡p\log p; add their log-determinants before you compare likelihoods.
    • Trusting one Hutchinson probe for evaluation, or exponentiating it as an unbiased likelihood. Use the exact trace or many probes for test numbers.
    • Expecting a perfect fit of separated modes. The model density is positive everywhere, also between separated modes (section 3.5).

    8. Check yourself #

    1. A coupling layer gives s(xA)=(0.3,−0.1,0.5)s(x_A) = (0.3, -0.1, 0.5). What is log⁡∣det⁡J∣\log|\det J| of the layer, and of its inverse?
      Answer0.3−0.1+0.5=0.70.3 - 0.1 + 0.5 = 0.7. The inverse layer has −0.7-0.7.
    2. A Glow 1×11 \times 1 convolution acts on a 16×16×816 \times 16 \times 8 feature map, and log⁡∣det⁡W∣=0.2\log|\det W| = 0.2. What does the layer add to log⁡p(x)\log p(x) in the density direction?
      Answer16⋅16⋅0.2=51.216 \cdot 16 \cdot 0.2 = 51.2 nats: the Jacobian has HW=256HW = 256 diagonal blocks equal to WW.
    3. A MAF on D=100D = 100 dimensions. How many MADE passes does it need to evaluate log⁡p\log p of a batch of data? To draw a batch of samples?
      AnswerOne pass for the density. 100 sequential passes for sampling, because xix_i needs x<ix_{<i}.
    4. Why is IAF a good VAE posterior but a poor density estimator for data?
      AnswerA VAE needs samples z∼qz \sim q and log⁡q(z)\log q(z) of those same samples: one pass each, since uu is known. The density of an outside point needs uu from xx, which takes DD sequential passes.
    5. A CNF has f(x)=Rxf(x) = Rx with R=(0−110)R = \begin{pmatrix} 0 & -1 \\ 1 & 0 \end{pmatrix} (a rotation). How does log⁡pt(x(t))\log p_t(x(t)) change along a trajectory?
      AnswerIt stays constant: tr⁡R=0\operatorname{tr} R = 0, so the flow is divergence-free and keeps volume.
    6. Hutchinson with Rademacher probes on J=(213−1)J = \begin{pmatrix} 2 & 1 \\ 3 & -1 \end{pmatrix}. Give the possible values of ε⊤Jε\varepsilon^\top J \varepsilon, the mean and the variance.
      Answerε⊤Jε=2−1+(1+3)ε1ε2=1+4ε1ε2\varepsilon^\top J \varepsilon = 2 - 1 + (1 + 3)\varepsilon_1\varepsilon_2 = 1 + 4\varepsilon_1\varepsilon_2, so 55 or −3-3, each with probability 1/21/2. Mean 1=tr⁡J1 = \operatorname{tr} J; variance 16=(J12+J21)216 = (J_{12} + J_{21})^2.
    Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
    1. State the change-of-variables formula for z=f(x)z = f(x).

    2. z∼N(0,1)z \sim \mathcal N(0, 1) and x=az+bx = az + b. What is pX(x)p_X(x)?

    3. Log-likelihood of a flow f=fK∘⋯∘f1f = f_K \circ \dots \circ f_1 in the density direction?

    4. Affine coupling layer: formula and log⁡∣det⁡J∣\log|\det J|?

    5. Why is the Jacobian of a coupling layer triangular?

    6. MAF vs IAF: which is fast for what?

    7. Log-determinant of a Glow 1×11 \times 1 convolution on an H×W×cH \times W \times c map?

    8. State the instantaneous change of variables.

    9. What is Hutchinson's trace estimator, and why is it unbiased?

    10. Why can a flow not have a lower-dimensional latent space?

    Open the review →

    9. Interview angle #

    • "Write the log-likelihood of a normalizing flow." — log⁡pZ(f(x))+∑klog⁡∣det⁡Jfk∣\log p_Z(f(x)) + \sum_k \log|\det J_{f_k}| along the density direction.
    • "Coupling or autoregressive flow?" — The cost table: coupling is fast both ways but weaker per layer; MAF is fast for density, IAF for sampling.
    • "Derive the log-determinant of a Glow 1×11 \times 1 convolution." — Block-diagonal Jacobian with HWHW copies of WW: HWlog⁡∣det⁡W∣HW\log|\det W|; the LU form makes it O(c)O(c).
    • "How do you get the likelihood of a diffusion or flow-matching model?" — The instantaneous change of variables along the probability-flow ODE, with a Hutchinson or exact trace (for diffusion there is also the ELBO of lesson 07).
    • "Why do flows give worse samples than diffusion models?" — The same dimension everywhere, the topology limit, many constrained layers, and maximum likelihood spends capacity on covering all the data. Flow matching and diffusion train an unconstrained network and get invertibility from the ODE.

    10. Practice #

    The notebook for this lesson has five exercises, each with a check cell and a folded solution, and a demonstration that trains a small RealNVP on two moons in NumPy:

    1. 1D change of variables: the density of x=sinh⁡(z)x = \sinh(z), checked against a histogram of mapped samples.
    2. Affine coupling forward and inverse; compare the log-determinant with a finite-difference Jacobian.
    3. A RealNVP stack: log_prob and sample; check that the density integrates to 1 on a grid.
    4. Hutchinson's estimator with Gaussian and Rademacher probes; compare the variances with the formulas.
    5. The linear ODE dx/dt=Axdx/dt = Ax: check that the change of log⁡pt\log p_t along a path is −ttr⁡A-t\operatorname{tr}A.

    11. Watch and read #

    Change of variables, the log-determinant and coupling layers, with clear animations.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    A full lecture on flows: 1D flows, change of variables, coupling layers (RealNVP, Glow) and autoregressive flows (MAF, IAF).
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    The paper that introduced continuous normalizing flows and the instantaneous change of variables.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play