-
\(\displaystyle D_{f}(P_{x}\| P_{\theta }) = \int _{X} P_{\theta }(x)\cdot f\bigl( \frac{P_{x}(x)}{P_{\theta }(x)} \bigr) dx\)Start from the definition of the f-divergence, with \(f\) convex, lower-semicontinuous, \(f(1)=0\).
-
\(f(u) = \sup _{t \in \operatorname{dom} f^{*}} \{ t\cdot u - f^{*}(t) \}\)Fenchel–Moreau: a convex, l.s.c. function equals its biconjugate. Here \(f^{*}(t)=\sup _{u}\{tu-f(u)\}\) is the convex conjugate.
-
\(\displaystyle f\bigl(\frac{P_{x}}{P_{\theta }}\bigr) = \sup _{t} \{ t\cdot \frac{P_{x}}{P_{\theta }} - f^{*}(t) \}\)Substitute \(u = P_{x}(x)/P_{\theta }(x)\) into the biconjugate form.
-
\(\displaystyle D_{f} = \int _{X} P_{\theta }(x)\cdot \sup _{t} \{ t\cdot \frac{P_{x}}{P_{\theta }} - f^{*}(t) \} dx\)Plug the ratio back inside the integral. The optimal \(t\) depends on \(x\), so it cannot simply be pulled outside — call the maximiser a function \(T(x)\).
-
\(\displaystyle D_{f} \ge \sup _{T \in \mathcal{T} } \int _{X} P_{\theta }(x)\bigl\{ T(x)\cdot \frac{P_{x}}{P_{\theta }} - f^{*}(T(x)) \bigr\} dx\)Why ≥ and not =: for any function \(T\) the integrand is ≤ the pointwise sup, so the integral drops. Searching only a representable class \(\mathcal{T}\) (e.g. neural nets) may miss the true maximiser \(T^{*}\), so we keep a lower bound.
-
\(\displaystyle D_{f} \ge \sup _{T} \bigl[ \int _{X} T(x)\cdot P_{x}(x) dx - \int _{X} f^{*}(T(x))\cdot P_{\theta }(x) dx \bigr]\)The key cancellation: in the first term \(P_{\theta }\cdot T\cdot (P_{x}/P_{\theta }) = T\cdot P_{x}\). The \(P_{\theta }\) vanishes — that is what makes it an expectation under \(P_{x}\).
-
\(D_{f}(P_{x}\| P_{\theta }) \ge \sup _{T} \bigl[ \mathbb{E} _{P_{x}}[T(x)] - \mathbb{E} _{P_{\theta }}[f^{*}(T(x))] \bigr]\)Each integral against a density is an expectation → estimable by Monte-Carlo sample averages. Equality holds iff \(\mathcal{T}\) contains the optimum \(T^{*}(x)=f'(P_{x}/P_{\theta })\). Represent \(T\) by a net \(T_{\omega }\) and the bound becomes the f-GAN min–max.
Quiz 1, decoded: the adversarial half of GenAI.
Across three past papers (2025 T2 · 2025 T3 · 2026 T1), Quiz 1 tests one thing: the mathematics of GANs — from f-divergences and variational bounds, through Wasserstein GANs and inversion, to FID. No VAEs, no diffusion, no transformers. This guide walks the whole story and drills the exact question templates that keep coming back.
Exam intel — where the marks actually are
The three papers are drawn from the same tightly-scoped bank. Many questions are the same template with different numbers. Prioritise by frequency.
Format
- Question types: MCQ single-answer · MSQ multi-select · NAT numeric answer. Marks per question range 1–4.
- Split: roughly half concept-recall (know the exact formula / which statement is false) and half short numeric computation (a trace, a small-distribution divergence, a layer-size product).
- Style: heavy, precise LaTeX notation. It rewards exact recall (the exact objective, the exact conjugate, the exact optimal discriminator) far more than hand-waving.
Topic frequency across the 3 papers
Combined GenAI questions, binned by theme. Longer bar = it shows up more, so it earns more of your revision time.
If you memorise five things cold you cover the majority of marks:
- 1.the f-divergence generator functions \(f(u)\) + Fenchel conjugate
- 2.the minimax GAN objective & its optimal discriminator \(D^{*}=\)\(\displaystyle \frac{p_{x}}{p_{x}+p_{\theta }}\)
- 3.the WGAN dual + Lipschitz enforcement
- 4.the BiGAN joint objective
- 5.the FID formula
Everything else is bonus.
The big picture: one idea, told four ways
Every model in this course is the same three-step recipe. Hold this in your head and each section slots in.
We are given data \(D = \{x_{1},\dots ,x_{n}\}\) drawn i.i.d. from an unknown distribution \(P_{x}\). The goal of generative modelling is to estimate \(P_{x}\) and learn to sample from it — not to classify, but to synthesise new points that look like they came from \(P_{x}\).
We never observe the densities \(P_{x}\) or \(P_{\theta }\) — only samples from each. So the entire game is: rewrite the divergence as expectations, which the Law of Large Numbers lets us estimate from samples. That single move — divergence → expectation → sample average — is the spine of the whole course.
The generator \(g_{\theta }(z)\) turns cheap noise into data. A second network — the discriminator / critic — measures how far \(P_{\theta }\) is from \(P_{x}\). They are trained adversarially: the critic tries to tell real from fake, the generator tries to fool it. When the critic can no longer win, \(P_{\theta } \approx P_{x}\) and \(g_{\theta }\) has become a sampler for \(P_{x}\).
- 1.How do we compute a divergence without knowing either density?
- 2.Which divergence should we pick?
- 3.How do we choose \(g_{\theta }\)?
- 4.How do we solve the (hard, saddle-point) optimisation?
Sections 03–07 are literally the answers, in order.
Foundations & problem setup
The vocabulary and the one theorem (Law of Large Numbers) that makes everything else computable.
Data, distributions, and the generator
- \(x_{i} \in \mathbb{R} ^{d}\) — each datapoint is a high-dimensional vector. E.g. a 400×400×3 image ⇒ \(d = 480,000\).
- Samples are independent across examples (\(x_{i} \perp x_{j}\)), but the dimensions within one \(x_{i}\) are not independent (pixels are correlated).
- The generator \(g_{\theta }: Z \to X\) maps a known latent \(z \sim \mathcal{N} (0,I)\) to data space. Its output \(\hat{x} = g_{\theta }(z)\) has an implicit density \(P_{\theta }\) we can sample from but cannot write down.
A discriminative model learns the conditional \(P_{y|x}\) and never samples. A generative model learns to draw from \(P_{x}\). Same data, opposite goal.
The one theorem you compute with: Monte Carlo
Any integral against a density is an expectation, and any expectation is a sample average in the limit. This is why "we only have samples" is not a blocker.
f-Divergence & Variational Divergence Minimisation
The machinery that turns "measure the gap between two distributions" into "train two neural nets." Every exam tests the \(f(u)\) table and the conjugate.
Definition & properties
The key exam fact: different choices of \(f\) give different classic divergences — so different generative models. Memorise this table; it is directly asked every semester.
| Divergence | Generator function \(f(u)\) | Conjugate \(f^{*}(t)\) |
|---|---|---|
| Forward KL \(D_{\mathrm{KL}}(P_{x}\| P_{\theta })\) | \(u \log u\) | \(e^{t-1}\) |
| Reverse KL \(D_{\mathrm{KL}}(P_{\theta }\| P_{x})\) | \(-\log u\) | \(-1-\log (-t)\) |
| Total Variation (TV) | \(\tfrac{1}{2} |u-1|\) | \(t\), \(|t|\le \tfrac{1}{2}\) |
| Jensen–Shannon (JS) | \(\displaystyle \tfrac{1}{2} (u \log u - (u+1)\log \frac{u+1}{2})\) | \(-\log (2-e^{t})\) |
| GAN (JS-like) | \(u \log u - (u+1)\log (u+1)\) | \(-\log (1-e^{t})\) |
The Wasserstein distance is NOT an f-divergence — it can't be written in this integral form. That exact "which of these cannot be represented as an f-divergence?" question appeared verbatim. KL is asymmetric: \(D_{\mathrm{KL}}(P_{x}\| P_{\theta }) \ne D_{\mathrm{KL}}(P_{\theta }\| P_{x})\) (forward vs reverse).
The convex-conjugate trick → variational lower bound
The problem: the integrand contains the ratio \(P_{x}/P_{\theta }\), which is not an expectation of any single random variable. The fix is the Fenchel (convex) conjugate, which rewrites a convex \(f\) as a supremum of linear functions:
Substituting and replacing the pointwise optimum with a function \(T(x)\) (a neural net can only search a restricted class, so equality becomes ≥) yields the punchline of Week 1:
These variational-form questions hinge on: any \(T\) gives a lower bound (good for iterative optimisation); the bound's tightness depends on the discriminator's capacity to approximate the optimal \(T^{*}\); and the optimum is \(T^{*}(x) = f'(P_{x}/P_{\theta })\). A statement claiming a "different conjugate" or an "upper bound" is the false one.
Drill it — f-divergence questions
- \(f(u)=u \log u\)
- \(f(u)=-\log u\)
- \(f(u)=\tfrac{1}{2} |u-1|\)
- \(f(u)=(u-1)^{2}\)
- \(f(u)=\tfrac{1}{2} |u-1|\)
- \(f(u)=u \log u\)
- \(f(u)=\log (1+u)\)
- \(f(u)=u-1\)
› Reveal answer
Forward KL is \(u \log u\); reverse just swaps the roles, giving \(-\log u\). Know all four rows of the table cold — one of them is asked every time.
- \(f^{*}(t)=\log (1+e^{t})\)
- \(f^{*}(t)=e^{t-1}\)
- \(f^{*}(t)=t^{2}\)
- \(f^{*}(t)=1/(1+e^{-t})\)
› Reveal answer
Set derivative \(t - (\log u + 1) = 0 \Rightarrow u = e^{t-1}\). Substitute back: \(t\cdot e^{t-1} - e^{t-1}(t-1) = e^{t-1}\).
(b) TV distance \(D_{\mathrm{TV}}=\tfrac{1}{2} \Sigma |p_{i}-q_{i}|\) for \(P=[0.1,0.2,0.7]\), \(Q=[0.2,0.3,0.5]\).
› Reveal answer
(a) By the course's definition, \(D_{f}(P\|Q) = \Sigma_i P_i \log(P_i/Q_i)\) — that is \(0.5\log(0.5/0.25) + 0.5\log(0.5/0.75)\) \(= 0.5(0.693) + 0.5(-0.405)\) \(\approx 0.144\), i.e. 0.14 (natural log). The published key's 0.13 is the reverse KL: \(\Sigma_i Q_i \log(Q_i/P_i)\) \(= 0.25\log(0.5) + 0.75\log(1.5)\) \(\approx 0.131\). So the number depends on which direction you compute — the forward \(D_{\mathrm{KL}}(P\|Q)\) that the f-divergence definition asks for is 0.14. (b) \(\tfrac{1}{2}(0.1+0.1+0.2) = 0.2\).
- KL
- Reverse KL
- Total Variation
- Wasserstein
› Reveal answer
KL, reverse KL, and TV all correspond to a valid convex \(f(u)\). Wasserstein is an optimal-transport metric — a different construction entirely (Section 07).
The GAN — one specific choice of f
Plug the JS-like \(f\) into the variational bound, pick the matching activation, and the abstract min–max collapses into the famous GAN objective with a sigmoid discriminator.
For GANs we take \(f(u)=u \log u - (u+1)\log (u+1)\), whose conjugate is \(f^{*}(t)=-\log (1-e^{t})\) on \(\operatorname{dom} f^{*}=\mathbb{R} ^{-}\). Choosing the activation \(\sigma _{f}(v)=-\log (1+e^{-v})\) to keep the critic's output in that domain, the value function becomes exactly:
Reading the two networks
- G a sampler: noise in, image out.
- D a probability: "how likely is this real?"
- The linear head \(V_{\omega }(x)\in \mathbb{R}\) is the logit; sigmoid squashes it to \([0,1]\).
The optimal discriminator — memorise these three lines
If \(P_{\mathrm{data}}\) and \(P_{g}\) have disjoint supports (e.g. two Dirac deltas at different points), the discriminator becomes perfect: \(D^{*}=1\) on real, \(0\) on fake, and the value function \(= log1 + log1 = 0\). The answer to "what is \(V(G)\)?" is 0. This is precisely why training saturates — see Section 07.
Drill it — GAN objective & D*
- \(D^{*}=P_{\theta }/(P_{x}+P_{\theta })\)
- \(D^{*}=P_{x}/(P_{x}+P_{\theta })\)
- \(D^{*}=1[P_{x}>P_{\theta }]\)
- \(D^{*}=\log (P_{x}/P_{\theta })\)
- \(V=-\log 4 + 2\cdot JSD(P_{x}\| P_{\theta })\)
- \(V=\log 4 - 2\cdot JSD(P_{x}\| P_{\theta })\)
- \(V=D_{\mathrm{KL}}(P_{x}\| P_{\theta })\)
- \(V=0\) for all \(\theta\)
› Reveal answer
The \(-log4\) is the floor (achieved when the distributions match); the \(2\cdot JSD\) term is what the generator drives to zero.
- \(-\log 2\)
- \(0\)
- \(-\log (0.5)\)
- \(\log 4\)
› Reveal answer
Disjoint supports ⇒ a perfect discriminator (\(D=1\) on data, \(D=0\) on generated). Then \(V = \mathbb{E} [log1] + \mathbb{E} [\log (1-0)] = 0\). Same answer regardless of where the deltas sit, as long as they differ.
- \(|\partial\,\text{minimax}/\partial a| \approx 0.99,\ |\partial\,\text{non-sat}/\partial a| \approx 0.01\)
- \(|\partial\,\text{minimax}/\partial a| \approx 0.01,\ |\partial\,\text{non-sat}/\partial a| \approx 0.99\)
- Both \(\approx 0.5\)
- Both \(\approx 0\)
› Reveal answer
When the generator is losing (\(\sigma (a)\approx 0\)) the minimax loss gives a vanishing gradient (≈ 0.01) — no learning signal. The non-saturating loss \(-\log \sigma (a)\) gives a strong gradient (≈ 0.99). This is exactly why practitioners use the non-saturating generator loss.
Training the min–max & the classifier view
Alternating gradient ascent/descent, the scheduling knobs, and the intuition that a GAN is a "classifier-guided sampler" — with the crucial caveat.
The alternating loop
- Scheduling is a knob: 1 D-step + 1 G-step, or k D-steps per G-step, etc. A training loop that runs the discriminator update k times inside the loop means the discriminator is updated multiple times per generator update.
- Failure signal: if the discriminator loss collapses to ≈0 while the generator loss shoots up, the discriminator has become too strong — the generator's gradient has vanished.
- Stop when generated-sample quality is good enough; there is no clean "loss went to zero" stopping rule.
GAN as a classifier-guided sampler — and the trap
Intuition: if a classifier \(D_{\omega }\) can no longer tell real from generated, maybe \(P_{\theta }=P_{x}\). Tweak θ until the classifier fails.
\(P_{x}=P_{\theta } \Rightarrow\) classifier fails, but classifier failure ⇏ \(P_{x}=P_{\theta }\). A badly-placed decision boundary can fail while the distributions are still far apart; the generator could even mode-hop to dodge a fixed classifier. Fix: the classifier must be re-optimised jointly with the generator — that co-adaptation is exactly the \(\min _{\theta } \max _{\omega }\) saddle point.
optimizer_D block k times before one optimizer_G step — what does it imply?- Generator is updated multiple times per discriminator update
- Discriminator is updated multiple times per generator update
- Both networks are updated simultaneously
- The model uses gradient accumulation
- The generator is overfitting to the noise
- The discriminator has become too strong
- The generator's learning rate is too high
- The noise vector dimension is too large
› Reveal answer
A dominant discriminator drives the generator's gradient toward zero (vanishing-gradient saturation) — the motivation for WGAN.
loss.backward() twice without zero_grad(). What happens to param.grad?- It is overwritten by the second backward pass
- It becomes zero due to autograd safety
- It accumulates (adds) gradients from both passes
- It becomes NaN deterministically
› Reveal answer
Autograd accumulates into .grad by default; that's why every training step begins with optimizer.zero_grad(). Forgetting it sums stale gradients.
DCGAN & Conditional GAN
Two architectural variants: one changes how the generator upsamples, the other adds control over what gets generated.
DCGAN — Deep Convolutional GAN
Typically \(z \in \mathbb{R} ^{k}\), \(x \in \mathbb{R} ^{d}\) with \(k \ll d\) — the generator must expand dimensionality. A plain GAN uses fully-connected layers then reshapes to an image. DCGAN uses transposed (up-)convolution layers to grow the latent straight up to image size \(\mathbb{R} ^{r\times c\times 3}\) — no reshape needed, and spatial structure is respected throughout.
Conditional GAN (cGAN)
Vanilla GANs give no control. With labelled data \(D=\{(x_{i},y_{i})\}\sim P_{\mathrm{xy}}\) we instead sample from the conditional \(P_{x|y}\). Feed the label \(y\) (one-hot or a text embedding) into both networks:
Counting generator parameters (a guaranteed NAT template)
For linear layers \(a \to b \to c \to \dots\) excluding biases, parameters = sum of consecutive products \(a\cdot b + b\cdot c + \dots\)
- 78,400
- 102,400
- 246,272
- 156,000
› Reveal answer
\(100\cdot 128 + 128\cdot 256 + 256\cdot 784 = 12,800 + 32,768 + 200,704 = 246,272\). If biases were included, add \(128+256+784\).
- A · \(\min _{\theta }\max _{\omega } \mathbb{E} _{x\sim P_{x}}[\log D_{\omega }(x)] + \mathbb{E} _{z}[\log (1-D_{\omega }(g_{\theta }(z)))]\)
- B · \(\min _{\theta } \mathbb{E} _{(x,y)}\| x - g_{\theta }(y)\| ^{2}\)
- C · \(\min _{\theta }\max _{\omega } \mathbb{E} _{(x,y)\sim P_{x|y}}[\log D_{\omega }(x,y)] + \mathbb{E} _{(\hat{x},y)\sim P^{\theta}_{\hat{x}|y}}[\log (1-D_{\omega }(\hat{x},y))]\)
› Reveal answer
The tell is that both arguments to \(D_{\omega }\) carry the label \(y\). Option A is the unconditional GAN; B is a regression, not adversarial.
Wasserstein GAN — fixing the instability
First why f-divergence GANs are unstable, then the optimal-transport metric that cures it and the Lipschitz constraint that makes it trainable.
Why training saturates: manifold hypothesis + perfect discriminator
- Manifold hypothesis: real data (images) lie on a low-dimensional manifold inside the huge ambient space \(\mathbb{R} ^{d}\). A random binary image is almost never meaningful (the "monkey-at-a-typewriter" problem).
- So the supports of \(P_{x}\) and \(P_{\theta }\) almost surely do not overlap.
- Perfect-discriminator theorem: with non-overlapping supports a discriminator can reach 100% accuracy ⇒ \(D_{f}\) becomes independent of θ ⇒ the generator gradient vanishes. Training saturates.
Swap the "hard" f-divergence for a softer metric that stays finite and differentiable even when supports are disjoint — the Wasserstein (Earth-Mover's) distance.
Wasserstein / Earth-Mover distance
Think of \(P_{x}\) and \(P_{\hat{x}}\) as piles of dirt. A transport plan \(\gamma (x,\hat{x})\) is a joint distribution (a table whose row-sums give one marginal, column-sums the other) telling you how much mass to move from each \(x\) to each \(\hat{x}\). The cost of a plan is the average distance mass travels; Wasserstein picks the cheapest plan.
Making it trainable: Kantorovich–Rubinstein duality
The primal min over all transport plans is intractable. Duality rewrites \(W_{1}\) as a maximisation over 1-Lipschitz functions — which a neural "critic" can represent:
Enforcing the 1-Lipschitz constraint — three methods, ranked
| Method | How | Verdict |
|---|---|---|
| Weight clipping | \(\| \omega \| \to\) clamp each step | Weak — under-uses capacity, causes vanishing/exploding gradients |
| Gradient penalty (WGAN-GP) | \(\lambda \mathbb{E} _{\hat{x}}(\| \nabla _{\hat{x}}f(\hat{x})\| _{2}-1)^{2}\) | Strong — penalises deviation from unit gradient norm |
| Spectral normalisation | bound each layer's spectral norm | Strong — bounds the Lipschitz constant per layer |
- 1.Weight clipping is the method that fails to properly enforce Lipschitz.
- 2.You update the critic several times per generator step to keep it near-optimal. Only a near-optimal critic gives an output that actually equals the Wasserstein distance — and only then can it point the generator in a useful direction to improve.
WGAN is also exact, not a lower bound.
Drill it — Wasserstein & transport
- It is finite and continuous even when supports are disjoint
- It is always zero for disjoint supports
- It upper-bounds the KL divergence
- It requires the supports to have the same dimensionality
- Weight clipping (capacity underuse, vanishing gradients)
- Gradient penalty via \(\lambda \mathbb{E} _{\hat{x}}(\| \nabla _{\hat{x}}D(\hat{x})\| _{2}-1)^{2}\)
- Spectral normalisation of each layer
- Directly constraining \(\| f(x_{1})-f(x_{2})\| \le \| x_{1}-x_{2}\|\)
› Reveal answer
JS is constant (log2) for disjoint supports → no gradient. \(W_{1}\) varies smoothly with how far apart the piles are. Weight clipping crudely caps weights, under-using capacity and re-introducing gradient problems.
- \(0.3\)
- \(9.0\)
- \(3.0\)
- \(0.9\)
› Reveal answer
\(10 \cdot (1.3 - 1)^{2} = 10 \cdot 0.09 = 0.9\). The penalty is zero exactly when the gradient norm is 1 (the Lipschitz sweet spot).
- \(0.20\)
- \(0.35\)
- \(0.55\)
- \(0.75\)
› Reveal answer
For two 1-D Gaussians with equal variance, \(W_{1} = |\mu _{r} - \mu _{g}| = |0.20 - 0.55| = 0.35\). (In general 1-D, \(W_{1}\) is the area between the CDFs.)
- \(\begin{bmatrix}0.25&0&0\\0.25&0&0\\0&0.3&0.2\end{bmatrix}\)
- \(\begin{bmatrix}0.2&0.05&0\\0.3&0&0\\0&0.25&0.25\end{bmatrix}\)
- \(\begin{bmatrix}0.1&0.1&0.05\\0.2&0.2&0.1\\0.2&0&0.1\end{bmatrix}\)
- \(\begin{bmatrix}0.3&0&0\\0.2&0.2&0.2\\0&0.1&0.3\end{bmatrix}\)
- \(1.1\)
- \(1.5\)
- \(0.8\)
- \(0.9\)
› Reveal answer
Method: a valid plan's i-th row sums to \(P_{i}\) and j-th column sums to \(Q_{j}\). Total transport cost is the element-wise product summed, \(\displaystyle \sum_{i,j} T_{ij}\, C_{ij}\). For Q185's \(T\) and \(C\) the only non-zero terms are \(T_{21}C_{21}=0.1\) and \(T_{32}C_{32}=0.2\), so the cost is \(0.3\) — but 0.3 isn't among the options, and the key marks 0.9. Like Q186's FID key, this one looks flawed; learn the method (\(\sum T_{ij}C_{ij}\)), not that number.
- A ·
for p in D.parameters(): p = torch.clamp(p, -0.01, 0.01) - B ·
for p in D.parameters(): p.data.clamp_(-0.01, 0.01) - C ·
torch.nn.utils.clip_grad_norm_(D.parameters(), 0.01)
› Reveal answer
A rebinds the local variable p and changes nothing. C clips gradients, not weights. Only B mutates the parameter tensor in place (note the trailing _ and .data).
- JSD saturates when the supports of \(P_{\mathrm{data}}\) and \(P_{g}\) do not overlap
- Generator gradients can vanish when the discriminator becomes too strong
- JSD is not continuous w.r.t. the generator's parameters
- JSD always provides unbiased gradients in high dimensions
› Reveal answer
The false option is "JSD always provides unbiased gradients in high dimensions" — the opposite of the truth.
GAN inversion & BiGAN
A trained generator maps \(Z \to X\). Inversion goes backwards — find the \(z\) for a given \(x\) — enabling feature extraction and semantic editing.
Why invert?
- Feature extraction: the recovered \(z\) vectors are compact features for downstream tasks.
- Editing: to edit an image, invert \(x_{i} \to z_{i}\), apply \(z_{\mathrm{edit}}=f_{\mathrm{edit}}(z_{i})\), then decode \(x_{\mathrm{edit}}=g_{\theta }(z_{\mathrm{edit}})\).
Three ways to make a GAN invertible:
① Bidirectional GAN (BiGAN)
Add an encoder \(E_{\phi }: X \to Z\). The twist: the discriminator no longer judges images alone — it judges (data, latent) pairs, learning the joint statistics.
(x, Eφ(x))x ~ Px
(gθ(z), z)z ~ 𝒩(0,I)
② Latent-regression inversion
Simpler: keep an ordinary GAN discriminator and bolt on an encoder trained to regress the latent back:
③ Inversion via optimisation
For a single target image and a frozen generator, just optimise the latent directly: \(z^{*} = \operatorname*{arg\,min} _{z} \| x - g_{\theta }(z)\| _{2}^{2}\).
Drill it — inversion
- \(\mathbb{E} _{x\sim p_{\mathrm{data}}}[\log D(x,E(x))] + \mathbb{E} _{z\sim p_{z}}[\log (1-D(G(z),z))]\)
- \(\mathbb{E} _{z\sim p_{z}}[\log D(G(z),z)] + \mathbb{E} _{x\sim p_{\mathrm{data}}}[\log (1-D(x,E(x)))]\)
- \(\mathbb{E} _{x\sim p_{\mathrm{data}}}[\log (1-D(x,E(x)))] + \mathbb{E} _{z\sim p_{z}}[\log (1-D(G(z),z))]\)
- \(\mathbb{E} _{x\sim p_{\mathrm{data}}}[\log D(x)] + \mathbb{E} _{z\sim p_{z}}[\log (1-D(G(z)))]\)
› Reveal answer
Objective: \(\mathbb{E} _{x}[\log D(x, E(x))] + \mathbb{E} _{z}[\log (1 - D(G(z), z))]\). The discriminator must learn joint statistics, not marginals — that's what makes the encoder a true inverse.
- D must distinguish fake and real with high confidence
- The composite maps \(G(E(x)) \approx x\) and \(E(G(z)) \approx z\) for all x, z
- The generator and encoder must share weights
- D must estimate a pixel-wise binary-mask loss
› Reveal answer
Marginal matching alone (\(P_{\theta }=P_{x}\)) is not enough — BiGAN's strength is matching the full joint.
- \(R_{\phi }(z) \approx x\) and \(g_{\theta }(x) \approx z\)
- \(z \approx R_{\phi }(x)\) and \(g_{\theta }(R_{\phi }(x)) \approx x\)
- \(D_{w}(x) \approx R_{\phi }(x)\)
- \(R_{\phi }(x)\) directly estimates \(p_{\theta }(x)\)
- \(z^{*} = \operatorname*{arg\,min} _{z} \| x - g_{\theta }(z)\| _{2}^{2}\)
- \(w^{*} = \operatorname*{arg\,max} _{w} D_{w}(x)\)
- \(\theta ^{*} = \operatorname*{arg\,min} _{\theta } \| x - g_{\theta }(z)\| ^{2}\) for random \(z\)
- \(x^{*} = \operatorname*{arg\,min} _{x} \| x - g_{\theta }(z)\| ^{2}\)
› Reveal answer
(b) freezes \(g_{\theta }\) and optimises the input \(z\) — not the weights \(\theta , \omega\), and not the image.
Adversarial domain adaptation
The same min–max, reused to make features domain-agnostic so a classifier trained on one domain works on another.
Domain shift: we have labelled source data \(D_{S}=\{(x_{i},y_{i})\}\sim P_{S}\) but must perform at test time on an unlabelled target \(D_{T}=\{\hat{x}_{j}\}\sim P_{T}\) with \(P_{S} \ne P_{T}\) (e.g. the PACS dataset: photo → sketch → cartoon → art). A vanilla classifier trained on \(P_{S}\) fails on \(P_{T}\).
Unsupervised Domain Adaptation (UDA): we want features that are good for classifying and look the same across domains. Three networks share the job:
- Feature extractor \(\phi\) — turns any input (source or target) into a feature vector \(f\).
- Label predictor \(h_{\psi }\) — reads a feature and predicts its class \(y\); trained only on the labelled source.
- Domain discriminator \(D_{\omega }\) — reads a feature and guesses which domain it came from (source or target).
The core trick: train \(\phi\) so the domain discriminator can't tell the two domains apart. If source and target features look identical, a classifier trained on source features automatically works on target features too.
CE = cross-entropy — the ordinary classification loss. It measures how far the predicted class probabilities \(h_{\psi }(f_{s})\) are from the true label \(y\); smaller means better predictions. Minimising it trains the label predictor (and the features feeding it) to classify the source correctly. Nothing GAN-specific — it's the same loss any classifier uses.
\(\phi\) is pulled two ways: the classifier wants features that separate the classes, but we also want features the domain discriminator cannot separate by domain. Plain back-prop of the domain loss would push \(\phi\) to help \(D_{\omega }\) — making the domains easier to tell apart, the opposite of the goal. The gradient-reversal layer (GRL) sits between \(\phi\) and \(D_{\omega }\): it does nothing on the forward pass, but on the backward pass it multiplies the gradient by \(-\lambda\). Flipping the sign turns \(\phi\)'s update into "make the domains harder to tell apart" — so the whole min–max trains with normal gradient descent in one backward pass. \(\lambda\) just controls how hard to push.
Because φ forces \(P_{f_{s}}=P_{f_{t}}\), the same head \(h_{\psi ^{*}}\) works on target data: \(ŷ_{\mathrm{test}} = h_{\psi ^{*}}(\phi ^{*}(\hat{x}_{\mathrm{test}}))\). If the domain classifier could still hit 100% accuracy, the features are misaligned — adaptation has failed.
- \([-1, 2]\)
- \([1, -2]\)
- \([-2, 4]\)
- \([0, 0]\)
- \([-2.1, 0.4]\)
- \([-2.2, -4.3]\)
- \([0.2, 0.1]\)
- \([0, 0]\)
› Reveal answer
GRL multiplies the incoming gradient by \(-\lambda\). (a) \(-0.5\cdot [2,-4]=[-1,2]\) ✓ matches the key. (b) \(-0.2\cdot [-1,-5]\) should give \([0.2, 1.0]\); the paper's marked option reads [0.2, 0.1], which is inconsistent with \(-\lambda \nabla\) (a likely source typo). Trust the rule \(-\lambda \cdot \nabla\), not that one option.
- The domains are perfectly aligned
- The classifier is overfitting
- The domains are misaligned
- Nothing can be inferred
› Reveal answer
Perfect separability of features means φ has not made them domain-invariant — the opposite of the goal.
Evaluation — Fréchet Inception Distance
How good is a trained generator? FID measures the Wasserstein-2 distance between real and generated features, assuming both are Gaussian.
Procedure: push real data \(D_{\mathrm{true}}\) and generated data \(D_{\mathrm{gen}}\) through a pretrained Inception-v3 (trained on ImageNet); take activations from the penultimate layer; fit a Gaussian to each set (mean + covariance); then measure the closed-form Wasserstein-2 distance between the two Gaussians.
For 1-D features, \(FID = (\mu _{r}-\mu _{g})^{2} + (\sigma _{r}-\sigma _{g})^{2}\). The covariance term collapses to \(\sigma _{r}^{2}+\sigma _{g}^{2}-2\sigma _{r}\sigma _{g}=(\sigma _{r}-\sigma _{g})^{2}\).
Drill it — FID
› Reveal answer
Mean term: \(\| [-1,-2]\| ^{2} = 1+4 = 5\). Covariance term: \(\Sigma _{r}\Sigma _{g}=4I \Rightarrow (\Sigma _{r}\Sigma _{g})^{1/2}=2I\), so \(\operatorname{Tr} (I+4I-4I)=\operatorname{Tr} (I)=2\) (in 2-D). Total \(= 5+2 = 7\). The official key states 6 — a likely errata; know the method and you're safe either way.
- \(1\)
- \(2\)
- \(3\)
- \(5\)
› Reveal answer
\((0-1)^{2} + (2-1)^{2} = 1 + 1 = 2\).
- 1st = mean/bias shift; 2nd = covariance mismatch
- Both terms measure covariance only
- Both terms are dominated by the generator's variance
- 1st = variance difference; 2nd = mean shift
- The output logits of the generator
- Raw RGB pixel values
- The first convolution layer of the discriminator
- The penultimate layer of an Inception-v3 network
- If means & covariances are equal, FID is negative
- FID is non-negative and equals 0 when distributions are identical
- FID can be undefined if \(\Sigma _{r}\) is not positive definite
- FID equals the KL divergence between the distributions
› Reveal answer
FID is not a KL divergence and cannot be negative; it is undefined only in degenerate covariance cases, not "when \(\Sigma _{r}\) isn't positive definite" as a trap option claims.
Worked derivations
The two results the course leans on hardest — proved line by line — plus two short ones worth reproducing under exam pressure. Each step pairs the algebra with the reason it is allowed.
① The variational lower bound of an f-divergence
The engine of the whole f-GAN / VDM framework. It converts an intractable integral over a density ratio into a supremum of two expectations — which the Law of Large Numbers lets us estimate from samples.
② The optimal discriminator → Jensen–Shannon divergence
The classic result that explains what a GAN actually minimises. Two parts: first solve for the best discriminator, then substitute it back into the value function.
-
\(\displaystyle V(G,D) = \int _{X} \bigl[ P_{x}(x) \log D(x) + P_{\theta }(x) \log (1-D(x)) \bigr] dx\)Write both expectations of the GAN objective as integrals and combine under one integral sign.
-
\(g(d) = a\cdot \log d + b\cdot \log (1-d)\), \(a=P_{x}(x)\), \(b=P_{\theta }(x)\)The integrand is a sum of independent pointwise terms, so maximising the integral = maximising each term separately over its value \(d=D(x)\in (0,1)\).
-
\(\displaystyle g'(d) = \frac{a}{d} - \frac{b}{1-d} = 0 \Rightarrow a(1-d) = b\cdot d\)First-order condition. Rearranging: \(a = d(a+b)\). The second derivative \(g''<0\), so this is a maximum.
-
\(\displaystyle D^{*}(x) = \frac{a}{a+b} = \frac{P_{x}(x)}{P_{x}(x)+P_{\theta }(x)}\)The optimal discriminator is the posterior probability that \(x\) is real. (At \(P_{x}=P_{\theta }\) it equals \(\tfrac{1}{2}\) — the discriminator is maximally confused.)
-
\(\displaystyle V(G,D^{*}) = \int P_{x} \log \bigl(\frac{P_{x}}{P_{x}+P_{\theta }}\bigr) + P_{\theta } \log \bigl(\frac{P_{\theta }}{P_{x}+P_{\theta }}\bigr) dx\)Substitute \(D^{*}\) (and \(1-D^{*} = P_{\theta }/(P_{x}+P_{\theta })\)) into \(V\).
-
\(\displaystyle m \triangleq \frac{P_{x}+P_{\theta }}{2} \Rightarrow \frac{P_{x}}{P_{x}+P_{\theta }} = \frac{1}{2}\cdot \frac{P_{x}}{m}\)Introduce the mixture \(m\). Since \(P_{x}+P_{\theta }=2m\), each argument gains a factor \(\tfrac{1}{2}\).
-
\(\displaystyle V = \int P_{x}\bigl[\log \frac{P_{x}}{m} - log2\bigr] + P_{\theta }\bigl[\log \frac{P_{\theta }}{m} - log2\bigr] dx\)\(\log (\tfrac{1}{2} \cdot P_{x}/m) = \log (P_{x}/m) - log2\). Pull the constant \(-log2\) out of each bracket.
-
\(\displaystyle V = \int P_{x} \log \frac{P_{x}}{m} dx + \int P_{\theta } \log \frac{P_{\theta }}{m} dx - log2\cdot \int (P_{x}+P_{\theta }) dx\)Split the integral. The last piece: \(\displaystyle \int P_{x}=\int P_{\theta }=1\), so \(\displaystyle \int (P_{x}+P_{\theta })dx = 2\).
-
\(V = D_{\mathrm{KL}}(P_{x}\| m) + D_{\mathrm{KL}}(P_{\theta }\| m) - 2 \log 2\)The first two integrals are exactly KL divergences to the mixture. And \(2log2 = log4\).
-
\(V(G,D^{*}) = 2\cdot JSD(P_{x}\| P_{\theta }) - \log 4\)By definition \(JSD = \tfrac{1}{2} D_{\mathrm{KL}}(P_{x}\| m) + \tfrac{1}{2} D_{\mathrm{KL}}(P_{\theta }\| m)\), so the two KL terms sum to \(2\cdot JSD\). Since \(JSD \ge 0\) (=0 ⇔ \(P_{x}=P_{\theta }\)), the generator's global optimum is \(V = -log4\), reached exactly when \(P_{\theta }=P_{x}\). So a GAN minimises the JSD.
③ Two quick ones worth memorising
- \(f^{*}(t) = \sup _{u>0} \{ t\cdot u - u \log u \}\)Definition of the conjugate.
- \(\displaystyle \frac{d}{du}[tu - u \log u] = t - \log u - 1 = 0\)Stationarity ⇒ \(\log u = t-1 \Rightarrow u^{*} = e^{t-1}\).
- \(f^{*}(t) = t\cdot e^{t-1} - e^{t-1}(t-1) = e^{t-1}\)Substitute \(u^{*}\) back; the \(t\)-terms cancel.
- \(\operatorname{Tr} (\Sigma _{r}+\Sigma _{g}-2(\Sigma _{r}\Sigma _{g})^{1/2})\)In 1-D, \(\Sigma _{r}=\sigma _{r}^{2}\), \(\Sigma _{g}=\sigma _{g}^{2}\) are scalars; the trace is the identity.
- \((\Sigma _{r}\Sigma _{g})^{1/2} = (\sigma _{r}^{2}\sigma _{g}^{2})^{1/2} = \sigma _{r}\sigma _{g}\)Since \(\sigma \ge 0\) the square root is exact.
- \(\sigma _{r}^{2} + \sigma _{g}^{2} - 2\sigma _{r}\sigma _{g} = (\sigma _{r}-\sigma _{g})^{2}\)A perfect square ⇒ \(FID = (\mu _{r}-\mu _{g})^{2} + (\sigma _{r}-\sigma _{g})^{2}\).
You are rarely asked to reproduce a full proof, but the individual lines are the MCQs: "what is the optimal \(D^{*}\)?", "what does \(V(G,D^{*})\) equal?", "what is \(f^{*}(t)\) for KL?", "why is the variational form a lower bound?". Knowing the derivation means every one of those is automatic.
Formula cheat sheet
Every formula the exam has asked, on one screen. If you can reproduce these from memory, you're ready.
f-divergence
KL: u log u · rev-KL: −log u · TV: ½|u−1|
Fenchel conjugate
For u log u: f*(t) = e^{t−1}
Variational bound (f-GAN)
Any T ⇒ a valid lower bound
GAN objective
D = sigmoid(logit)
Optimal discriminator
V(G,D*) = −log4 + 2·JSD
Conditional GAN
Label y into both nets
Wasserstein (primal)
γ = transport plan (marginals fixed)
WGAN (dual)
1-Lipschitz critic, no sigmoid
WGAN-GP penalty
Best Lipschitz enforcement
BiGAN
Discriminator on joint pairs
Domain adversarial
GRL multiplies gradient by −λ
FID
1-D: (Δμ)²+(Δσ)². Lower = better
Night-before recall list
Tick each one off out loud. If any makes you hesitate, jump back to its section.
- The 3-step recipe: family → divergence → argmin
- \(f(u)\) for KL, reverse-KL, TV — and \(f^*(t)=e^{t-1}\) for KL
- Wasserstein is NOT an f-divergence
- Variational bound is a lower bound (any T works)
- GAN objective with sigmoid D — write it blind
- \(D^* = P_x/(P_x+P_\theta)\); value \(= -\log 4 + 2\cdot\mathrm{JSD}\)
- Disjoint supports ⇒ value = 0, gradients vanish
- Non-saturating loss \(-\log\sigma(a)\) beats minimax
- Manifold hypothesis + perfect-discriminator theorem
- Wasserstein primal (transport plan) & K–R dual
- Weight clipping FAILS; GP / spectral-norm work
- Multiple critic steps per generator step, and why
p.data.clamp_(-0.01, 0.01)is the in-place clip- Backward accumulates grad → need zero_grad()
- BiGAN judges (x, E(x)) vs (G(z), z) pairs
- Inversion by optimisation: \(z^* = \arg\min\|x-g(z)\|^2\)
- GRL multiplies gradient by \(-\lambda\)
- FID formula + 1-D shortcut; lower is better
- FID features: penultimate layer of Inception-v3
- Param count: \(\Sigma\) of consecutive layer-size products
It's the story of turning "measure the distance between two distributions you can only sample from" into "train two networks against each other" — f-divergence → variational bound → GAN → (instability) → Wasserstein → inversion/adaptation → FID. Every question is a checkpoint on that one road.