当前位置:  开发笔记 > 编程语言 > 正文

越来越大的正WGAN-GP损失

如何解决《越来越大的正WGAN-GP损失》经验,为你挑选了1个好方法。

我正在研究在PyTorch中使用具有梯度损失的Wasserstein GAN,但始终会产生较大的正发电机损失,并随着时间的推移而增加。我大量借用了曹刚的实现,但是我正在使用此实现中使用的鉴别器和生成器损耗,因为Invalid gradient at index 0 - expected shape[] but got [1]如果尝试调用曹刚实现中使用.backward()onemoneargs,我会得到。

我正在使用增强的WikiArt数据集(> 400k 64x64图像)和CIFAR-10进行训练,并且获得了正常的WGAN(具有权重剪切功能)[即,它在25个时期后产生了可通过的图像],尽管事实上D和G损失在torch.mean(D_real)所有时期都徘徊在3 [我用等计算]。但是,在WGAN-GP版本中,发电机损耗在WikiArt和CIFAR-10数据集上都急剧增加,并且完全无法在WikiArt上产生噪声。

这是在CIFAR-10上经过25个纪元后的损失示例:

我没有使用单面标签平滑等技巧,并且使用默认学习率0.001进行训练,使用Adam优化器,并且每次生成器更新时,对鉴别器进行5次训练。为什么会发生这种疯狂的丢失行为,为什么正常的减肥瘦身WGAN在WikiArt上仍然“起作用”,但WGANGP完全失败了?

无论G和D都是DCGAN还是使用改良的DCGAN时,都会发生这种情况,这是创意对抗网络(Creative Adversarial Network),它要求D能够对图像进行分类,并且G生成模糊图像。

以下是我当前train方法的相关部分:

self.generator = Can64Generator(self.z_noise, self.channels, self.num_gen_filters).to(self.device)
self.discriminator =WCan64Discriminator(self.channels,self.y_dim, self.num_disc_filters).to(self.device)
style_criterion = nn.CrossEntropyLoss()

self.disc_optimizer = optim.Adam(self.discriminator.parameters(), lr=self.lr, betas=(self.beta1, 0.9))
self.gen_optimizer = optim.Adam(self.generator.parameters(), lr=self.lr, betas=(self.beta1, 0.9))


while i < len(dataloader):
            j = 0
            disc_loss_epoch = []
            gen_loss_epoch = []
            if self.type == "can":
                disc_class_loss_epoch = []
                gen_class_loss_epoch = []

            if self.gradient_penalty == False:
                # critic training methodology in official WGAN implementation
                if gen_iterations < 25 or (gen_iterations % 500 == 0):
                    disc_iters = 100
            else:
                disc_iters = self.disc_iterations

            while j < disc_iters and (i < len(dataloader)):
                # if using wgan with weight clipping
                if self.gradient_penalty == False:
                    # Train Discriminator
                    for param in self.discriminator.parameters():
                        param.data.clamp_(self.lower_clamp,self.upper_clamp)


                for param in self.discriminator.parameters():
                    param.requires_grad_(True)

                j+=1
                i+=1
                data = data_iterator.next()
                self.discriminator.zero_grad()
                real_images, image_labels = data
                # image labels are the the image's classes (e.g. Impressionism)
                real_images = real_images.to(self.device) 
                batch_size = real_images.size(0)
                real_image_labels = torch.LongTensor(batch_size).to(self.device)
                real_image_labels.copy_(image_labels)

                labels = torch.full((batch_size,),real_label,device=self.device)

                if self.type == 'can':
                    predicted_output_real, predicted_styles_real = self.discriminator(real_images.detach())
                    predicted_styles_real = predicted_styles_real.to(self.device)
                    disc_class_loss = style_criterion(predicted_styles_real,real_image_labels)
                    disc_class_loss.backward(retain_graph=True)

                else:
                    predicted_output_real = self.discriminator(real_images.detach())

                disc_loss_real = -torch.mean(predicted_output_real)


                # fake

                noise = torch.randn(batch_size,self.z_noise,1,1,device=self.device)
                with torch.no_grad():
                    noise_g = noise.detach()
                fake_images = self.generator(noise_g)
                labels.fill_(fake_label)

                if self.type == 'can':
                    predicted_output_fake, predicted_styles_fake = self.discriminator(fake_images)

                else:
                    predicted_output_fake = self.discriminator(fake_images)



                disc_gen_z_1 = predicted_output_fake.mean().item()

                disc_loss_fake = torch.mean(predicted_output_fake)


                #via https://github.com/znxlwm/pytorch-generative-model-collections/blob/master/WGAN_GP.py
                if self.gradient_penalty:
                    # gradient penalty
                    alpha = torch.rand((real_images.size()[0], 1, 1, 1)).to(self.device) 
                    x_hat = alpha * real_images.data + (1 - alpha) * fake_images.data
                    x_hat.requires_grad_(True)
                    if self.type == 'can':
                        pred_hat, _ = self.discriminator(x_hat)
                    else:
                        pred_hat = self.discriminator(x_hat)
                    gradients = grad(outputs=pred_hat, inputs=x_hat, grad_outputs=torch.ones(pred_hat.size()).to(self.device),
                                    create_graph=True, retain_graph=True, only_inputs=True)[0]

                    gradient_penalty = lambda_ * ((gradients.view(gradients.size()[0], -1).norm(2, 1) - 1) ** 2).mean()
                    disc_loss = disc_loss_fake + disc_loss_real + gradient_penalty
                else:
                    disc_loss  =  disc_loss_fake  + disc_loss_real


                if self.type == 'can':
                    disc_loss += disc_class_loss.mean()

                disc_x = disc_loss.mean().item()
                disc_loss.backward(retain_graph=True)
                self.disc_optimizer.step()



            # train generator
            for param in self.discriminator.parameters():
                param.requires_grad_(False)

            self.generator.zero_grad()
            labels.fill_(real_label)

            if self.type == 'can':
                predicted_output_fake, predicted_styles_fake = self.discriminator(fake_images)
                predicted_styles_fake = predicted_styles_fake.to(self.device)

            else:
                predicted_output_fake = self.discriminator(fake_images)

            gen_loss = -torch.mean(predicted_output_fake)
            disc_gen_z_2 = gen_loss.mean().item()

            if self.type == 'can':
                fake_batch_labels = 1.0/self.y_dim * torch.ones_like(predicted_styles_fake)
                fake_batch_labels = torch.mean(fake_batch_labels,1).long().to(self.device)
                gen_class_loss = style_criterion(predicted_styles_fake,fake_batch_labels)
                gen_class_loss.backward(retain_graph=True)
                gen_loss += gen_class_loss.mean()

            gen_loss.backward()
            gen_iterations += 1

这是(DCGAN)生成器的代码:

class Can64Generator(nn.Module):
def __init__(self, z_noise, channels, num_gen_filters):
    super(Can64Generator,self).__init__()
    self.ngpu = 1
    self.main = nn.Sequential(
    nn.ConvTranspose2d(z_noise, num_gen_filters * 16, 4, 1, 0, bias=False),
    nn.BatchNorm2d(num_gen_filters * 16),
    nn.ReLU(True),
    nn.ConvTranspose2d(num_gen_filters * 16, num_gen_filters * 4, 4, 2, 1, bias=False),
    nn.BatchNorm2d(num_gen_filters * 4),
    nn.ReLU(True),
    nn.ConvTranspose2d(num_gen_filters * 4, num_gen_filters * 2, 4, 2, 1, bias=False),
    nn.BatchNorm2d(num_gen_filters * 2),
    nn.ReLU(True),
    nn.ConvTranspose2d(num_gen_filters * 2, num_gen_filters, 4, 2, 1, bias=False),
    nn.BatchNorm2d(num_gen_filters),
    nn.ReLU(True),
    nn.ConvTranspose2d(num_gen_filters, 3, 4, 2, 1, bias=False),
    nn.Tanh()
    )
def forward(self, inp):
    output = self.main(inp)
    return output

这是(当前)CAN鉴别器,它具有用于样式(图像类)分类的额外层):

class Can64Discriminator(nn.Module):

def __init__(self, channels,y_dim, num_disc_filters):
        super(Can64Discriminator, self).__init__()
        self.ngpu = 1
        self.conv = nn.Sequential(
                nn.Conv2d(channels, num_disc_filters // 2, 4, 2, 1, bias=False),
                nn.LeakyReLU(0.2, inplace=True),

                nn.Conv2d(num_disc_filters // 2, num_disc_filters, 4, 2, 1, bias=False),
                nn.BatchNorm2d(num_disc_filters),
                nn.LeakyReLU(0.2, inplace=True),

                nn.Conv2d(num_disc_filters, num_disc_filters * 2, 4, 2, 1, bias=False),
                nn.BatchNorm2d(num_disc_filters * 2),
                nn.LeakyReLU(0.2, inplace=True),

                nn.Conv2d(num_disc_filters * 2, num_disc_filters * 4, 4, 2, 1, bias=False),
                nn.BatchNorm2d(num_disc_filters * 4),
                nn.LeakyReLU(0.2, inplace=True),

                nn.Conv2d(num_disc_filters * 4, num_disc_filters * 8, 4, 1, 0, bias=False),
                nn.BatchNorm2d(num_disc_filters * 8),
                nn.LeakyReLU(0.2, inplace=True),

            )
        # was this
        #self.final_conv = nn.Conv2d(num_disc_filters * 8, num_disc_filters * 8, 4, 2, 1, bias=False)

        self.real_fake_head = nn.Linear(num_disc_filters * 8, 1)

        # no bn and lrelu needed
        self.sig = nn.Sigmoid()
        self.fc = nn.Sequential() 
        self.fc.add_module("linear_layer{0}".format(num_disc_filters*16),nn.Linear(num_disc_filters*8,num_disc_filters*16))
        self.fc.add_module("linear_layer{0}".format(num_disc_filters*8),nn.Linear(num_disc_filters*16,num_disc_filters*8))
        self.fc.add_module("linear_layer{0}".format(num_disc_filters),nn.Linear(num_disc_filters*8,y_dim))
        self.fc.add_module('softmax',nn.Softmax(dim=1))

def forward(self, inp):
    x = self.conv(inp)
    x = x.view(x.size(0),-1) 
    real_out = self.sig(self.real_fake_head(x))
    real_out = real_out.view(-1,1).squeeze(1)
    style = self.fc(x) 
    #style = torch.mean(style,1) # CrossEntropyLoss requires input be (N,C)
    return real_out,style

在WGANGP版本和我的GAN中WGAN版本之间的唯一区别是WGAN版本的用途RMSproplr=0.00005和剪辑鉴别的权重,按照该WGAN纸。

是什么原因造成的?我想进行尽可能小的更改,因为我想单独比较损失函数。即使在CIFAR-10上使用未经修改的DCGAN鉴别器时,也会遇到相同的问题。我是否遇到这种情况,可能是因为我目前仅训练25个纪元,还是有其他原因?有趣的是,当使用LSGAN(nn.MSELoss())时,我的GAN完全不会产生任何噪声。

提前致谢!



1> Thomas Pinet..:

鉴别器中的批次归一化以梯度罚分破坏Wasserstein GAN。作者自己主张使用层归一化,但是在他们的论文中显然以粗体显示(https://papers.nips.cc/paper/7159-improved-training-of-wasserstein-gans.pdf)。很难说代码中是否还存在其他错误,但是我敦促您通读DCGAN和Wasserstein GAN论文,并真正记下超参数。弄错它们确实会破坏GAN的性能,并且执行超参数搜索会很快变得昂贵。

顺便说一下,转置卷积会在输出图像中产生楼梯伪像。请改用图像大小调整。有关此现象的深入说明,我可以推荐以下资源(https://distill.pub/2016/deconv-checkerboard/)。

推荐阅读
k78283381
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有