A PyTorch implementation of Generative Adversarial Networks (GAN) and Conditional GANs (cGAN) trained on FashionMNIST for generating fashion item images.
Both models generate 28x28 grayscale images of fashion items.
Input: z ~ N(0,1) of dimension 100
Linear(100 → 256*7*7) + BatchNorm + ReLU
↓
Reshape to (256, 7, 7)
↓
ConvTranspose2d(256 → 128, k=4, s=2, p=1) + BatchNorm + ReLU → (128, 14, 14)
↓
ConvTranspose2d(128 → 64, k=4, s=2, p=1) + BatchNorm + ReLU → (64, 28, 28)
↓
Conv2d(64 → 1, k=3, s=1, p=1) + Tanh → (1, 28, 28)
Output: Image in [-1, 1]
Input: Image (1, 28, 28)
Conv2d(1 → 64, k=4, s=2, p=1) + LeakyReLU(0.2) → (64, 14, 14)
↓
Conv2d(64 → 128, k=4, s=2, p=1) + BatchNorm + LeakyReLU(0.2) → (128, 7, 7)
↓
Flatten → Linear(128*7*7 → 1) + Sigmoid
Output: Probability [0, 1] (real vs fake)
Input: z ~ N(0,1) of dimension 100 + class label (0-9)
Label Embedding(10 → 50)
↓
Concatenate [z, embedding] → (150,)
↓
Linear(150 → 256*7*7) + BatchNorm + ReLU
↓
[Same architecture as standard Generator]
Output: Class-conditioned image in [-1, 1]
Input: Image (1, 28, 28) + class label (0-9)
Label Embedding(10 → 28*28)
↓
Reshape embedding to (1, 28, 28)
↓
Concatenate [image, label_map] → (2, 28, 28)
↓
[Modified Discriminator with 2 input channels]
Output: Probability [0, 1] (real vs fake for given class)
1 import torch
2
3 # Load generator
4 G = Generator ( latent_dim = 100 , channels = 1 )
5 G . load_state_dict ( torch . load ( 'generator.pth' ) )
6 G . eval ( )
7
8 # Generate images
9 with torch . no_grad ( ) :
10 z = torch . randn ( 16 , 100 ) # 16 random images
11 fake_images = G ( z )
12
13 # Denormalize: [-1, 1] → [0, 1]
14 fake_images = ( fake_images + 1 ) / 2
1 import torch
2
3 # Load conditional generator
4 cG = ConditionalGenerator ( latent_dim = 100 , num_classes = 10 , embedding_dim = 50 )
5 cG . load_state_dict ( torch . load ( 'conditional_generator.pth' ) )
6 cG . eval ( )
7
8 # Generate 8 sneakers (class 7)
9 with torch . no_grad ( ) :
10 z = torch . randn ( 8 , 100 )
11 labels = torch . full ( ( 8 , ) , 7 , dtype = torch . long ) # 7 = Sneaker
12 fake_sneakers = cG ( z , labels )
13
14 # Denormalize
15 fake_sneakers = ( fake_sneakers + 1 ) / 2
1 def interpolate_latent ( G , z1 , z2 , steps = 10 ) :
2 """Smoothly interpolate between two latent vectors"""
3 images = [ ]
4 for alpha in torch . linspace ( 0 , 1 , steps ) :
5 z = ( 1 - alpha ) * z1 + alpha * z2
6 with torch . no_grad ( ) :
7 img = G ( z . unsqueeze ( 0 ) )
8 images . append ( img )
9 return torch . cat ( images )
1 def interpolate_between_classes ( cG , class1 , class2 , steps = 10 ) :
2 """Interpolate between two fashion categories"""
3 z = torch . randn ( 1 , 100 ) # Fixed noise
4
5 emb1 = cG . label_embedding ( torch . tensor ( [ class1 ] ) )
6 emb2 = cG . label_embedding ( torch . tensor ( [ class2 ] ) )
7
8 images = [ ]
9 for alpha in torch . linspace ( 0 , 1 , steps ) :
10 emb = ( 1 - alpha ) * emb1 + alpha * emb2
11 # Manual forward with interpolated embedding
12 # ...
13 return images
torch>=1.9.0
torchvision>=0.10.0
numpy>=1.20.0
matplotlib>=3.4.0
tqdm>=4.60.0
seaborn>=0.11.0
1 @article{goodfellow2014generative,
2 title={Generative adversarial nets},
3 author={Goodfellow, Ian and others},
4 journal={NeurIPS},
5 year={2014}
6 }
7
8 @article{mirza2014conditional,
9 title={Conditional generative adversarial nets},
10 author={Mirza, Mehdi and Osindero, Simon},
11 journal={arXiv:1411.1784},
12 year={2014}
13 }
14
15 @online{fashionmnist,
16 author={Xiao, Han and Rasul, Kashif and Vollgraf, Roland},
17 title={Fashion-MNIST},
18 year={2017},
19 url={https://github.com/zalandoresearch/fashion-mnist}
20 }