Sahaj.blogs
16 Jun 2026 · StudyPhase 14 · Generative AI

Generative AI · DCGAN

The DCGAN architecture guidelines (strided convolutions, batch norm, ReLU/LeakyReLU, no pooling or fully connected hidden layers) built in PyTorch, with the tensor shapes traced from noise to a 32×32 image.

DCGAN (Radford, Metz and Chintala, 2015) made GANs work with convolutional networks, using a short list of architecture guidelines from the paper:

  • replace pooling with strided convolutions (discriminator) and fractionally-strided/transposed convolutions (generator)
  • use batch normalisation in both networks
  • no fully connected hidden layers in deeper architectures
  • ReLU in the generator (Tanh at the output), LeakyReLU in the discriminator

In March I reproduced the paper in my Modern-DCGAN-Reproducibility repo, keeping this all-convolutional architecture but changing the training engine (LSGAN, spectral norm, label smoothing). Here I rebuilt the architecture at 32×32 (CIFAR-10 size) and traced the shapes layer by layer. Following the shapes is the clearest way to understand how 100 numbers become an image.

import torch, torch.nn as nn
torch.manual_seed(0)
nz, ngf, ndf = 100, 64, 64

G = nn.Sequential(
    nn.ConvTranspose2d(nz, ngf * 4, 4, 1, 0, bias=False), nn.BatchNorm2d(ngf * 4), nn.ReLU(True),     # 1 -> 4
    nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 2), nn.ReLU(True), # 4 -> 8
    nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf), nn.ReLU(True),         # 8 -> 16
    nn.ConvTranspose2d(ngf, 3, 4, 2, 1, bias=False), nn.Tanh())                                         # 16 -> 32
D = nn.Sequential(
    nn.Conv2d(3, ndf, 4, 2, 1, bias=False), nn.LeakyReLU(0.2, True),                                    # 32 -> 16
    nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 2), nn.LeakyReLU(0.2, True),     # 16 -> 8
    nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 4), nn.LeakyReLU(0.2, True), # 8 -> 4
    nn.Conv2d(ndf * 4, 1, 4, 1, 0, bias=False))                                                          # 4 -> 1 (logit)

def trace(net, x, label):
    print(label)
    for layer in net:
        x = layer(x)
        if isinstance(layer, (nn.ConvTranspose2d, nn.Conv2d)):
            print(f"   {type(layer).__name__:<16} -> {tuple(x.shape)}")
    return x

img = trace(G, torch.randn(2, nz, 1, 1), "generator: noise -> image")
print("   output range:", round(img.min().item(), 3), "to", round(img.max().item(), 3), "(Tanh)")
trace(D, img, "discriminator: image -> real/fake logit")
count = lambda m: sum(p.numel() for p in m.parameters())
print(f"parameters: G {count(G):,} | D {count(D):,}")

Output:

generator: noise -> image
   ConvTranspose2d  -> (2, 256, 4, 4)
   ConvTranspose2d  -> (2, 128, 8, 8)
   ConvTranspose2d  -> (2, 64, 16, 16)
   ConvTranspose2d  -> (2, 3, 32, 32)
   output range: -0.996 to 0.999 (Tanh)
discriminator: image -> real/fake logit
   Conv2d           -> (2, 64, 16, 16)
   Conv2d           -> (2, 128, 8, 8)
   Conv2d           -> (2, 256, 4, 4)
   Conv2d           -> (2, 1, 1, 1)
parameters: G 1,068,928 | D 663,296

#generative-ai#gan#dcgan

Sources

  1. Radford, Metz & Chintala (2015), Unsupervised Representation Learning with Deep Convolutional GANs — arXiv
  2. PyTorch tutorial: DCGAN — PyTorch
  3. My repo: Modern-DCGAN-Reproducibility — GitHub