Flow-Based Generative Models · UFRJ · 2026.2
U0.T1–U0.T2. We fit a function \(f_\theta \colon x \mapsto y\) and judged it by prediction. Optimizers, schedules, initialization, normalization — all of that machinery still applies, unchanged.
Today. We fit a distribution \(p_\theta \approx q\) and judge it by how well it explains. The maximum-likelihood template from U0.T1, written without labels:
\[ \max_{\theta} \; \mathbb{E}_{x \sim q}\big[\log p_\theta(x)\big] . \]
Nothing above is new. What is new: the objective is no longer computable.
“Much of this course is about what to do when the model’s likelihood is easy to sample but hard to evaluate — or vice versa.”
Today it stops being a slogan. The VAE is our first concrete instance of the first half; autoregressive models, at the end of the hour, are the second half.
Question of the day: when \(\log p_\theta(x)\) cannot be computed, what exactly do we optimize instead — and what do we give up by doing so?
Build something complicated by marginalizing a hidden variable:
Prior \(p(z) = \mathcal{N}(0, I_{d_z})\) on a latent space; decoder \(p_\theta(x \mid z)\) on \(\mathbb{R}^d\). The model is the marginal \[ p_\theta(x) = \int p_\theta(x \mid z)\, p(z)\, \mathrm{d}z = \mathbb{E}_{z \sim p(z)}\big[p_\theta(x \mid z)\big]. \] Sampling is trivial: draw \(z \sim p(z)\), then \(x \sim p_\theta(x \mid z)\).
Each piece is as simple as a distribution gets — a standard Gaussian, and \(\mathcal{N}(g_\theta(z), \sigma^2 I)\) for a network \(g_\theta\).
Three Gaussians in, one multimodal distribution out — the parts are simple, the marginal is not.
(b) is the whole problem: the \(z\) explaining one fixed \(x\) (orange) hold 1.6% of the prior’s mass.
The marginal is an expectation, so estimate it. Draw \(z_1, \dots, z_K \sim p(z)\):
\[ \widehat{p}_\theta(x) = \frac{1}{K} \sum_{k=1}^{K} p_\theta(x \mid z_k), \qquad \mathbb{E}_{z_{1:K} \sim p(z)}\big[\widehat{p}_\theta(x)\big] = p_\theta(x). \]
Unbiased. Also useless:
A linear decoder \(g_\theta(z) = Az + b\), chosen so \(p_\theta(x)\) is known exactly. At \(K = 100\): prior sampling is \(68\%\) wrong, posterior-guided sampling \(8\%\).
Sample from a proposal \(r\) instead of the prior, and reweight:
\[ p_\theta(x) = \mathbb{E}_{z \sim r}\!\left[\frac{p_\theta(x \mid z)\, p(z)}{r(z)}\right]. \]
Take \(r = p_\theta(\cdot \mid x)\), the true posterior. By Bayes’ rule the ratio equals \(p_\theta(x)\) for every \(z\):
\[ \frac{p_\theta(x \mid z)\, p(z)}{p_\theta(z \mid x)} = p_\theta(x) \quad \Longrightarrow \quad \text{zero variance. One sample suffices.} \]
So the posterior is exactly the object we want.
Bayes’ rule computes the posterior from the marginal — which is what we were trying to find.
U1’s answer is invertibility. Build \(p_\theta\) from a bijection; the change-of-variables formula returns \(\log p_\theta(x)\) exactly, with no marginalization at all.
The VAE’s answer is bounding. Give up computing \(\log p_\theta(x)\); optimize a tractable lower bound instead.
Keep both on your map. Much of this course is a tour of such answers — and Flow Matching’s, in U3, is a third one that sidesteps the likelihood entirely.
The course reserves unsubscripted \(q\) for the data distribution. The VAE literature uses \(q\) for the encoder. Both appear in every equation for the next 25 minutes.
Thirty seconds well spent: this is why we can put diffusion and flow matching in the same equations in U3 without a symbol quietly changing meaning.
\[ \begin{aligned} \log p_\theta(x) &= \log \int q_\varphi(z \mid x)\, \frac{p_\theta(x \mid z)\, p(z)}{q_\varphi(z \mid x)}\, \mathrm{d}z = \log\, \mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\!\left[ \frac{p_\theta(x \mid z)\, p(z)}{q_\varphi(z \mid x)}\right] \\[4pt] &\ \ge\ \mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\!\left[ \log \frac{p_\theta(x \mid z)\, p(z)}{q_\varphi(z \mid x)}\right] &&\text{(Jensen; } \log \text{ concave)} \\[4pt] &= \underbrace{\mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\big[\log p_\theta(x \mid z)\big] - \mathrm{KL}\big(q_\varphi(z \mid x) \,\big\|\, p(z)\big)}_{\textstyle \mathrm{ELBO}(\theta, \varphi; x)} \end{aligned} \]
\(q_\varphi\) is arbitrary so far. Both terms are computable: we can sample \(q_\varphi\) because we designed it, and the KL of two Gaussians is closed-form.
\(\mathrm{KL}(a \,\|\, b) \ge 0\), with equality iff \(a = b\) almost everywhere.
\[ -\mathrm{KL}(a \,\|\, b) = \mathbb{E}_{y \sim a}\!\left[\log \frac{b(y)}{a(y)}\right] \;\le\; \log\, \mathbb{E}_{y \sim a}\!\left[\frac{b(y)}{a(y)}\right] = \log \int b = 0 . \]
KL gets its full treatment in UP.A — including the Gaussian closed forms you will use in the next lab (U0.L3) as black boxes, and the sense in which it is not a distance.
Jensen says the bound exists. It does not say what we lost. Start from the KL to the true posterior and substitute Bayes’ rule:
\[ \begin{aligned} \mathrm{KL}\big(q_\varphi(z \mid x) \,\big\|\, p_\theta(z \mid x)\big) &= \mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\big[\log q_\varphi(z \mid x) - \log p_\theta(z \mid x)\big] \\[2pt] &= \mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\big[\log q_\varphi(z \mid x) - \log p_\theta(x \mid z) - \log p(z) + \log p_\theta(x)\big] \\[2pt] &= -\,\mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\!\left[ \log \frac{p_\theta(x \mid z)\, p(z)}{q_\varphi(z \mid x)}\right] + \log p_\theta(x) \\[2pt] &= -\,\mathrm{ELBO}(\theta, \varphi; x) + \log p_\theta(x) . \end{aligned} \]
Line 3 uses that \(\log p_\theta(x)\) is constant in \(z\); line 4 is the definition. Rearrange.
For every \(\theta\), every \(\varphi\), and every \(x\) with \(p_\theta(x) > 0\): \[ \log p_\theta(x) = \mathrm{ELBO}(\theta, \varphi; x) + \mathrm{KL}\big(q_\varphi(z \mid x) \,\big\|\, p_\theta(z \mid x)\big). \] The slack is exactly the divergence from \(q_\varphi\) to the true posterior.
Since \(\mathrm{KL} \ge 0\), this re-proves \(\mathrm{ELBO} \le \log p_\theta(x)\) for free. The two derivations are not redundant: the first shows the bound exists, the second identifies it.
Over \(\varphi\): the left side does not depend on \(\varphi\) — maximizing the ELBO can only shrink the gap. Optimizing the encoder is approximate posterior inference.
At fixed \(\varphi\): the number we report falls short by exactly the posterior mismatch.
\[ \mathrm{ELBO}(\theta, \varphi; x) = \underbrace{\mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\big[\log p_\theta(x \mid z)\big]}_{\text{reconstruction}} \;-\; \underbrace{\mathrm{KL}\big(q_\varphi(z \mid x) \,\big\|\, p(z)\big)}_{\text{stay near the prior}} \]
Where training settles is a property of the model and the data, not something we set.
Course rule (U0.T2 recipe card): composite losses log their parts. Never log only the sum.
Classical variational inference optimizes a separate \(q^{(i)}(z)\) per datapoint — an inner loop at training and test time, useless on unseen \(x\).
The VAE’s move (Kingma and Welling 2014; Rezende, Mohamed, and Wierstra 2014): replace that optimization with a network.
\[ x \;\longmapsto\; \big(\mu_\varphi(x),\, \sigma_\varphi(x)\big), \qquad q_\varphi(z \mid x) = \mathcal{N}\big(z;\, \mu_\varphi(x),\, \operatorname{diag}(\sigma_\varphi(x)^2)\big). \]
One forward pass, any \(x\), including one never seen. The cost of inference is amortized across the dataset.
A variational bound plus Gaussian algebra returns in the D2 detour of U3, where the surprising punchline will be about the weighting of the resulting loss — not its minimizer.
That is the entire flag. Nothing more is claimed, and guessing the rest will not help you.
Training needs \(\nabla_\varphi \mathrm{ELBO}\), and the reconstruction term has the shape
\[ \nabla_\varphi \, \mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\big[f(z)\big], \qquad f(z) = \log p_\theta(x \mid z). \]
Compare with every gradient U0.T1 taught you:
Write \(\frac{1}{K}\sum_k f(z_k)\), call .backward(), get zero — correctly, since \(f\) really does not depend on \(\varphi\).
Let \(\varepsilon \sim \mathcal{N}(0, I_{d_z})\) — a law carrying no parameters — and set \[ z = \mu_\varphi(x) + \sigma_\varphi(x) \odot \varepsilon \quad \Longrightarrow \quad z \sim q_\varphi(z \mid x). \] Then, for integrable \(f\), \[ \nabla_\varphi \, \mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\big[f(z)\big] = \mathbb{E}_{\varepsilon \sim \mathcal{N}(0, I)}\big[ \nabla_\varphi\, f\big(\mu_\varphi(x) + \sigma_\varphi(x) \odot \varepsilon\big)\big]. \]
The exchange is now the ordinary one: the measure is \(\mathcal{N}(0, I)\), fixed and \(\varphi\)-free. Everything \(\varphi\)-dependent moved inside \(f\), where autodiff can reach it.
The graph now contains a random input. We changed no distribution — only which quantities the graph treats as given.
When no such transform exists — discrete latents, most obviously — the fallback is the score-function (REINFORCE) estimator:
\[ \nabla_\varphi \, \mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\big[f(z)\big] = \mathbb{E}_{z \sim q_\varphi(\cdot \mid x)}\big[f(z)\, \nabla_\varphi \log q_\varphi(z \mid x)\big]. \]
Fully general, needs no differentiable path through \(z\) — and badly high-variance without careful control variates. That is why we reparameterize wherever we can.
Every loss in the main course is an expectation over sampled quantities — in Flow Matching, \(\mathbb{E}_{t,\, x_0,\, x_1}\) over a time, a noise sample, and a data sample. Reparameterized sampling is how such objectives become trainable code rather than integrals on a page.
By U3 this will be so routine that the interesting question is no longer how to differentiate through a sample, but which sampling distribution to choose.
Not by architecture. Not by chronology. By what you can compute.
A generator \(G_\psi\) maps noise to samples and never defines a density; a discriminator \(D_\omega\) learns to tell fake from real (Goodfellow et al. 2014):
\[ \min_{\psi} \max_{\omega} \;\; \mathbb{E}_{x \sim q}\big[\log D_\omega(x)\big] + \mathbb{E}_{z \sim p(z)}\big[\log\big(1 - D_\omega(G_\psi(z))\big)\big]. \]
Note the expectations still carry their subscripts — the discipline does not lapse for a slide about someone else’s model.
Factor the joint along a fixed ordering of the \(d\) coordinates — no approximation anywhere:
\[ p_\theta(x) = \prod_{i=1}^{d} p_\theta\big(x_i \mid x_{<i}\big). \]
Each factor is a small conditional produced by a network reading only earlier coordinates. The likelihood is exact, which is why these remain the reference point for density estimation.
There is the planted sentence in its other orientation: fast to evaluate, slow to sample.
This one-fast-direction tradeoff reappears inside flow architectures in U1.T2 — masked autoregressive flows (fast density, slow sampling) against inverse autoregressive flows (fast sampling, slow density). GANs leave the course here, surviving only as the reason sample-based evaluation exists.
Components. \(p(z) = \mathcal{N}(0, I_{d_z})\); encoder \(q_\varphi(z \mid x) = \mathcal{N}\big(z; \mu_\varphi(x), \operatorname{diag}(\sigma_\varphi(x)^2)\big)\); decoder \(p_\theta(x \mid z)\).
Objective (minimized over \(\theta, \varphi\) jointly): \[ \mathcal{L}_{\mathrm{VAE}}(\theta, \varphi) = -\,\mathbb{E}_{x \sim q}\Big[ \mathbb{E}_{\varepsilon \sim \mathcal{N}(0, I)}\big[ \log p_\theta\big(x \mid \mu_\varphi(x) + \sigma_\varphi(x) \odot \varepsilon\big)\big] - \mathrm{KL}\big(q_\varphi(z \mid x) \,\big\|\, p(z)\big) \Big] \]
Sampling (no encoder): \(z \sim \mathcal{N}(0, I_{d_z})\), then \(x \sim p_\theta(x \mid z)\).
We never optimize what we want — only something provably below it. And the encoder, which the whole derivation was built around, plays no part in generation.
U0.L3 implements it, trained with the hygiene-stack from U0.L2 — config, seeding, MLflow logging, checkpointing.
Two specifics to expect:
{loss, recon, kl} — not a single scalar.That last one is the next session’s discussion (U0.L3), not today’s.
| From | Artifact | Role in PS0 |
|---|---|---|
| U0.L2 | hygiene-stack |
“trained with the hygiene stack” |
| U0.L3 | vae-mnist-scratch |
the model — next session |
| U0.L4 | unet-skeleton |
your own encoder, swapped in |
| U0.L4 | eval-harness |
FID at the course-standard sample count |
Graded on correctness and reproducibility — config, seed, commit, logged run — not on how good the samples look.