Generative Adversarial Networks Generator vs Discriminator Competition

# Generative Adversarial Networks: Generator vs Discriminator Competition

## Introduction & Motivation

GANs: generator and discriminator compete. Generator: learn to fool discriminator; generate realistic samples. Discriminator: distinguish real from fake. Adversarial loss: minimax game. Applications: image synthesis, style transfer, image-to-image translation, data augmentation.

Motivation: Supervised: need paired data. GANs: unsupervised; learn from real data distribution.

Applications: Image generation, style transfer, data augmentation.

---

## Core Concepts & Theory

### Generator

Transforms noise → samples; learns data distribution.

### Discriminator

Classifies real vs fake; provides learning signal.

### Adversarial Game

Minimax: generator minimizes discriminator advantage.

---

## Mathematical Formulation

GAN objective:
$$\min_G \max_D \mathbb{E}_x[\log D(x)] + \mathbb{E}_z[\log(1 - D(G(z)))]$$

Generator loss (practical):
$$L_G = -\mathbb{E}_z[\log D(G(z))]$$

Discriminator loss:
$$L_D = -\mathbb{E}_x[\log D(x)] - \mathbb{E}_z[\log(1 - D(G(z)))]$$

---

## Advanced Theory & Extensions

### Wasserstein GAN (WGAN)

Wasserstein distance; more stable training; gradient penalty.

### Conditional GAN

Class-conditional generation; control output.

### StyleGAN

Learned style mixing; progressive growing.

---

## Computational Considerations

Generator: O(forward + backward) per batch.

Discriminator: O(2·forward + backward) real + fake.

Training: Alternating updates; typically 1 D : 1 G step.

---

## Practical Implementation Strategies

### Training Stability

Balance G/D strength; careful learning rates.

### Spectral Normalization

Stabilize discriminator; prevent vanishing gradients.

### Progressive Growing

Start small, gradually increase resolution.

---

## Benchmark Datasets & Evaluation

CIFAR-10: Standard benchmark; Inception Score ~8.0.

CelebA: Faces; FID ~5-10 for good models.

ImageNet: Large-scale; resolution 256×256+.

---

## Key Challenges & Limitations

### Mode Collapse

Generator ignores modes; produces limited diversity.

### Training Instability

Careful balancing required; hyperparameter sensitive.

### Evaluation Difficulty

No single metric; Inception Score, FID, human evaluation.

---

## Hyperparameter Tuning

Learning rate: 2e-4 typical; G:D 1:1 to 1:5 ratio.

Batch size: 32-128; larger helps stability.

Architecture: Deep discriminator; progressive generator.

---

## Real-World Applications & Case Studies

Image Generation: DCGAN, StyleGAN; photorealistic synthesis.

Conditional: CycleGAN; unpaired image translation.

Text-to-Image: CLIP guidance + diffusion.

---

## Integration with Other Methods

GAN + VAE → adversarial VAE.

GAN + Diffusion → hybrid models.

---

## Summary & Key Takeaways

Generative adversarial networks via competing generator-discriminator pair enable unsupervised learning of data distributions, producing high-quality samples through adversarial training.

Principles:
1. Minimax game: generator vs discriminator.
2. Mode collapse: avoid via balanced loss.
3. Spectral normalization: stabilize training.
4. Progressive growing: increase resolution gradually.
5. Evaluation: multi-metric assessment essential.

---

---

## Appendix: Practical Labs

### Lab 1: GAN Components

import torch
import torch.nn as nn
import numpy as np

class Generator(nn.Module):
 def __init__(self, latent_dim=100, output_dim=784):
 super().__init__()
 self.net = nn.Sequential(
 nn.Linear(latent_dim, 256),
 nn.ReLU(),
 nn.Linear(256, 512),
 nn.ReLU(),
 nn.Linear(512, output_dim),
 nn.Sigmoid()
 )

 def forward(self, z):
 return self.net(z)

class Discriminator(nn.Module):
 def __init__(self, input_dim=784):
 super().__init__()
 self.net = nn.Sequential(
 nn.Linear(input_dim, 512),
 nn.ReLU(),
 nn.Linear(512, 256),
 nn.ReLU(),
 nn.Linear(256, 1),
 nn.Sigmoid()
 )

 def forward(self, x):
 return self.net(x)

# Test
np.random.seed(42)
G = Generator(latent_dim=100)
D = Discriminator(input_dim=784)

z = torch.randn(32, 100)
fake_samples = G(z)
score_fake = D(fake_samples)

assert fake_samples.shape == (32, 784), "Generator output shape"
assert score_fake.shape == (32, 1), "Discriminator output shape"
print("✓ GAN components working")

if __name__ == "__main__":
 print("Lab 1: Components - PASSED")

### Lab 2: Adversarial Loss

import torch
import torch.nn.functional as F
import numpy as np

def generator_loss(D, fake_samples):
 """Generator loss: fool discriminator"""
 fake_scores = D(fake_samples)
 loss = -F.logsigmoid(fake_scores).mean()
 return loss

def discriminator_loss(D, real_samples, fake_samples):
 """Discriminator loss: distinguish real vs fake"""
 real_scores = D(real_samples)
 fake_scores = D(fake_samples)
 
 loss_real = -F.logsigmoid(real_scores).mean()
 loss_fake = -F.logsigmoid(1 - fake_scores).mean()
 
 return loss_real + loss_fake

# Test
np.random.seed(42)
class DummyD(nn.Module):
 def forward(self, x):
 return torch.rand(len(x), 1)

D = DummyD()
real = torch.randn(32, 784)
fake = torch.randn(32, 784)

g_loss = generator_loss(D, fake)
d_loss = discriminator_loss(D, real, fake)

assert torch.isfinite(g_loss), "G loss finite"
assert torch.isfinite(d_loss), "D loss finite"
print("✓ Adversarial loss working")

if __name__ == "__main__":
 print("Lab 2: Loss - PASSED")

### Lab 3: Training Step

import torch
import torch.nn as nn
import numpy as np

def train_step(G, D, real_batch, optimizer_G, optimizer_D, latent_dim=100):
 """Single GAN training step"""
 batch_size = len(real_batch)
 
 # Discriminator step
 optimizer_D.zero_grad()
 real_score = D(real_batch)
 
 z = torch.randn(batch_size, latent_dim)
 fake_batch = G(z)
 fake_score = D(fake_batch.detach())
 
 d_loss = -torch.log(real_score).mean() - torch.log(1 - fake_score).mean()
 d_loss.backward()
 optimizer_D.step()
 
 # Generator step
 optimizer_G.zero_grad()
 z = torch.randn(batch_size, latent_dim)
 fake_batch = G(z)
 fake_score = D(fake_batch)
 
 g_loss = -torch.log(fake_score).mean()
 g_loss.backward()
 optimizer_G.step()
 
 return g_loss.item(), d_loss.item()

# Test
np.random.seed(42)
G = nn.Linear(100, 784)
D = nn.Linear(784, 1)
opt_G = torch.optim.Adam(G.parameters())
opt_D = torch.optim.Adam(D.parameters())

real = torch.randn(32, 784)
g_loss, d_loss = train_step(G, D, real, opt_G, opt_D)

assert np.isfinite(g_loss), "G loss finite"
assert np.isfinite(d_loss), "D loss finite"
print("✓ Training step working")

if __name__ == "__main__":
 print("Lab 3: Training - PASSED")

### Lab 4: Mode Coverage Assessment

import numpy as np

def mode_coverage(generated_samples, num_modes=10):
 """Assess generator mode coverage"""
 # Cluster generated samples
 from sklearn.cluster import KMeans
 
 kmeans = KMeans(n_clusters=num_modes, random_state=42)
 labels = kmeans.fit_predict(generated_samples)
 
 # Count samples per mode
 unique_modes = len(np.unique(labels))
 coverage = unique_modes / num_modes
 
 return coverage

# Test
np.random.seed(42)
generated = np.random.randn(1000, 64)

coverage = mode_coverage(generated, num_modes=10)

assert 0 <= coverage <= 1, "Coverage in [0,1]"
print("✓ Mode coverage working")

if __name__ == "__main__":
 print("Lab 4: Coverage - PASSED")

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account