I am new to machine learning and have been playing around with implementing DCGAN models as a requisite for the research I am doing. I have a somewhat basic model but everytime I run it, regardless what loss function I select as my criterion, I always get a similar message about input and output size being mismatched and I don't know what to do. The stacktrace is as follows:
Traceback (most recent call last): File "c:\PycharmProjects\ctgan\dcgan.py", line 148, in <module dcgan.train() File "c:\PycharmProjects\ctgan\dcgan.py", line 101, in train errD_real = criterion(output_real, label_real) # Calculate the loss with the reshaped >labels File "C:.conda\envs\DL_IDS\lib\site-packages\torch\nn\modules\module.py", line 1511, in >_wrapped_call_impl return self._call_impl(*args, **kwargs) File "C:.conda\envs\DL_IDS\lib\site-packages\torch\nn\modules\module.py", line 1520, in >_call_impl return forward_call(*args, **kwargs) File "C:.conda\envs\DL_IDS\lib\site-packages\torch\nn\modules\loss.py", line 725, in >forward return F.binary_cross_entropy_with_logits(input, target, File "C:.conda\envs\DL_IDS\lib\site-packages\torch\nn\functional.py", line 3197, in >binary_cross_entropy_with_logits raise ValueError(f"Target size ({target.size()}) must be the same as input size ({input.size()})") ValueError: Target size (torch.Size([64, 1])) must be the same as input size (torch.Size([2304]))
The full code for my DCGAN model is as follows:
import torch
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.optim as optim
import torchvision.utils as vutils
class DCGAN:
def __init__(self, dataset, nz=100, ngf=79, ndf=79, nc=3):
self.nz = nz
self.ngf = ngf
self.ndf = ndf
self.nc = nc
self.dataset = dataset
# Initialize the networks
self.netG = self.Generator(nz, ngf, nc)
self.netD = self.Discriminator(nc, ndf)
# Define the loss function and optimizers
self.criterion = nn.BCEWithLogitsLoss()
self.optimizerG = optim.SGD(self.netG.parameters(), lr=0.0002, momentum=0.9)
self.optimizerD = optim.SGD(self.netD.parameters(), lr=0.0002, momentum=0.9)
class Generator(nn.Module):
def __init__(self, nz, ngf, nc):
super(DCGAN.Generator, self).__init__()
self.main = nn.Sequential(
nn.ConvTranspose2d(nz, ngf * 4, 4, 1, 0, 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):
def __init__(self, nc, ndf):
super(DCGAN.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, 1, 4, 1, 0, bias=False),
nn.Sigmoid()
)
def forward(self, x):
print("input shape :", x.shape)
if x.dim() == 3:
# Add a batch dimension
x = x.unsqueeze(0)
x = self.main(x)
return x.view(-1, 1)
def train(self, num_epochs=10):
# Data loading and preprocessing
# Remove unused variable
# transform = transforms.Compose([
# transforms.Resize((81, 393)),
# transforms.ToTensor(),
# transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
# ])
# dataset = self.dataset
# dataloader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=2)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Sigmoid Cross Entropy Loss
criterion = nn.BCEWithLogitsLoss()
for epoch in range(num_epochs):
for i, data in enumerate(dataloader, 0):
# Update Discriminator
self.netD.zero_grad()
real_data = data[0].to(device)
batch_size = real_data.size(0)
# Create real labels (1s)
label_real = torch.full((batch_size, 1), 1.0, device=device) # Adjusted to match the dimensions
output_real = self.netD(real_data).view(-1)
label_real = label_real.view(-1, 1) # Reshape label_real to match the shape of output_real
errD_real = criterion(output_real, label_real) # Calculate the loss with the reshaped labels
errD_real.backward()
noise = torch.randn(batch_size, self.nz, 1, 1, device=device)
fake_data = self.netG(noise)
# Create fake labels (0s)
label_fake = torch.full((batch_size, 1), 0.0, device=device) # Adjusted to match the dimensions
output_fake = self.netD(fake_data.detach()).view(-1)
errD_fake = criterion(output_fake, label_fake)
errD_fake.backward()
self.optimizerD.step()
# Update Generator
self.netG.zero_grad()
label_real.fill_(1.0) # Adjusted to use float labels
output = self.netD(fake_data).view(-1)
errG = criterion(output, label_real)
errG.backward()
self.optimizerG.step()
if i % 100 == 0:
print('[%d/%d][%d/%d] Loss_D: %.4f Loss_G: %.4f'
% (epoch, num_epochs, i, len(dataloader),
errD_real.item() + errD_fake.item(), errG.item()))
# Save generated images for every epoch
fake = self.netG(torch.randn(64, self.nz, 1, 1, device=device))
vutils.save_image(fake.detach(), f'fake_samples_epoch_{epoch + 1}.png', normalize=True)
# Save the generator model
torch.save(self.netG.state_dict(), 'dcgan_generator_weights.pth')
if __name__ == '__main__':
# Example usage:
# my_dataset = datasets.CIFAR10 # Set your dataset class dynamically
transform = transforms.Compose([
transforms.Resize(79),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
])
my_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
dataloader = DataLoader(my_dataset, batch_size=64, shuffle=True, num_workers=2)
dcgan = DCGAN(dataset=dataloader)
dcgan.train()
pass
I have tried to expand, resize, reshape my data in all sorts of manner I could find online but none of it seems to yield any meaningful outcome. How to resolve this?