GANs from DCGAN to StyleGAN
Losses, DCGAN code, Pix2Pix, CycleGAN and StyleGAN. Defaults, failure signatures and fixes.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Comparisons
- Defaults and numbers
- Troubleshooting
- Questions and tips
StyleGAN generator#
One training step#
Losses and formulas#
- Minimax
- \min_G \max_D \; \mathbb{E}_x[\log D(x)] + \mathbb{E}_z[\log(1 - D(G(z)))]
- D loss
- binary cross-entropy with real = 1 and fake = 0.
- G loss
- -\log D(G(z)). This is the non-saturating form.
- WGAN
- \text{loss}_D = \mathbb{E}[D(\text{fake})] - \mathbb{E}[D(\text{real})], \text{loss}_G = -\mathbb{E}[D(\text{fake})]
- Pix2Pix G
- -\log D(x, G(x)) + \lambda \cdot \lVert y - G(x) \rVert_1
- Cycle
- F(G(x)) \approx x and G(F(y)) \approx y.
- AdaIN
- y_{\text{scale}} \cdot \frac{x - \mathrm{mean}(x)}{\mathrm{std}(x)} + y_{\text{bias}}
- Truncation
- w' = \hat{w} + \psi \cdot (w - \hat{w}). \psi < 1 trades diversity for quality.
DCGAN train_step#
opt_d.zero_grad()d_real = D(real)logits, sigmoid only in the lossd_fake = D(G(z).detach())no gradient flows into Gloss_d = (F.binary_cross_entropy_with_logits(d_real, torch.ones_like(d_real)) + F.binary_cross_entropy_with_logits(d_fake, torch.zeros_like(d_fake)))loss_d.backward()opt_d.step()opt_g.zero_grad()d_fake = D(G(z))second pass keeps the graphloss_g = F.binary_cross_entropy_with_logits(d_fake, torch.ones_like(d_fake))loss_g.backward()non-saturating G lossopt_g.step()Tasks in code#
| Task | Code |
|---|---|
| Build the generator | Generator(z_dim= |
| Wrap a D conv in SN | spectral_norm(c) |
| Make the optimizers | Adam(lr= |
| Sample in eval mode | sample(G, |
| Count parameters | sum(p.numel() for p in G.parameters()) |
| Condition G or D | inp = |
| Map z to w | w = |
| Truncate w | w_bar[i] + psi * (w_test[i] - w_bar[i]) |
One pass against many steps#
| Factor | Pix2Pix | SD-Img2Img | SDXL-Turbo | ControlNet + SDXL |
|---|---|---|---|---|
| Steps | 1 | 20 | 1-4 | 20-30 |
| 512² on one L4 | ~30 ms | ~1.2 s | ~0.15-0.35 s | ~3-5 s |
Use X when#
- GAN real-time generation under 10 ms, style transfer, image-to-image translation.
- StyleGAN3 photoreal human faces with a fixed pose.
- Pix2Pix thousands of paired examples, a narrow task and fast inference.
- CycleGAN image translation with no paired data.
- Frozen mapping network domain adaptation from a few images.
- Diffusion or flow matching anything multi-modal or open-ended.
Four GANs side by side#
| Factor | DCGAN | Pix2Pix | CycleGAN | StyleGAN |
|---|---|---|---|---|
| Input | noise z | image x, dropout as noise | image from domain X | z mapped to w |
| Generator | transposed convs, tanh out | U-Net with skips | G: X to Y and F: Y to X | constant plus AdaIN per block |
| Extra loss | none | λ times L1 | cycle consistency | path-length reg in StyleGAN2 |
| Data | images only | paired (x, y) | unpaired | narrow domain, faces |
| Use for | 32x32 baseline | sketch to photo | horses to zebras, seasons | photoreal faces, editing |
Defaults#
| Setting | Default | Note |
|---|---|---|
Adam lr | 2e-4 | DCGAN default for G and D |
Adam betas | (0.5, 0.999) | Low beta1 |
z_dim | 64 | Noise for the 32x32 DCGAN |
| D LeakyReLU slope | 0.2 | All D layers |
| Pix2Pix λ on L1 | 100 | Start here, anneal down |
| PatchGAN field | ~70×70 | Pixels per output cell |
| Truncation ψ | 0.7 | Use 1.0 for diversity |
| TTUR ratio | 2-4 | D learns faster than G |
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
| D loss low, G loss oscillates, variety drops | Mode collapse | Minibatch discrimination, spectral norm, labels |
| D accuracy ~100%, G loss huge and static | D wins | Smaller D, lower D learning rate, label smoothing |
| Both losses swing with no trend | Oscillation | TTUR or Wasserstein loss |
| D above 95% accuracy | D too strong | Cut D learning rate by 2-5x |
| One real mode never appears | G memorizes a mode | Noise on D inputs, or WGAN-GP |
| Output ignores the condition | Weak condition signal in D | Condition D early, projection D |
| Blurry Pix2Pix output | L1 weight too high | Anneal λ down once stable |
| Droplet artifacts | AdaIN zeroes the mean | Weight demodulation of StyleGAN2 |
Terms#
- DCGAN
- strided convs, batch norm, ReLU in G, LeakyReLU in D.
- WGAN-GP
- Wasserstein distance plus gradient penalty.
- SN
- spectral norm. Bounds the Lipschitz constant of each D layer.
- TTUR
- two-timescale update rule. Two learning rates.
- cGAN
- conditional GAN. G(z, c) and D(x, c) both see the condition.
- PatchGAN
- D outputs an N × N grid of per-patch scores.
- AdaIN
- adaptive instance norm. Normalize, then scale and shift by w.
- FID
- Fréchet Inception Distance. Lower is better.
Questions#
- Why
G(z).detach()in the D step? - It stops gradients into G during the D update.
- Why the non-saturating loss?
- Early on
D(G(z))is near zero. The original G loss then has vanishing gradients. - Why switch to eval mode before sampling?
- Batch norm then uses running stats.
- Why does D see the pair (x, y)?
- Without x, D cannot check consistency.
- Why does StyleGAN still ship?
- One forward pass. Under 10 ms for a 1024² face on a 4090.
- Can a GAN give p(x)?
- No. It is an implicit density model. It only samples.