Department of Information Technology
Natural Language Processing Lab
Semester            B.E. Semester VII – INFT
Subject             Deep Learning Lab
Laboratory          Prof. Rasika Ransing
Teacher:
Laboratory          L07
Student Name        Roshan Vilas Khatal
Roll Number         22101A0040
Grade and
Subject Teacher’s
Signature
Experiment     09
Number
Experiment     Train a DCGAN to generate synthetic images and evaluate output quality
Title
Resources /    Hardware: Desktop/Laptop                Software: Google Colab
Apparatus
Required
Code:          import os
               import torch
               import torch.nn as nn
               import torch.optim as optim
               from torch.utils.data import DataLoader, Dataset, Subset
               from torchvision import transforms, utils
               from PIL import Image
               import kagglehub
               from glob import glob
# -----------------------------
# Download CelebA via kagglehub
# -----------------------------
path = kagglehub.dataset_download("jessicali9530/celeba-
dataset")
print("Path to dataset files:", path)
# CelebA images folder
data_path = os.path.join(path, "img_align_celeba")
print("Checking images folder exists:",
os.path.exists(data_path))
# -----------------------------
# Hyperparameters
# -----------------------------
device = torch.device("cuda" if torch.cuda.is_available() else
"cpu")
print("Using device:", device)
latent_dim = 100
batch_size = 128
epochs = 20         # increase later
image_size = 128
sample_dir = "samples"
os.makedirs(sample_dir, exist_ok=True)
# -----------------------------
# Transform
# -----------------------------
transform = transforms.Compose([
   transforms.Resize(image_size),
   transforms.CenterCrop(image_size),
   transforms.ToTensor(),
   transforms.Normalize([0.5]*3, [0.5]*3)   # [-1,1]
])
# -----------------------------
# Custom Dataset for flat images
# -----------------------------
class CelebADataset(Dataset):
     def __init__(self, root, transform=None):
        # Include both .jpg and .JPG, search recursively
        self.files = glob(os.path.join(root, "**", "*.jpg"),
recursive=True) + glob(os.path.join(root, "**", "*.JPG"),
recursive=True)
        self.transform = transform
        if len(self.files) == 0:
            raise ValueError(f"No images found in {root} or
its subdirectories with .jpg or .JPG extensions. Check the
folder and extensions!")
     def __len__(self):
        return len(self.files)
     def __getitem__(self, idx):
        img = Image.open(self.files[idx]).convert("RGB")
        if self.transform:
            img = self.transform(img)
        return img, 0     # dummy label
dataset = CelebADataset(root=data_path, transform=transform)
# Optional subset for fast debugging
subset = Subset(dataset, range(min(10000, len(dataset))))
dataloader = DataLoader(subset, batch_size=batch_size,
shuffle=True, num_workers=2)
print("Total images used:", len(subset))
# -----------------------------
# DCGAN Generator
# -----------------------------
class Generator(nn.Module):
   def __init__(self, latent_dim):
       super().__init__()
       self.net = nn.Sequential(
            nn.ConvTranspose2d(latent_dim, 512, 4, 1, 0,
bias=False),
           nn.BatchNorm2d(512), nn.ReLU(True),
           nn.ConvTranspose2d(512, 256, 4, 2, 1, bias=False),
           nn.BatchNorm2d(256), nn.ReLU(True),
           nn.ConvTranspose2d(256, 128, 4, 2, 1, bias=False),
           nn.BatchNorm2d(128), nn.ReLU(True),
           nn.ConvTranspose2d(128, 64, 4, 2, 1, bias=False),
           nn.BatchNorm2d(64), nn.ReLU(True),
           nn.ConvTranspose2d(64, 3, 4, 2, 1, bias=False),
           nn.Tanh()
       )
   def forward(self, z):
       return self.net(z)
# -----------------------------
# DCGAN Discriminator
# -----------------------------
class Discriminator(nn.Module):
   def __init__(self):
       super().__init__()
       self.net = nn.Sequential(
           nn.Conv2d(3, 64, 4, 2, 1, bias=False),
           nn.LeakyReLU(0.2, inplace=True),
           nn.Conv2d(64, 128, 4, 2, 1, bias=False),
            nn.BatchNorm2d(128), nn.LeakyReLU(0.2,
inplace=True),
           nn.Conv2d(128, 256, 4, 2, 1, bias=False),
            nn.BatchNorm2d(256), nn.LeakyReLU(0.2,
inplace=True),
           nn.Conv2d(256, 512, 4, 2, 1, bias=False),
            nn.BatchNorm2d(512), nn.LeakyReLU(0.2,
inplace=True),
           nn.Conv2d(512, 1, 4, 1, 0, bias=False),
           nn.Sigmoid()
       )
   def forward(self, img):
       # Flatten the output to a 1D tensor
       return self.net(img).view(-1, 1).squeeze(1)
# -----------------------------
# Initialize models & optimizers
# -----------------------------
G = Generator(latent_dim).to(device)
D = Discriminator().to(device)
criterion = nn.BCELoss()
optimizerD = optim.Adam(D.parameters(), lr=0.0002, betas=(0.5,
0.999))
optimizerG = optim.Adam(G.parameters(), lr=0.0002, betas=(0.5,
0.999))
fixed_noise = torch.randn(64, latent_dim, 1, 1, device=device)
# -----------------------------
# Training Loop
# -----------------------------
for epoch in range(epochs):
   for i, (imgs, _) in enumerate(dataloader):
       real_imgs = imgs.to(device)
       b_size = real_imgs.size(0)
       real_labels = torch.ones(b_size, device=device)
       fake_labels = torch.zeros(b_size, device=device)
       # Train Discriminator
       optimizerD.zero_grad()
       output_real = D(real_imgs)
       lossD_real = criterion(output_real, real_labels)
        noise = torch.randn(b_size, latent_dim, 1, 1,
device=device)
       fake_imgs = G(noise)
       output_fake = D(fake_imgs.detach())
       lossD_fake = criterion(output_fake, fake_labels)
       lossD = lossD_real + lossD_fake
       lossD.backward()
       optimizerD.step()
       # Train Generator
       optimizerG.zero_grad()
       output_fake = D(fake_imgs)
       lossG = criterion(output_fake, real_labels)
       lossG.backward()
       optimizerG.step()
       if i % 200 == 0:
            print(f"Epoch [{epoch+1}/{epochs}] Step
[{i}/{len(dataloader)}] "
                  f"LossD: {lossD.item():.4f} LossG:
{lossG.item():.4f}")
   # Save generated images
   with torch.no_grad():
       fake = G(fixed_noise).detach().cpu()
   utils.save_image(fake,
          f"{sample_dir}/epoch_{epoch+1}.png", normalize=True, nrow=8)
              print(f" Saved sample images at
          {sample_dir}/epoch_{epoch+1}.png")
Output:   Epoch 1
          Epoch 5
Epoch 10
Epoch 15
Epoch 20
Conclusion :
               This experiment successfully implemented and trained a Deep
               Convolutional GAN (DCGAN) on the CelebA dataset to generate human face
               images from random noise. The generator and discriminator models were
               trained adversarially, where the generator improved in producing realistic
               samples while the discriminator learned to distinguish real from fake.
               Although early outputs were blurry, progressive training gradually
               improved the quality and structure of generated faces. The experiment
               demonstrates the effectiveness of GANs in learning complex data
               distributions, while also highlighting limitations such as potential mode
               collapse and limited detail at higher resolutions. With longer training, use of
               the full dataset, and advanced GAN variants, the quality and diversity of
               generated images can be further enhanced.