import torch import torch.nn as nn class Generator(nn.Module): def __init__(self, latent_dim=100): super(Generator, self).__init__() # Mapping the 100-dimension noise vector to a 7x7 spatial foundation self.init_size = 7 self.l1 = nn.Sequential(nn.Linear(latent_dim, 256 * self.init_size ** 2)) # Using kernel=4, stride=2, padding=1 perfectly doubles the resolution at each step self.conv_blocks = nn.Sequential( nn.BatchNorm2d(256), # 7x7 -> 14x14 nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(128), nn.LeakyReLU(0.2, inplace=True), # 14x14 -> 28x28 nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(64), nn.LeakyReLU(0.2, inplace=True), # 28x28 -> 56x56 nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(32), nn.LeakyReLU(0.2, inplace=True), # 56x56 -> 112x112 nn.ConvTranspose2d(32, 16, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(16), nn.LeakyReLU(0.2, inplace=True), # 112x112 -> 224x224 # Output is 1 channel (Grayscale) and uses Tanh to map pixels to [-1, 1] nn.ConvTranspose2d(16, 1, kernel_size=4, stride=2, padding=1), nn.Tanh() ) def forward(self, z): out = self.l1(z) out = out.view(out.shape[0], 256, self.init_size, self.init_size) img = self.conv_blocks(out) return img class Discriminator(nn.Module): def __init__(self): super(Discriminator, self).__init__() def discriminator_block(in_filters, out_filters, bn=True): block = [ # Wrap the convolution in spectral normalization nn.utils.spectral_norm(nn.Conv2d(in_filters, out_filters, kernel_size=4, stride=2, padding=1)), nn.LeakyReLU(0.2, inplace=True), nn.Dropout2d(0.25) ] if bn: block.append(nn.BatchNorm2d(out_filters, 0.8)) return block self.model = nn.Sequential( # Input: 1 x 224 x 224 *discriminator_block(1, 16, bn=False), # 112x112 *discriminator_block(16, 32), # 56x56 *discriminator_block(32, 64), # 28x28 *discriminator_block(64, 128), # 14x14 *discriminator_block(128, 256), # 7x7 ) # The downsampled image is flattened and fed into a single neuron to guess: Real or Fake? ds_size = 7 self.adv_layer = nn.Sequential( nn.Linear(256 * ds_size ** 2, 1), nn.Sigmoid() ) def forward(self, img): out = self.model(img) out = out.view(out.shape[0], -1) validity = self.adv_layer(out) return validity if __name__ == "__main__": print("Testing GAN Dimensions...") # 1. Create a dummy noise vector (Batch Size of 2, 100 random numbers each) latent_dim = 100 z = torch.randn(2, latent_dim) # 2. Test Generator gen = Generator(latent_dim) fake_imgs = gen(z) print(f"Generator Output Shape: {fake_imgs.shape}") # EXPECTED: [2, 1, 224, 224] (2 images, 1 channel, 224x224 pixels) # 3. Test Discriminator disc = Discriminator() validity = disc(fake_imgs) print(f"Discriminator Output Shape: {validity.shape}") # EXPECTED: [2, 1] (2 guesses between 0.0 and 1.0) print("If you see [2, 1, 224, 224] and [2, 1], the architecture is perfectly locked in!")