I try to imitate DCAGN, using residual structure to build a symmetric generator and discriminator; my structure is as follows, I imitate ACGAN input corresponding labels. However, after training, the images generated by the generator have always been noise maps and have hardly changed.
And I tried to change the loss function from BCEloss to hinge loss and the optimizer from Adam optimizer to RMSprop, but nothing works
class netD(nn.Module):
def __init__(self,Residual_block,num_classes = 3):
super(netD,self).__init__()
self.layer1 = nn.Sequential(
# nn.Conv2d(3,8,kernel_size=7,stride = 2,padding = 3),
nn.Conv2d(3,8,kernel_size=5,stride = 2,padding = 2),
# nn.Conv2d(3,8,kernel_size=3,stride = 2,padding = 1),
# nn.BatchNorm2d(8),
nn.LeakyReLU(0.2),
# nn.ReLU(inplace=True),
# nn.MaxPool2d(kernel_size=3,stride=2,padding=1)
nn.Conv2d(8,8,kernel_size=3,stride = 2,padding = 1),
nn.BatchNorm2d(8),
nn.LeakyReLU(0.2),
# nn.ReLU(inplace=True),
)
def resnet_block(input_channels,output_channels,num_residuals,first_block=False):
blk = []
for i in range(num_residuals):
if i == 0 and not first_block:
blk.append(
Residual_block(input_channels,output_channels,use_1x1conv = True,stride=2)
)
else:
blk.append(
Residual_block(output_channels,output_channels)
)
return blk
self.layer2 = nn.Sequential(*resnet_block(8,8,2,first_block = True))
self.layer3 = nn.Sequential(*resnet_block(8,16,2))
self.layer4 = nn.Sequential(*resnet_block(16,32,2))
self.layer5 = nn.Sequential(*resnet_block(32,64,2))
self.layer6 = nn.Sequential(*resnet_block(64,128,2))
self.layer7 = nn.Sequential(*resnet_block(128,256,2))
self.layer8 = nn.Sequential(*resnet_block(256,512,2))
self.layer9 = nn.Sequential(*resnet_block(512,1024,2))
# self.layer10 = nn.Sequential(
# nn.AdaptiveAvgPool2d((1,1)),
# nn.Flatten(),
# # nn.Linear(512, 1)
# )
self.adv_layer = nn.Sequential(nn.Flatten(),nn.Linear(1024, 1), nn.Sigmoid())
self.aux_layer = nn.Sequential(nn.Flatten(),nn.Linear(1024, num_classes), nn.Softmax())
class netG(nn.Module):
def __init__(self,Residual_block,num_classes = 3):
super(netG,self).__init__()
self.label_emb = nn.Embedding(3, 100)
self.layer0 = nn.Sequential(
nn.ConvTranspose2d(100,1024,kernel_size = 4,stride = 1,padding = 0 ,bias = False),
nn.GroupNorm(num_channels=1024,num_groups=64),
# nn.BatchNorm2d(1024),
# nn.LeakyReLU(0.2, inplace=True),
nn.ReLU(inplace=True),
# nn.UpsamplingNearest2d(scale_factor=2)
)
# self.linear0 = nn.Linear(100, 512*16*16) #(100,256)
def resnet_block(input_channels,output_channels,num_residuals):
blk = []
for i in range(num_residuals):
blk.append(
Dconv_Residual_block(output_channels,output_channels)
)
return blk
self.layer1 = nn.Sequential(
*resnet_block(1024,1024,2),
nn.ConvTranspose2d(1024,512,kernel_size = 4,stride = 2,padding = 1 ,bias = False),
nn.GroupNorm(num_channels=512,num_groups=32),
# nn.BatchNorm2d(512),
# nn.LeakyReLU(0.2, inplace=True),
nn.ReLU(inplace=True)
)
self.layer2 = nn.Sequential(
*resnet_block(512,512,2),
nn.ConvTranspose2d(512,256,kernel_size = 4,stride = 2,padding = 1 ,bias = False),
nn.GroupNorm(num_channels=256,num_groups=16),
# nn.BatchNorm2d(256),
# nn.LeakyReLU(0.2, inplace=True),
nn.ReLU(inplace=True)
)
self.layer3 = nn.Sequential(
*resnet_block(256,256,2),
nn.ConvTranspose2d(256,128,kernel_size = 4,stride = 2,padding = 1 ,bias = False),
nn.GroupNorm(num_channels=128,num_groups=8),
# nn.BatchNorm2d(128),
# nn.LeakyReLU(0.2, inplace=True),
nn.ReLU(inplace=True)
)
self.layer4 = nn.Sequential(
*resnet_block(128,128,2),
nn.ConvTranspose2d(128,64,kernel_size = 4,stride = 2,padding = 1 ,bias = False),
nn.GroupNorm(num_channels=64,num_groups=4),
# nn.BatchNorm2d(64),
# nn.LeakyReLU(0.2, inplace=True)
nn.ReLU(inplace=True)
)
self.layer5 = nn.Sequential(
*resnet_block(64,64,2),
nn.ConvTranspose2d(64,32,kernel_size = 4,stride = 2,padding = 1 ,bias = False),
nn.GroupNorm(num_channels=32,num_groups=2),
# nn.BatchNorm2d(32),
# nn.LeakyReLU(0.2, inplace=True)
nn.ReLU(inplace=True)
)
self.layer6 = nn.Sequential(
*resnet_block(32,32,2),
nn.ConvTranspose2d(32,16,kernel_size = 4,stride = 2,padding = 1 ,bias = False),
nn.GroupNorm(num_channels=16,num_groups=1),
# nn.BatchNorm2d(16),
nn.ReLU(inplace=True)
# nn.LeakyReLU(0.2, inplace=True)
)
self.layer7 = nn.Sequential(
*resnet_block(16,16,2),
nn.ConvTranspose2d(16,3,kernel_size = 4,stride = 2,padding = 1 ,bias = False),
# nn.BatchNorm2d(3),
# nn.LayerNorm([3,512,512]),
nn.Tanh()
)
batch_size = imgs.shape[0]
# Adversarial ground truths
valid = Variable(FloatTensor(batch_size, 1).fill_(1.0), requires_grad=False)
fake = Variable(FloatTensor(batch_size, 1).fill_(0.0), requires_grad=False)
# Configure input
real_imgs = Variable(imgs.type(FloatTensor))
labels = Variable(labels.type(LongTensor))
# -----------------
# Train Generator
# -----------------
optimizer_G.zero_grad()
# Sample noise and labels as generator input
z = Variable(FloatTensor(np.random.normal(0, 1, (batch_size, opt.latent_dim))))
gen_labels = Variable(LongTensor(np.random.randint(0, opt.n_classes, batch_size)))
# Generate a batch of images
gen_imgs = generator(z, gen_labels)
# Loss measures generator's ability to fool the discriminator
validity, pred_label = discriminator(gen_imgs)
g_loss = 0.5 * (criterionG(validity, valid) + auxiliary_loss(pred_label, gen_labels))
g_loss.backward()
optimizer_G.step()
# ---------------------
# Train Discriminator
# ---------------------
optimizer_D.zero_grad()
# Loss for real images
real_pred, real_aux = discriminator(real_imgs)
d_real_loss = (criterionD(real_pred, valid) + auxiliary_loss(real_aux, labels)) / 2
# Loss for fake images
fake_pred, fake_aux = discriminator(gen_imgs.detach())
d_fake_loss = (criterionD(fake_pred, fake) + auxiliary_loss(fake_aux, gen_labels)) / 2
# Total discriminator loss
d_loss = (d_real_loss + d_fake_loss) / 2
# Calculate discriminator accuracy
pred = np.concatenate([real_aux.data.cpu().numpy(), fake_aux.data.cpu().numpy()], axis=0)
gt = np.concatenate([labels.data.cpu().numpy(), gen_labels.data.cpu().numpy()], axis=0)
d_acc = np.mean(np.argmax(pred, axis=1) == gt)
d_loss.backward()
optimizer_D.step()
I have tried the simplest discriminator combined with the generator I wrote, but this structure has some effects. Why is this ? Is there something wrong with my discriminator structure? My input image is 512x512.