GANs: the forger and the detective
How does a generator learn by competing against a critic?
Lesson complete
If you like:
A forger paints fake bills and a detective tries to spot them. Every time the detective catches one, the forger learns to paint better.
No voice: the lesson advances on its own with subtitles.
The voice for this lesson is being recorded: for now it advances on its own with subtitles.
Review modeComment on this stepI finished the lesson
What you will achieve
- Explain what the generator does (turns a randomly drawn number into a fake data point) and what the discriminator does (estimates how likely a data point is to be real).
- Describe adversarial training as a turn-based game and recognize its ideal end: the discriminator answers 0.5 because it can no longer tell.
- Recognize mode collapse and instability in a real training run, and explain why diffusion took the lead in images.
Key ideas
- A GAN is two competing networks: the generator turns a randomly drawn number into a fake data point; the discriminator estimates how likely a data point is to be real.
- The generator never sees the real data: it learns only through the discriminator’s answer, moving its fakes toward where the discriminator says “more real.”
- The ideal end is a tie: the discriminator answers 0.5 to everything because it can no longer tell. The lesson’s GAN gets close, though not all the way.
- Mode collapse (producing only part of the variety) and instability are its typical problems: with one setting changed, four of twenty matches collapsed.
- Diffusion took the lead in images (Dhariwal and Nichol, 2021) because it trains stably and covers the variety better; GANs are still faster at generating.
What many people believe
Common belief A GAN’s generator learns by copying the real data it is shown.
What is true The generator never sees a real data point. It only receives random numbers and the discriminator’s answer, and adjusts its weights so that answer becomes “real.” Only the discriminator sees the real data.
Check yourself
Four questions. No grade, no account: they just show whether the idea stuck.
Under the hoodFor those who want the math and the code. You do not need it to follow the course.
The game in one formula
The generator takes noise (in the lesson, the standard bell) and produces . The discriminator returns , the probability it assigns to coming from the data. Goodfellow et al. (2014) set up a two-player minimax game:
raises by saying “1” to real data and “0” to fakes (it is the cross-entropy of a binary classifier, with the sign flipped); lowers it by pushing toward 1. What one gains, the other loses: it is a zero-sum game.
The best possible detective, and the tie
With fixed, the optimal discriminator is
where is the distribution of the fakes. If a region holds two fakes for every real point, the best answer there is . That is what the collapsing match measures: on the left mountain (all the fakes and half the real data) the detective answers between 0.32 and 0.35; on the right, where there are no fakes, 1.00. The paper proves the game’s global optimum is at , with everywhere. There the detective’s loss equals and the generator’s (non-saturating version, below) ; over the last two hundred steps of the lesson’s healthy match they average 1.384 and 0.702.
The non-saturating trick and the steps
Early on, rejects fakes with high confidence and saturates: it gives almost no gradient. So the same paper proposes that maximize instead, which has the same fixed point and stronger gradients early on. The lesson uses it. The gradient that corrects flows through (backpropagation through both networks, lesson 8): for each fake, says which way to move it. The arrows in the scene are that derivative, computed from the detective’s real curve.
Algorithm 1 alternates steps of with one of ; the authors used . In the lesson, is the only hyperparameter that changes: with , all 20 seeds cover both mountains; with , 15 cover them, 4 collapse (one mountain gets under 5% of the fakes), and one ends up halfway (48% and 6%). The paper warns about the opposite imbalance, training too much without updating , which it calls “the Helvetica scenario”: sends too many values of to the same . Either way, the balance between the players matters.
The lesson’s GAN
- Data: a 50/50 mix of and . The scene’s 800 real points are quantiles of each bell, and the generator’s 800 draws are quantiles of , so every histogram is reproducible.
- Networks: and are identical, (141 parameters each). Adam with rate and , batches of 256, 2,000 generator steps. The weights were exported quantized to 16 bits and the browser runs the networks (forward pass only); the scripts
train_gan.pyandtrain_detective.pyare in the lesson folder. - The detective alone: to present it separately, the healthy match’s initial detective was trained for 1,000 steps against the frozen initial forger (everything near 0). It answers 0.95 to 1.6 and 0.05 to 0.07.
- “Near a mountain”: within 0.8 of its center. Real data: 47.75% in each. Fakes at the end of the healthy match: 46.4% and 48.1%.
- What did not come out perfect: the fake mountains are narrower (the tallest packs 337 of the 800 fakes into one 0.25-wide stretch; the real one, 98), and a bridge of fakes remains in the valley. The bridge is unavoidable with this design: is a continuous function of a single number, so the values near 0 land between the two mountains. There . The detective, small and trained at the same pace, does not detect the narrowness.
In code
import torch, torch.nn as nn
torch.manual_seed(0)
def net(): # 1 → 10 → 10 → 1, with tanh: 141 parameters
return nn.Sequential(nn.Linear(1, 10), nn.Tanh(), nn.Linear(10, 10), nn.Tanh(), nn.Linear(10, 1))
def real(n): # 50/50 mix of N(−1.5, 0.4²) and N(+1.5, 0.4²)
sign = torch.randint(0, 2, (n, 1)) * 2 - 1
return 1.5 * sign + 0.4 * torch.randn(n, 1)
G, D = net(), net() # forger and detective
opt_G = torch.optim.Adam(G.parameters(), lr=5e-4, betas=(0.5, 0.999))
opt_D = torch.optim.Adam(D.parameters(), lr=5e-4, betas=(0.5, 0.999))
bce = nn.BCEWithLogitsLoss() # applies the sigmoid and computes −log
one, zero = torch.ones(256, 1), torch.zeros(256, 1)
for step in range(2000):
# detective’s turn: it should say 1 to real data and 0 to fakes
fakes = G(torch.randn(256, 1)).detach()
loss_D = bce(D(real(256)), one) + bce(D(fakes), zero)
opt_D.zero_grad(); loss_D.backward(); opt_D.step()
# forger’s turn: make the detective say “real” to its fakes
loss_G = bce(D(G(torch.randn(256, 1))), one)
opt_G.zero_grad(); loss_G.backward(); opt_G.step()
with torch.no_grad():
x = G(torch.randn(10000, 1))
left = ((x + 1.5).abs() < 0.8).float().mean().item()
right = ((x - 1.5).abs() < 0.8).float().mean().item()
print(f'fakes near each mountain: {left:.2f} and {right:.2f}')
dr, df = torch.sigmoid(D(real(10000))).mean().item(), torch.sigmoid(D(x)).mean().item()
print(f'detective, on average: real {dr:.2f}, fakes {df:.2f}')
# fakes near each mountain: 0.47 and 0.48
# detective, on average: real 0.50, fakes 0.50
(PyTorch 2.11 on CPU; another version may give slightly different figures.)
What comes next
GANs dominated high-quality image generation until Dhariwal and Nichol (2021) showed that diffusion models beat them. They themselves point out that GANs capture less diversity and are hard to train, “collapsing without carefully selected hyperparameters and regularizers,” while diffusion offers distribution coverage, a stationary training objective (it does not depend on a changing rival), and easy scalability; its drawback is slower generation, in many noise-removal steps. That is lesson 17.
Decision lens
What this idea means if your job is to decide, not to code.
- The human eye is no longer a reliable detector: in Nightingale and Farid’s study (2022), 315 people were right 48.2% of the time when separating real faces from faces made with StyleGAN2, and with training and feedback they reached only 59.0%. Verifying authenticity takes provenance and tools, not intuition.
- If a vendor generates synthetic data (for training or testing), ask how they measured variety: mode collapse can erase exactly the rare cases that matter most, without the samples “looking bad.”
- Training a GAN is fragile: ask for results across several runs and seeds, not a single demo. In the lesson, changing one setting made four of twenty matches collapse.
- Choose by use: diffusion gives more quality and variety but generates in many steps; a GAN generates in a single pass, useful when speed rules (real time, small devices).
Terms in this lesson
- GAN (generative adversarial network) A generative model made of two networks trained by competing: a generator that produces fake data and a discriminator that tries to tell it apart from real data (Goodfellow et al., 2014).
- Generator In a GAN, the network that turns a randomly drawn number (or vector) into a fake data point. It never sees the real data: it learns from the discriminator’s answer.
- Discriminator In a GAN, the network that receives a data point and estimates, between 0 and 1, how likely it is to be real rather than from the generator. At the ideal tie it answers 0.5.
- Mode collapse A typical GAN failure: the generator produces only part of the variety in the data (for example, just one of several “mountains” or a single kind of image).
- Generative model A model that learns the distribution of its data (what is common, what is rare) and can therefore produce new, similar data. A model that classifies, by contrast, only learns the boundary between groups.
- Distribution The way the data is spread out: which values (or combinations of values) are common, which are rare, and which never appear. With two measures it looks like a cloud of points.
- Sampling Drawing a new data point that follows a distribution: common things come out often and rare things seldom. It is how a generative model generates. (Not to be confused with the audio samples of lesson 2.)
- Sigmoid The function σ(z) = 1/(1 + e⁻ᶻ): it turns any number into a value between 0 and 1, and equals 0.5 when z = 0.
- Gradient descent A method that adjusts the weights step by step, always against the slope of the error (the gradient), until it reaches a bottom.
- Backpropagation An algorithm that computes the gradient of the loss with respect to every weight of a network in a single backward sweep, applying the chain rule layer by layer. It computes the blames; it does not move the weights (in the 1986 paper, the name covered the whole learning procedure).
- Batch A small set of examples, picked at random, used to estimate the gradient in one training step.
- Hyperparameter A setting a person fixes for training (rate, batch size, epochs, optimizer, schedule). It is not learned with gradients.
- Loss function A single number that summarizes how wrong a model is on its data. Training is the search for the parameters that make it as small as possible.
- Weight (w) In a linear model, the number that multiplies the input: the slope of the line. It tells how much the prediction rises for each unit the input grows.
- Diffusion model A generative model that learns to undo a fixed process that mixes data with noise step by step (the forward process). It generates by starting from pure static and removing a little estimated noise, many times.
Full transcript
Sources
- Goodfellow, I. J., Pouget-Abadie, J., Mirza, M., Xu, B., Warde-Farley, D., Ozair, S., Courville, A., Bengio, Y. (2014). Generative Adversarial Networks (arXiv 1406.2661; NeurIPS 2014)
- Goodfellow, I. (2016). NIPS 2016 Tutorial: Generative Adversarial Networks (arXiv 1701.00160)
- Dhariwal, P., Nichol, A. (2021). Diffusion Models Beat GANs on Image Synthesis (arXiv 2105.05233; NeurIPS 2021)
- Nightingale, S. J., Farid, H. (2022). AI-synthesized faces are indistinguishable from real faces and more trustworthy (PNAS 119(8), e2120481119)
- Karras, T., Laine, S., Aittala, M., Hellsten, J., Lehtinen, J., Aila, T. (2020). Analyzing and Improving the Image Quality of StyleGAN (arXiv 1912.04958; CVPR 2020)
CommentsThis lesson’s public conversation: questions, facts to check, ideas.
Comments live in GitHub Discussions, in the course’s public repository; writing one requires a GitHub account. They load from giscus.app when you open this section. The course reviewers read them, and if a change is accepted, it is applied in both languages. Open the thread on GitHub