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…