| """
|
| DCGAN Generator and Discriminator for 64x64 texture image generation.
|
| """
|
| import torch
|
| import torch.nn as nn
|
|
|
|
|
|
|
| LATENT_DIM = 100
|
|
|
| NGF = 64
|
|
|
| NDF = 64
|
|
|
| NC = 3
|
|
|
|
|
| class Generator(nn.Module):
|
| """
|
| DCGAN Generator: maps a latent vector (100-dim) to a 64x64 RGB image.
|
| Architecture: Linear -> Reshape -> TransposedConv blocks -> Tanh
|
| """
|
| def __init__(self, latent_dim=LATENT_DIM, ngf=NGF, nc=NC):
|
| super(Generator, self).__init__()
|
| self.main = nn.Sequential(
|
|
|
| nn.ConvTranspose2d(latent_dim, ngf * 8, 4, 1, 0, bias=False),
|
| nn.BatchNorm2d(ngf * 8),
|
| nn.ReLU(True),
|
|
|
|
|
| nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
|
| nn.BatchNorm2d(ngf * 4),
|
| nn.ReLU(True),
|
|
|
|
|
| nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
|
| nn.BatchNorm2d(ngf * 2),
|
| nn.ReLU(True),
|
|
|
|
|
| nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),
|
| nn.BatchNorm2d(ngf),
|
| nn.ReLU(True),
|
|
|
|
|
| nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),
|
| nn.Tanh()
|
|
|
| )
|
|
|
| def forward(self, x):
|
| return self.main(x)
|
|
|
|
|
| class Discriminator(nn.Module):
|
| """
|
| DCGAN Discriminator: classifies 64x64 RGB images as real or fake.
|
| Architecture: Conv blocks -> Sigmoid
|
| """
|
| def __init__(self, ndf=NDF, nc=NC):
|
| super(Discriminator, self).__init__()
|
| self.main = nn.Sequential(
|
|
|
| nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),
|
| nn.LeakyReLU(0.2, inplace=True),
|
|
|
|
|
| nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
|
| nn.BatchNorm2d(ndf * 2),
|
| nn.LeakyReLU(0.2, inplace=True),
|
|
|
|
|
| nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
|
| nn.BatchNorm2d(ndf * 4),
|
| nn.LeakyReLU(0.2, inplace=True),
|
|
|
|
|
| nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
|
| nn.BatchNorm2d(ndf * 8),
|
| nn.LeakyReLU(0.2, inplace=True),
|
|
|
|
|
| nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
|
| nn.Sigmoid()
|
|
|
| )
|
|
|
| def forward(self, x):
|
| return self.main(x).view(-1, 1).squeeze(1)
|
|
|
|
|
| def weights_init(m):
|
| """Initialize weights from a normal distribution (DCGAN paper recommendation)."""
|
| classname = m.__class__.__name__
|
| if classname.find('Conv') != -1:
|
| nn.init.normal_(m.weight.data, 0.0, 0.02)
|
| elif classname.find('BatchNorm') != -1:
|
| nn.init.normal_(m.weight.data, 1.0, 0.02)
|
| nn.init.constant_(m.bias.data, 0)
|
|
|