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:
GANs were introduced in 2014 by Ian Goodfellow and colleagues.
2️⃣ Why GANs Were Revolutionary
Before GANs:
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:
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:
Workflow:
Random Noise → Generator → Fake Image Fake Image → Discriminator Real Image → Discriminator
Discriminator tries to:
Generator tries to:
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:
Generator:
This adversarial setup drives learning.
5️⃣ Training Process
Each training step:
GAN training is unstable because:
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?
🔟 Key Challenges of GANs
FULL COMPILATION OF ALL 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()