TensorFlow GANs Basics
A Generative Adversarial Network (GAN) is a system where two neural networks compete against each other to produce realistic synthetic data. GANs generate photorealistic human faces that do not belong to real people, create artwork in any artistic style, synthesize medical images for training datasets, and convert rough sketches into detailed photos. Understanding GANs opens one of the most creative areas in modern machine learning.
The Counterfeiter and Detective Analogy
Imagine a counterfeiter who prints fake banknotes and a detective who tries to spot the fakes. The counterfeiter studies the detective's feedback and improves the fakes. The detective studies both real and fake notes and sharpens their detection skills. They push each other to higher levels of expertise. Eventually, the counterfeiter produces banknotes so good that even the detective cannot reliably tell them apart from real ones.
In a GAN:
- The Generator is the counterfeiter — it creates fake data
- The Discriminator is the detective — it classifies data as real or fake
The Two Networks in Detail
The Generator
The Generator takes random noise as input (a vector of random numbers) and produces a synthetic output — an image, a sound clip, or text. It starts by generating terrible, random-looking outputs. Over thousands of training steps, it learns to produce outputs that fool the Discriminator.
Random Noise Vector Generated Image
[0.23, -0.81, 0.55, ...] (looks like random pixels initially)
│
▼
[Generator Network]
Dense → Reshape → Conv2DTranspose × 3
│
▼
Synthetic Image
(128×128 pixels)
The Discriminator
The Discriminator is a standard image classifier. It receives either a real image from your dataset or a fake image from the Generator. It outputs a single number: close to 1 means "this looks real," close to 0 means "this looks fake."
Real Image ──┐
├──► [Discriminator Network] ──► 0.92 (probably real)
Fake Image ──┘ Conv2D × 3 → Dense 0.03 (probably fake)
How Training Works
GAN Training Loop: ────────────────────────────────────────────────────────── Phase 1: Train the Discriminator 1. Take a batch of REAL images → label them 1 (real) 2. Generate a batch of FAKE images → label them 0 (fake) 3. Train Discriminator on both batches 4. Update Discriminator weights to improve detection Phase 2: Train the Generator 1. Generate a batch of FAKE images 2. Pass them through the (now frozen) Discriminator 3. Label them 1 (pretend they are real — this tricks the loss) 4. Update Generator weights to produce more convincing fakes 5. The Generator's goal: maximize Discriminator's error Repeat these two phases alternately for thousands of steps ──────────────────────────────────────────────────────────
Building a Simple GAN in TensorFlow
Step 1: Define the Generator
import tensorflow as tf
def build_generator(latent_dim=100):
model = tf.keras.Sequential([
# Accept random noise vector
tf.keras.layers.Dense(7 * 7 * 256, activation='relu',
input_shape=(latent_dim,)),
tf.keras.layers.Reshape((7, 7, 256)),
# Upsample to 14×14
tf.keras.layers.Conv2DTranspose(128, (4, 4), strides=2,
padding='same', activation='relu'),
# Upsample to 28×28
tf.keras.layers.Conv2DTranspose(64, (4, 4), strides=2,
padding='same', activation='relu'),
# Final image layer
tf.keras.layers.Conv2DTranspose(1, (7, 7), padding='same',
activation='tanh')
# tanh outputs values between -1 and 1 (image pixels)
])
return model
Conv2DTranspose is the reverse of Conv2D. While Conv2D shrinks spatial dimensions, Conv2DTranspose expands them. The Generator uses Conv2DTranspose layers to grow a small latent vector into a full-sized image.
Step 2: Define the Discriminator
def build_discriminator():
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(64, (3, 3), strides=2, padding='same',
input_shape=(28, 28, 1)),
tf.keras.layers.LeakyReLU(0.2),
tf.keras.layers.Dropout(0.3),
tf.keras.layers.Conv2D(128, (3, 3), strides=2, padding='same'),
tf.keras.layers.LeakyReLU(0.2),
tf.keras.layers.Dropout(0.3),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(1, activation='sigmoid')
# Outputs probability: 1=real, 0=fake
])
return model
LeakyReLU is used in the Discriminator instead of ReLU because it allows small negative values to pass through, which prevents neurons from becoming permanently inactive during adversarial training.
Step 3: Build the Combined GAN
latent_dim = 100
generator = build_generator(latent_dim)
discriminator = build_discriminator()
# Compile discriminator separately
discriminator.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
# Combined GAN: noise → generator → discriminator
discriminator.trainable = False # Freeze discriminator during GAN training
gan_input = tf.keras.Input(shape=(latent_dim,))
gan_output = discriminator(generator(gan_input))
gan = tf.keras.Model(gan_input, gan_output)
gan.compile(optimizer='adam', loss='binary_crossentropy')
Step 4: The Custom Training Loop
import numpy as np
def train_gan(gan, generator, discriminator, dataset, epochs, latent_dim):
for epoch in range(epochs):
for real_images in dataset:
batch_size = real_images.shape[0]
# ── Phase 1: Train Discriminator ──────────────────────
noise = np.random.normal(0, 1, (batch_size, latent_dim))
fake_images = generator.predict(noise, verbose=0)
real_labels = np.ones((batch_size, 1))
fake_labels = np.zeros((batch_size, 1))
d_loss_real = discriminator.train_on_batch(real_images, real_labels)
d_loss_fake = discriminator.train_on_batch(fake_images, fake_labels)
# ── Phase 2: Train Generator ──────────────────────────
noise = np.random.normal(0, 1, (batch_size, latent_dim))
misleading_labels = np.ones((batch_size, 1)) # Pretend fakes are real
g_loss = gan.train_on_batch(noise, misleading_labels)
print(f"Epoch {epoch+1}: D_loss={d_loss_real[0]:.3f}, G_loss={g_loss:.3f}")
The Nash Equilibrium: When GANs Converge
GANs aim for a theoretical state called Nash Equilibrium: the Generator produces outputs so realistic that the Discriminator can do no better than guessing randomly (50% accuracy). At this point, the Generator has learned the true distribution of the training data and can generate new samples that are statistically indistinguishable from real data.
Training Progress: ───────────────────────────────────────────────────── Epoch 1: Generator output = noise Discriminator = 99% accurate Epoch 100: Blurry shapes Discriminator = 80% accurate Epoch 500: Recognizable images Discriminator = 65% accurate Epoch 1000: Realistic images Discriminator ≈ 50% accurate (Nash) ─────────────────────────────────────────────────────
Common GAN Problems and Solutions
Mode Collapse
The Generator learns to produce only one or a few types of outputs, ignoring the diversity in the real data. For example, a face GAN might generate only blonde women regardless of what noise you provide.
Solution: Use Wasserstein GAN (WGAN) loss or add minibatch discrimination.
Training Instability
The Generator and Discriminator fail to improve together. One becomes too powerful and the other stops learning.
Solution: Use the same learning rate for both, train them the same number of steps, and use label smoothing (set real labels to 0.9 instead of 1.0).
Vanishing Gradients
When the Discriminator is much better than the Generator early on, it classifies all fakes with near-zero probability. The Generator receives almost no gradient signal and stops learning.
Solution: Use LeakyReLU, spectral normalization, or Wasserstein loss.
Types of GANs
- DCGAN — Deep Convolutional GAN; the standard baseline for image generation
- Conditional GAN (cGAN) — both networks receive a class label, so you control what type of image gets generated
- Pix2Pix — translates one image type to another (sketch to photo, day to night)
- CycleGAN — converts between two image domains without paired training examples (horses to zebras)
- StyleGAN — generates high-resolution faces with controllable style attributes
- WGAN — uses Wasserstein distance for more stable training
GANs represent one of the most active research areas in machine learning. The creative applications — from art generation to drug discovery — continue to expand. The next topic covers the Transformer model, which revolutionized natural language processing and is now reshaping computer vision as well.
