Hey! I’m learning how to use Pytorch and how to use GANs so I followed Pytorch’s tutorial to create a DCGAN.
However, I wanted to use my own dataset, which I created based on keras’ mnist.load_data() function, which returns X_train in the shape (n_samples, height, width) and y_train in (n_samples,). So I didn’t use torchvision.dataset.ImageFolder neither torch.utils.data.DataLoader.
My dataset got shape (2092, 3, 28,28) and, to apply normalization, I did dataset = dataset/127.5 - 1
so all pixel values would be between -1 and 1.
I also did some modifications in the networks so, instead of working with 64x64 images, they would work with 28x28:
# Size of feature maps in generator
ngf = 28
# Size of feature maps in discriminator
ndf = 28
class Generator(nn.Module):
def __init__(self, ngpu, ):
super(Generator, self).__init__()
self.ngpu = ngpu
self.main = nn.Sequential(
# input is Z, going into a convolution
nn.ConvTranspose2d( nz, ngf * 8, 7, 1, 0, bias=False),
nn.BatchNorm2d(ngf * 8),
nn.ReLU(True),
# state size. (ngf*8) x 7 x 7
nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
nn.BatchNorm2d(ngf * 4),
nn.ReLU(True),
# state size. (ngf*4) x 14 x 14
nn.ConvTranspose2d( ngf * 4, ngf * 2, 4, 2, 1, bias=False),
nn.BatchNorm2d(ngf * 2),
nn.ReLU(True),
# state size. (ngf*2) x 28 x 28
nn.ConvTranspose2d( ngf * 2, ngf, 1, 1, 0, bias=False),
nn.BatchNorm2d(ngf),
nn.ReLU(True),
# state size. (ngf) x 28 x 28
nn.ConvTranspose2d( ngf, nc, 1, 1, 0, bias=False),
nn.Tanh()
# state size. (nc) x 28 x 28
)
def forward(self, input):
return self.main(input)
class Discriminator(nn.Module):
def __init__(self, ngpu):
super(Discriminator, self).__init__()
self.ngpu = ngpu
self.main = nn.Sequential(
# input is (nc) x 28 x 28
nn.Conv2d(nc, ndf, 10, 1, 1, bias=False),
nn.LeakyReLU(0.2, inplace=True),
nn.Dropout(0.4, inplace=False),
# state size. (ndf) x 21 x 21
nn.Conv2d(ndf, ndf * 2, 10, 1, 1, bias=False),
nn.BatchNorm2d(ndf * 2),
nn.LeakyReLU(0.2, inplace=True),
nn.Dropout(0.4, inplace=False),
# state size. (ndf*2) x 14 x 14
nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
nn.BatchNorm2d(ndf * 4),
nn.LeakyReLU(0.2, inplace=True),
nn.Dropout(0.4, inplace=False),
# state size. (ndf*4) x 7 x 7
nn.Conv2d(ndf * 4, ndf * 8, 3, 2, 1, bias=False),
nn.BatchNorm2d(ndf * 8),
nn.LeakyReLU(0.2, inplace=True),
nn.Dropout(0.4, inplace=False),
# state size. (ndf*8) x 4 x 4
nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False), # This returns (1,1,1)
nn.Sigmoid()
)
def forward(self, input):
return self.main(input)
I also made some edits in the training loop:
for epoch in range(num_epochs):
netD.zero_grad()
# Format batch
b_size = batch_size
real_cpu = dataset[np.random.randint(0, dataset.shape[0], size=batch_size), :, :, :].to(device)
# Forward pass real batch through D
output = netD(real_cpu).view(-1)
label = torch.full((real_cpu.shape[0],), real_label, dtype=torch.float, device=device)
# Calculate loss on all-real batch
errD_real = criterion(output, label)
# Calculate gradients for D in backward pass
errD_real.backward()
D_x = output.mean().item()
## Train with all-fake batch
# Generate batch of latent vectors
noise = torch.randn(b_size, nz, 1, 1, device=device)
# Generate fake image batch with G
[...]
The rest of the code remains the same as the tutorial(including the rest of the training loop after the […])
However, whenever I plot the generated images, I get only some white squares. I’ve printed the Discriminator, labels_D and Generator output and Generator was generating only tensors with pixel values around -0.03: tensor([[[-2.9896e-02, -4.0004e-02, -1.5176e-02, ..., -6.8201e-02, 5.9256e-03, -3.3405e-02], [-4.2447e-02, 1.9592e-02, -6.5596e-02, ..., 7.0819e-02, -8.5874e-04, -2.7269e-02], [-2.5704e-02, 1.2020e-02, 5.5241e-02, ..., -4.2040e-02, -1.6354e-02, -5.8591e-05], ...
. Discriminator and labels_D, however, seem to be fine, D outputs a tensor with shape (b_size,) where each number is correctly within range [0,1], while labels_D is a tensor with shape (b_size,) full of 1s.
Can someone help me fix this generator problem? I can’t see any problem in my code…