Generative Models
Chapter: 4.5 Generative Models Difficulty: Level 3 — Production (from-scratch derivations, code-from-memory, explain-out-loud) Time limit: 45 minutes Total marks: 60
Question 1 — ELBO Derivation from Scratch (12 marks)
Starting from the marginal log-likelihood with latent variable and an approximate posterior :
(a) Derive the Evidence Lower Bound (ELBO), showing every algebraic step, and prove that . (6)
(b) Explain why maximizing the ELBO is a valid surrogate for maximizing , and what the gap between them represents. (3)
(c) Write the ELBO in its "reconstruction + regularization" decomposed form and name each term. (3)
Question 2 — Reparameterization Trick (10 marks)
(a) For a Gaussian posterior , write the reparameterized sample in terms of , and a noise variable . State the distribution of . (3)
(b) Explain out loud (in words) why the naive Monte-Carlo gradient is problematic to estimate, and how reparameterization fixes it. (4)
(c) Derive the closed-form KL term for a single dimension. (3)
Question 3 — GAN Objective & Optimal Discriminator (12 marks)
Given the minimax GAN value function
(a) Derive the optimal discriminator for a fixed generator . (5)
(b) Substitute back into and show the generator objective reduces to . (5)
(c) From this result, explain why mode collapse and vanishing generator gradients can occur, and one concrete fix (e.g. WGAN). (2)
Question 4 — DDPM Forward Process (10 marks)
The DDPM forward process is .
(a) Derive the closed-form marginal in terms of . Show the recursion collapse. (6)
(b) Write as a reparameterized function of and . (2)
(c) State what happens to as and why this matters for sampling. (2)
Question 5 — Code from Memory: VAE Loss (8 marks)
Write a PyTorch-style function vae_loss(x, x_recon, mu, logvar) that returns the negative ELBO (reconstruction + KL). Use logvar . Assume binary cross-entropy reconstruction. Comment each line explaining the term it implements. (8)
Question 6 — Explain Out Loud: Evaluation & Guidance (8 marks)
(a) Explain the Fréchet Inception Distance (FID) formula and what each of its two terms measures. Why is lower better? (4)
(b) Explain classifier-free guidance: write the guided noise prediction combining conditional and unconditional predictions, and describe the effect of the guidance scale . (4)
Answer keyMark scheme & solutions
Question 1 (12 marks)
(a) Start with marginal, multiply/divide by : (6) By Jensen's inequality (log is concave): (1) Exact identity: write : (2)
(b) Since , ELBO always (1). Maximizing ELBO pushes the lower bound up; the true posterior is intractable so we can't optimize likelihood directly (1). The gap equals the KL between approximate and true posterior — tightness of the bound; zero gap means matches the true posterior exactly (1).
(c) (3) Reconstruction rewards accurate decoding; KL keeps latent code close to prior (1).
Question 2 (10 marks)
(a) , where . (3)
(b) The expectation is over which depends on ; the sampling operation is not differentiable w.r.t. (2). The score-function/REINFORCE estimator works but has high variance (1). Reparameterization moves stochasticity to (independent of ), making a deterministic differentiable function of , so passes through and gives a low-variance pathwise estimator (1).
(c) Single-dim KL: (3) (Steps: expand log-ratio, take Gaussian moments , .)
Question 3 (12 marks)
(a) For fixed , maximize integrand pointwise: (5) For , set derivative . So
(b) Substitute: (5) Add/subtract in each: Global minimum when , giving .
(c) When supports don't overlap, JS is constant → gradient vanishes, generator gets no signal → mode collapse (generator maps to few modes to fool ) (1). Fix: WGAN uses Earth-Mover distance (with weight clipping / gradient penalty) giving smooth, non-vanishing gradients everywhere (1).
Question 4 (10 marks)
(a) Let . Recursively: (6) Substitute : Sum of two independent Gaussians → variance adds: (2). Repeating:
(b) . (2)
(c) As , so — independent of (1). This lets sampling begin from pure Gaussian noise then run the learned reverse process (1).
Question 5 (8 marks)
import torch.nn.functional as F
def vae_loss(x, x_recon, mu, logvar):
# reconstruction term: -E[log p(x|z)] via BCE, summed over pixels
recon = F.binary_cross_entropy(x_recon, x, reduction='sum')
# KL(N(mu,sigma^2)||N(0,1)) = 0.5*sum(mu^2 + sigma^2 - logvar - 1)
kl = 0.5 * torch.sum(mu.pow(2) + logvar.exp() - logvar - 1)
# negative ELBO = reconstruction + KL regularizer
return recon + klMarks: correct BCE recon (2), correct KL formula matching Q2c (3), sign/sum correct (2), comments (1).
Question 6 (8 marks)
(a) FID: (4) Computed on Inception activations. First term = squared distance between mean feature vectors (measures difference in average content) (1); second term = covariance mismatch (measures difference in feature diversity/spread) (1). It is the Fréchet (Wasserstein-2) distance between two Gaussians fit to real/generated features (1). Lower = generated distribution closer to real → better quality & diversity (1).
(b) Guided prediction: (4) = unconditional prediction (condition dropped during training) (1); the difference is the "conditional direction" (1). → unconditional; → standard conditional; amplifies conditioning → sharper prompt adherence but reduced diversity / possible artifacts (2).
[
{"claim": "KL(N(mu,sigma^2)||N(0,1)) = 0.5*(mu^2+sigma^2-log(sigma^2)-1)",
"code": "mu,s=symbols('mu s',positive=True); z=symbols('z'); import sympy as sp; p=1/sp.sqrt(2*pi*s**2)*sp.exp(-(z-mu)**2/(2*s**2)); q=1/sp.sqrt(2*pi)*sp.exp(-z**2/2); kl=sp.integrate(p*sp.log(p/q),(z,-oo,oo)); target=sp.Rational(1,2)*(mu**2+s**2-sp.log(s**2)-1); result=sp.simplify(kl-target)==0"},
{"claim": "Optimal GAN value equals -log4 + 2*JSD at p_g=p_data i.e. min value = -log(4)",
"code": "a=symbols('a',positive=True); Dstar=a/(a+a); val=a*sp.log(Dstar)+a*sp.log(1-Dstar); result=sp.simplify(2*val - (-sp.log(4)))==0"},
{"claim": "DDPM variance recursion: alpha_t*(1-alpha_{t-1})+(1-alpha_t) = 1-alpha_t*alpha_{t-1}",
"code": "at,a1=symbols('at a1'); lhs=at*(1-a1)+(1-at); rhs=1-at*a1; result=sp.simplify(lhs-rhs)==0"},
{"claim": "Classifier-free guidance at w=1 reduces to conditional prediction",
"code": "e_c,e_u,w=symbols('e_c e_u w'); g=e_u+w*(e_c-e_u); result=sp.simplify(g.subs(w,1)-e_c)==0"}
]