Flow-Based Generative Models · UFRJ · 2026.2
| Unit | Strategy | What it costs |
|---|---|---|
| U1 — today | invertible by construction | what the map is allowed to be |
| U2 | volume change by calculus | a solver inside every training step |
| U3 | refuse to play | nothing yet |
Today is the first row. It is also the first session where a model gets trained.
A generative model is a pushforward of noise, and training is maximum likelihood: \[ p_\theta = \big(\psi^{\theta}\big)_{\#}\, p_0 , \qquad \operatorname*{arg\,max}_{\theta}\; \mathbb{E}_{x_1 \sim q}\big[ \log p_\theta(x_1) \big] = \operatorname*{arg\,min}_{\theta}\; \mathrm{KL}\big(q \,\Vert\, p_\theta\big) . \]
Therefore training needs \(\log p_\theta(x_1)\) at data points. The definition only gives you samples.
For a generic network \(\psi^{\theta}\), the density at \(x_1\) is an integral over every noise point that lands there: \[ p_\theta(x_1) = \int p_0(x_0)\, \delta\big(x_1 - \psi^{\theta}(x_0)\big)\, \mathrm{d}x_0 . \]
No closed form. Preimages may be empty, or infinite, or the output may lie on a surface with no density at all.
Two escape routes: bound it (the variational autoencoder; one line, not today), or make it exact by construction. This unit takes the second.
What must \(\psi^{\theta}\) satisfy for \(\log p_\theta(x_1)\) to be exactly computable?
This stays on the board until the end. A second question joins it later, and that one is not answered today.
\(y = g(x)\) with \(g\) differentiable and strictly monotone: \[ p_y(y) = p_x\big(g^{-1}(y)\big)\, \left| \frac{\mathrm{d}\,g^{-1}}{\mathrm{d}y}(y) \right| . \]
The absolute value is the content: mass is conserved, density is not. Where \(g\) stretches, the density falls by the same factor.
PS1.1.8 made you compute it for \(\tanh\). The primer promised the \(d\)-dimensional version as PS1.3. Here it is.
\(\psi\) a diffeomorphism of \(\mathbb{R}^{d}\), \(x \sim p\), \(y = \psi(x)\). Then \[ (\psi_{\#} p)(y) = p\big(\psi^{-1}(y)\big)\, \big|\det J_{\psi^{-1}}(y)\big| = \frac{p(x)}{\big|\det J_{\psi}(x)\big|}, \qquad x = \psi^{-1}(y) . \]
Hypotheses, displayed: \(\psi\) is a bijection, \(\psi\) is differentiable, \(\psi^{-1}\) is differentiable.
The two forms agree because \(J_{\psi^{-1}}(y) = J_\psi(x)^{-1}\). Statement as in (Papamakarios et al. 2021, sec. 2.1).
\[ \log p_\theta(x_1) \;=\; \log p_0(x_0) \;-\; \log\big|\det J_{\psi^{\theta}}(x_0)\big| , \qquad x_0 = \big(\psi^{\theta}\big)^{-1}(x_1) . \]
Log form, forward Jacobian, and \(\psi^{\theta}\) generates (noise to data), as in UP.T1.
Read it as a recipe: undo the map to find \(x_0\), evaluate \(\log p_0\) there, subtract the log-volume factor.
The papers write the map the other way (\(f\): data to latent, \(= (\psi^{\theta})^{-1}\)). Translate before you read.
\[ \underbrace{(\psi_{\#}p)\big(\psi(x_0)\big)}_{\text{density at image}} \cdot \underbrace{|\det J_\psi(x_0)|\, h^{d}}_{\text{volume of image}} \;\approx\; \underbrace{p(x_0)}_{\text{density at source}} \cdot \underbrace{h^{d}}_{\text{volume of source}} \]
Every noise point in the cube lands in the image cell, and no other does, because \(\psi\) is a bijection.
The determinant is the exchange rate between volume and density. Where the map expands, the density drops by the same factor.
Waved hands, named as waved hands. Closing them is PS1.3.
(a) Linear. \(\mathrm{vol}(AB) = |\det A|\,\mathrm{vol}(B)\) for boxes \(B\), via elementary matrices.
(b) Local. \(\mathrm{vol}(\psi(C_h))/h^{d} \to |\det J_\psi(x_0)|\): sandwich \(\psi(C_h)\) between two scaled copies of the parallelepiped \(J_\psi(x_0)(C_h - x_0)\).
(c) Global. Cut a box into cubes, apply (b), pass to the limit with dominated convergence: \(\int_{\psi(B)} g = \int_B (g \circ \psi)\, |\det J_\psi|\).
(d) Read off the density, both forms, and the log form.
Route fixed on purpose: linearization, not measure-theoretic pushforward machinery. The notes carry the hints.
The theorem asks three things of \(\psi\):
Together: a diffeomorphism. Everything built today inherits these hypotheses.
\[ \psi^{\theta} = \psi_K \circ \cdots \circ \psi_1 , \qquad (\psi^{\theta})^{-1} = \psi_1^{-1} \circ \cdots \circ \psi_K^{-1} , \qquad \det J_{\psi^{\theta}}(x_0) = \prod_{k} \det J_{\psi_k}(z_{k-1}) \]
Diffeomorphisms compose. The inverse undoes the layers in reverse; the chain rule multiplies the determinants.
Name the intermediate points once: \[ z_0 = x_0, \qquad z_k = \psi_k(z_{k-1}), \qquad z_K = x_1 . \]
A sample flows through the layers. The inverse normalizes data back to the source.
\[ \log p_\theta(x_1) \;=\; \log p_0(z_0) \;-\; \sum_{k=1}^{K} \log\big|\det J_{\psi_k}(z_{k-1})\big| , \qquad z_K = x_1,\;\; z_{k-1} = \psi_k^{-1}(z_k) . \]
One board line. The chain is computed by running the inverse, from the data point down to the noise point.
Every term must be cheap: for every layer, at every data point, at every training step.
| Operation | Direction | Needs, per layer | Cost driver |
|---|---|---|---|
| Sampling | forward, \(x_0 \to x_1\) | evaluate \(\psi_k\) | one pass per layer |
| Density / training | inverse, \(x_1 \to x_0\) | \(\psi_k^{-1}\) and \(\log\lvert\det J_{\psi_k}\rvert\) | the inverse, and the log-det |
Versioned: U1.T2 adds a row per architecture; U2.T2 changes what the cells contain; U3.L1 touches neither row.
A dense \(d \times d\) Jacobian: \(O(d^{2})\) to store, \(O(d^{3})\) to take the determinant of — per layer, per data point, per step.
\(32 \times 32\) colour image: \(d = 3072\), so \(d^{3} \approx 3 \times 10^{10}\).
And the inverse of a generic network is not available at all.
The whole architectural zoo of this unit is a list of tricks to make both rows cheap simultaneously.
One layer: input \(x\), output \(y\). In the chain of block C, \(x = z_{k-1}\) and \(y = z_k\).
Partition \(x = (x_A, x_B)\), \(d_A + d_B = d\). Take any network \(m_\theta \colon \mathbb{R}^{d_A} \to \mathbb{R}^{d_B}\):
\[ y_A = x_A , \qquad y_B = x_B + m_\theta(x_A) . \]
Half passes through untouched. The other half is shifted by an amount that depends on the untouched half only (Dinh, Krueger, and Bengio 2015, sec. 3.2).
Order the coordinates \((x_A, x_B)\) and differentiate block by block: \[ J_\psi(x) = \begin{bmatrix} I_{d_A} & 0 \\[4pt] \dfrac{\partial m_\theta}{\partial x_A}(x_A) & I_{d_B} \end{bmatrix} \quad\Longrightarrow\quad \det J_\psi(x) = 1 . \]
Block lower-triangular: the determinant is the product of the diagonal blocks. The expensive block never enters.
Inverse, free: \(\;x_A = y_A , \quad x_B = y_B - m_\theta(y_A) .\)
Invertibility of the whole does not require invertibility of the parts.
To undo the layer you evaluate \(m_\theta\) at \(y_A\), which you have, because \(y_A = x_A\). You never invert \(m_\theta\).
So \(m_\theta\) can be as deep, as wide, and as non-invertible as you like. Every coupling architecture in this unit rides on this.
\(\det J \equiv 1\) means the layer preserves volume. So does any stack of them.
A volume-preserving flow cannot concentrate or spread mass. A real dataset has a different spread from \(\mathcal{N}(0, I_d)\).
NICE’s fix: one final diagonal scaling layer, \(y_i = S_{ii}\,x_i\), with \(\log|\det J_\psi(x)| = \sum_i \log|S_{ii}|\). A global rescaling, once.
The next block makes the rescaling local. That is the whole difference.
Same untouched half, same conditioner reading it. One new operation on the path of \(x_B\): a scale before the shift.
Keep the split and the pass-through half. Replace the shift by a shift and a scale, both read off \(x_A\):
\[ y_A = x_A , \qquad y_B = x_B \odot \exp\!\big(s_\theta(x_A)\big) + t_\theta(x_A) . \]
\(s_\theta, t_\theta \colon \mathbb{R}^{d_A} \to \mathbb{R}^{d_B}\) arbitrary networks; \(\odot\) elementwise. The exponential keeps every scale positive (Dinh, Sohl-Dickstein, and Bengio 2017, sec. 3.2).
\[ \log\big|\det J_\psi(x)\big| \;=\; \sum_{j=1}^{d_B} s_\theta(x_A)_j \]
A sum read off one forward pass of \(s_\theta\). No \(d \times d\) matrix formed, no determinant computed.
Inverse, closed form: \(\;x_A = y_A, \quad x_B = \big(y_B - t_\theta(y_A)\big) \odot \exp\!\big(-s_\theta(y_A)\big).\)
The sum depends on \(x_A = y_A\) only, so it is available on both sides of the layer — the inverse pass, which training runs, reads it for free.
| NICE (additive) | RealNVP (affine) | |
|---|---|---|
| Layer | \(y_B = x_B + m_\theta(x_A)\) | \(y_B = x_B \odot e^{s_\theta(x_A)} + t_\theta(x_A)\) |
| \(\log\lvert\det J_\psi\rvert\) | \(0\) | \(\sum_j s_\theta(x_A)_j\) |
| Inverse | subtract; one pass of \(m_\theta\) | subtract, divide; one pass of \(s_\theta, t_\theta\) |
| Volume | preserved; a global scaling layer at the end | changed locally, per layer |
| Untouched half | \(x_A\), read by the conditioner | \(x_A\), read by the conditioner |
Both rows of the two-costs table are one conditioner pass per layer, in both directions, for both layers.
Shading is the cell’s area ratio, \(|\det J|\) averaged over the cell: constant down each column, because it depends on \(x_A\) alone.
\(e^{s}\) overflows in single precision near \(s \approx 88\). \(e^{-s}\) in the inverse divides by almost zero when \(s\) is large.
Early in training \(s_\theta\) is a random network, and both happen.
Implementations bound the scale: \(s = c \cdot \tanh(\tilde s)\) before the exponential.
One slide. The lab (U1.L1) shows the loss curve when you forget.
\[ \begin{aligned} \mathcal{L}(\theta) &= -\;\mathbb{E}_{x_1 \sim q}\Big[ \log p_0(z_0) - \sum_{k=1}^{K} \log\big|\det J_{\psi_k}(z_{k-1})\big| \Big] , \\[4pt] &\phantom{=} z_K = x_1,\qquad z_{k-1} = \psi_k^{-1}(z_k) . \end{aligned} \]
The subscript on \(\mathbb{E}\) is mandatory, and this is the first loss of the course where it is enforced. Each log-det is a sum of scales at the untouched half of \(z_{k-1}\).
PS1.4 is exactly the bookkeeping of this expression for a three-layer RealNVP. Assigned now.
\(\psi^{\theta} = \psi_3 \circ \psi_2 \circ \psi_1\); coordinates of a vector written \((\xi_1, \dots, \xi_4)\) (\(x_1\) stays the data point). Layers 1 and 3 condition on \((\xi_1, \xi_2)\) and move \((\xi_3, \xi_4)\); layer 2 the reverse.
(a) Write the inverse pass: \(z_2, z_1, z_0\) from a data point, in the order computed.
(b) Write \(\log p_\theta(x_1)\) fully explicitly: every log-det as its sum of scales, every scale at the correct intermediate point.
(c) Write the minibatch loss, sample mean in place of the expectation, subscript kept.
(d) Replace \(\psi_2\) by a swap of the halves. Redo (b). Which term changes?
Mechanical on purpose: the notation of the loss through your hands once, before U1.L1 puts it through code.
A coupling layer leaves \(x_A\) exactly as it found it. Same split forever means a model of \(x_B\) only.
Check the permutation in your head now; check it in code next session (U1.L1).
For images: binary masks, checkerboard and channel-wise. One line; that is U1.L2.
With alternation in place, a stack of \(K\) affine coupling layers moves every coordinate, and the composed Jacobian is dense once \(K \ge 3\).
The natural next belief: with enough layers, a coupling flow reaches anything. Asserted today. Not proven.
How expressive is a stack of these, really?
Written on the board next to the session question. Answered in U1.T2.
flow_log_prob is the telescoped log-likelihood: inverse chain, plus \(\log p_0(z_0)\), minus the \(K\) sums of scales. You write it in U1.L1. opt: AdamW, LR \(3 \times 10^{-4}\), weight decay \(0.01\); sched: warmup, then cosine.
Bootcamp readers: training-loop-template with a new loss line, under optimizer-schedule-defaults. For everyone else, the box is the whole definition.
| On the board | Status |
|---|---|
| The session question — what must \(\psi^{\theta}\) satisfy? | Answered: a diffeomorphism, built from layers whose inverse and log-det are cheap. |
| The depth question — how expressive is a stack? | Open. U1.T2. |
| The fine print — bijection, differentiable, both ways | Unexamined. U1.T2. |
Assigned today: PS1.3 (the proof) and PS1.4 (the bookkeeping).