Generative Adversarial Networks (GANs) | Deep Learning Tutorial - Learn with VOKS
Back

Generative Adversarial Networks (GANs)


1️⃣ What is a GAN?

A Generative Adversarial Network (GAN) is a deep learning model that can generate new data that looks real.

For example:

  • Fake human faces
  • Artificial artwork
  • Synthetic medical images
  • AI-generated fashion designs

GANs were introduced in 2014 by Ian Goodfellow and colleagues.


2️⃣ Why GANs Were Revolutionary

Before GANs:

  • Models generated blurry images.
  • Generative models were complex and slow.

GANs changed this by introducing:

Two neural networks competing against each other.

This “competition” makes the generator improve continuously.

Research and development in GANs have been explored by institutions such as:

  • OpenAI
  • Google
  • Meta

3️⃣ GAN Architecture

A GAN consists of two networks:

| Component      | Role |
|---------------|------|
| Generator (G) | Creates fake data |
| Discriminator (D) | Detects real vs fake data |

Think of it like:

  • Generator → Counterfeiter
  • Discriminator → Police

Workflow:

Random Noise → Generator → Fake Image
Fake Image → Discriminator
Real Image → Discriminator

Discriminator tries to:

  • Output 1 for real
  • Output 0 for fake

Generator tries to:

  • Fool discriminator

4️⃣ Mathematical Intuition

The GAN objective is a minimax game:

Minimize (Generator) and Maximize (Discriminator):

min_G max_D V(D,G)

Loss function:

E[log D(real)] + E[log(1 - D(fake))]

Discriminator:

  • Wants D(real) → 1
  • Wants D(fake) → 0

Generator:

  • Wants D(fake) → 1

This adversarial setup drives learning.


5️⃣ Training Process

Each training step:

  1. Sample real data
  2. Generate fake data
  3. Train discriminator
  4. Train generator
  5. Repeat

GAN training is unstable because:

  • If discriminator becomes too strong → generator fails
  • If generator becomes too strong → discriminator fails

Balancing is key.


6️⃣ Types of GANs

🔹Vanilla GAN

Basic GAN architecture.


🔹DCGAN (Deep Convolutional GAN)

Uses convolutional layers.

Great for images.


🔹Conditional GAN (cGAN)

Generates data conditioned on labels.

Example:

Generate digit “5”.

🔹CycleGAN

Transforms images between domains.

Example:

Horse ↔ Zebra.

🔹StyleGAN

Developed by NVIDIA.

Generates highly realistic human faces.


7️⃣ Applications of GANs

| Application | Description |
|------------|-------------|
| Image Generation | Create realistic faces |
| Image Super-Resolution | Increase image quality |
| Data Augmentation | Generate more training data |
| Medical Imaging | Synthetic scans |
| Art Generation | AI artwork |
| Deepfakes | Face swapping |

8️⃣ Simple GAN Example (MNIST Digits)

We will generate handwritten digits.


🔹 Install Required Libraries

pip install tensorflow matplotlib numpy

🔹 Python Implementation

import tensorflow as tf
from tensorflow.keras import layers
import numpy as np
import matplotlib.pyplot as plt

# Load MNIST
(x_train, _), (_, _) = tf.keras.datasets.mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)

BUFFER_SIZE = 60000
BATCH_SIZE = 256
latent_dim = 100

train_dataset = tf.data.Dataset.from_tensor_slices(x_train).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)

# Generator
def build_generator():
    model = tf.keras.Sequential()
    model.add(layers.Dense(7*7*128, use_bias=False, input_shape=(latent_dim,)))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Reshape((7, 7, 128)))
    model.add(layers.Conv2DTranspose(64, (5, 5), strides=(1, 1), padding='same', use_bias=False))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))

    return model

# Discriminator
def build_discriminator():
    model = tf.keras.Sequential()
    model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))

    model.add(layers.Flatten())
    model.add(layers.Dense(1))

    return model

generator = build_generator()
discriminator = build_discriminator()

cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)

def discriminator_loss(real_output, fake_output):
    real_loss = cross_entropy(tf.ones_like(real_output), real_output)
    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)
    return real_loss + fake_loss

def generator_loss(fake_output):
    return cross_entropy(tf.ones_like(fake_output), fake_output)

generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)

@tf.function
def train_step(images):
    noise = tf.random.normal([BATCH_SIZE, latent_dim])

    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
        generated_images = generator(noise, training=True)

        real_output = discriminator(images, training=True)
        fake_output = discriminator(generated_images, training=True)

        gen_loss = generator_loss(fake_output)
        disc_loss = discriminator_loss(real_output, fake_output)

    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)
    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)

    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))
    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))

for epoch in range(10):
    for image_batch in train_dataset:
        train_step(image_batch)

# Generate images
noise = tf.random.normal([16, latent_dim])
generated_images = generator(noise, training=False)

plt.figure(figsize=(4,4))
for i in range(16):
    plt.subplot(4,4,i+1)
    plt.imshow(generated_images[i, :, :, 0], cmap='gray')
    plt.axis('off')
plt.show()

9️⃣ What Happens in This Code?

  1. Load MNIST digits
  2. Build Generator (noise → image)
  3. Build Discriminator (image → real/fake)
  4. Train both in adversarial setup
  5. Generate new fake digits

🔟 Key Challenges of GANs

  • Mode collapse (generator outputs similar images)
  • Training instability
  • Sensitive hyperparameters
  • Hard to evaluate

FULL COMPILATION OF ALL CODE


Example Code:
# Install:
# pip install tensorflow matplotlib numpy

import tensorflow as tf
from tensorflow.keras import layers
import numpy as np
import matplotlib.pyplot as plt

(x_train, _), (_, _) = tf.keras.datasets.mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)

BUFFER_SIZE = 60000
BATCH_SIZE = 256
latent_dim = 100

train_dataset = tf.data.Dataset.from_tensor_slices(x_train).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)

def build_generator():
    model = tf.keras.Sequential()
    model.add(layers.Dense(7*7*128, use_bias=False, input_shape=(latent_dim,)))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())
    model.add(layers.Reshape((7, 7, 128)))
    model.add(layers.Conv2DTranspose(64, (5, 5), strides=(1, 1), padding='same', use_bias=False))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())
    model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
    return model

def build_discriminator():
    model = tf.keras.Sequential()
    model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))
    model.add(layers.Flatten())
    model.add(layers.Dense(1))
    return model

generator = build_generator()
discriminator = build_discriminator()

cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)

def discriminator_loss(real_output, fake_output):
    real_loss = cross_entropy(tf.ones_like(real_output), real_output)
    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)
    return real_loss + fake_loss

def generator_loss(fake_output):
    return cross_entropy(tf.ones_like(fake_output), fake_output)

generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)

@tf.function
def train_step(images):
    noise = tf.random.normal([BATCH_SIZE, latent_dim])
    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
        generated_images = generator(noise, training=True)
        real_output = discriminator(images, training=True)
        fake_output = discriminator(generated_images, training=True)
        gen_loss = generator_loss(fake_output)
        disc_loss = discriminator_loss(real_output, fake_output)

    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)
    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)

    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))
    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))

for epoch in range(10):
    for image_batch in train_dataset:
        train_step(image_batch)

noise = tf.random.normal([16, latent_dim])
generated_images = generator(noise, training=False)

import matplotlib.pyplot as plt
plt.figure(figsize=(4,4))
for i in range(16):
    plt.subplot(4,4,i+1)
    plt.imshow(generated_images[i, :, :, 0], cmap='gray')
    plt.axis('off')
plt.show()
Deep Learning
Architecture Activation Functions BackPropagation Image Recognition Natural Language Processing (NLP) with Deep Learning Time Series Forecasting Autoencoders Generative Adversarial Networks (GANs)
All Courses
Advance AI Bootstrap C C++ Computer Vision Content Writing CSS Cyber Security Data Analysis Deep Learning Email Marketing Excel Figma HTML Java Script Machine Learning MySQLi Node JS PHP Power Bi Python Python for AI Python for Analysis React React Native SEO SMM SQL