【问题标题】:How to feed a image to Generator in GAN Pytorch如何在 GAN Pytorch 中将图像输入到生成器
【发布时间】:2021-06-21 16:00:10
【问题描述】:

所以,我在 celeba 数据集(人)的 pytorch 中训练 DCGAN 模型。这是生成器的架构:

Generator(
  (main): Sequential(
    (0): ConvTranspose2d(100, 512, kernel_size=(4, 4), stride=(1, 1), bias=False)
    (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU(inplace=True)
    (3): ConvTranspose2d(512, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU(inplace=True)
    (6): ConvTranspose2d(256, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (7): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (8): ReLU(inplace=True)
    (9): ConvTranspose2d(128, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (10): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (11): ReLU(inplace=True)
    (12): ConvTranspose2d(64, 3, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (13): Tanh()
  )
)

所以在训练之后,如果我输入这样的遮挡图像,我想检查生成器的输出: (尺寸:64X64)

但您可能已经猜到图像有 3 个通道,并且我的生成器在开始时接受 100 个通道的潜在向量,那么将这个图像提供给生成器并检查输出的正确方法是什么? (我期望生成器仅尝试生成图像的被遮挡部分)。如果您想要参考代码,请尝试 this pytorch 的演示文件。我已经根据自己的需要修改了这个文件,所以作为参考,这样就可以了。

【问题讨论】:

    标签: pytorch generative-adversarial-network dcgan


    【解决方案1】:

    你不能那样做。正如您所说,您的网络需要 100 维输入,通常从标准正态分布中采样:

    所以生成器的工作是获取这个随机向量并生成与真实图像无法区分的 3x64x64 图像。输入是从标准正态分布中采样的随机 100 维向量。在不修改架构和重新训练新模型的情况下,我看不到任何将图像输入到当前网络的方法。如果你想尝试一个新模型,你可以将输入更改为被遮挡的图像,应用一些 conv。 / 线性层将维度减少到 100,然后保持网络的其余部分相同。这样,网络将尝试学习生成图像,而不是从潜在向量,而是从被遮挡图像中提取的特征向量。它可能有效,也可能无效。

    编辑我决定试一试,看看网络是否可以使用这种类型的条件输入向量而不是潜在向量进行学习。我使用了您链接的教程示例并添加了一些更改。首先是一个用于接收输入并将其减少到 100 维的新网络:

    class ImageTransformer(nn.Module):
        def __init__(self):
            super(ImageTransformer, self).__init__()
            self.main = nn.Sequential(
                nn.Conv2d(3, 1, 4, 2, 1, bias=False),
                nn.LeakyReLU(0.2, inplace=True)
            )            
    
            self.linear = nn.Linear(32*32, 100)
    
        def forward(self, input):
            out = self.main(input).view(input.shape[0], -1)
            return self.linear(out).view(-1, 100, 1, 1)
    

    只需一个简单的卷积层 + relu + 线性层即可在输出端映射到 100 维。请注意,您可以在这里尝试更好的网络作为更好的特征提取器,我只是想做一个简单的测试。

    fixed_input = next(iter(dataloader))[0][0:64, :, : ,:]
    fixed_input[:, :, 20:44, 20:44] = torch.tensor(np.zeros((24,24), dtype = np.float32))
    fixed_input = fixed_input.to(device)
    

    这就是我修改张量以在输入上添加黑色补丁的方式。只需采样一批以创建固定输入来跟踪过程,就像教程中使用随机向量完成的那样。

    # Create the generator
    netG = Generator().to(device)
    netD = Discriminator().to(device)
    netT = ImageTransformer().to(device)
    
    # Apply the weights_init function to randomly initialize all weights
    #  to mean=0, stdev=0.2.
    netG.apply(weights_init)
    netD.apply(weights_init)
    netT.apply(weights_init)
    
    # Print the model
    print(netG)
    print(netD)
    print(netT)
    

    大部分步骤都是一样的,只是创建了新变压器网络的一个实例。最后,对训练循环稍作修改,其中生成器不输入随机向量,而是给定新变压器网络的输出。

    img_list = []
    G_losses = []
    D_losses = []
    iters = 0
    
    for epoch in range(num_epochs):
        for i, data in enumerate(dataloader, 0):
    
            ############################
            # (1) Update D network: maximize log(D(x)) + log(1 - D(G(z)))
            ###########################
            ## Train with all-real batch
            netD.zero_grad()
            transformed = data[0].detach().clone()
            transformed[:, :, 20:44, 20:44] = torch.tensor(np.zeros((24,24), dtype = np.float32))
            transformed = transformed.to(device)
            real_cpu = data[0].to(device)
            b_size = real_cpu.size(0)
            label = torch.full((b_size,), real_label, dtype=torch.float, device=device)
            output = netD(real_cpu).view(-1)
            errD_real = criterion(output, label)
            errD_real.backward()
            D_x = output.mean().item()
    
            ## Train with all-fake batch
            fake = netT(transformed)
            fake = netG(fake)
            label.fill_(fake_label)
            output = netD(fake.detach()).view(-1)
            errD_fake = criterion(output, label)
            errD_fake.backward()
            D_G_z1 = output.mean().item()
            errD = errD_real + errD_fake
            optimizerD.step()
    
            ############################
            # (2) Update G network: maximize log(D(G(z)))
            ###########################
            netG.zero_grad()
            label.fill_(real_label)
            output = netD(fake).view(-1)
            errG = criterion(output, label)
            errG.backward()
            D_G_z2 = output.mean().item()
            optimizerG.step()
    
            # Output training stats
            if i % 50 == 0:
                print('[%d/%d][%d/%d]\tLoss_D: %.4f\tLoss_G: %.4f\tD(x): %.4f\tD(G(z)): %.4f / %.4f'
                      % (epoch, num_epochs, i, len(dataloader),
                         errD.item(), errG.item(), D_x, D_G_z1, D_G_z2))
    
            # Save Losses for plotting later
            G_losses.append(errG.item())
            D_losses.append(errD.item())
    
            # Check how the generator is doing by saving G's output on fixed_noise
            if (iters % 500 == 0) or ((epoch == num_epochs-1) and (i == len(dataloader)-1)):
                with torch.no_grad():
                    fake = netT(fixed_input)
                    fake = netG(fake).detach().cpu()
                img_list.append(vutils.make_grid(fake, padding=2, normalize=True))
    
            iters += 1
    

    在减少损失等方面训练还可以。最后这是我经过 5 个 epoch 训练后得到的结果:

    那么这个结果告诉我们什么?由于生成器的输入不是从正态分布中随机获取的,因此生成器无法学习人脸的分布来创建不同范围的输出人脸。而且由于输入是条件特征向量,输出图像的范围是有限的。所以总而言之,生成器需要随机输入,即使它学会了删除补丁:)

    【讨论】:

    • 首先,感谢您所做的所有工作,我真的很感激。最初,我只需要一种方法来提供图像以生成你通过 ImageTransformer 所做的。甚至我也想过,但只是不确定。无论如何,谢谢 :) 其次,我所做的是,我用随机输入训练了生成器,然后我的目标是检查生成器在这些被遮挡的图像上的表现,看看我可以做出哪些改进来生成更好和多样化的图像。
    • 这样,我也许能够产生好的结果。另外,感谢自动放置补丁的方式。我一开始是手动做的:'(。但现在它会很容易。另外,如果您对我的计划方式有任何其他疑问或见解,请分享......我真的很感激。
    • 另外,我对特征提取器不太了解,所以如果你知道任何可以帮助我的东西,那就太好了..
    • 顺便说一句...我尝试通过 ImageTransformer 将图像提供给生成器...因为我的生成器接受了来自生成器的一组随机输入的训练,所以我认为提供这些图像不会一个问题...但是正如您所说,生成器确实学习了如何删除补丁,但它无法生成与没有补丁的原始图像几乎相似的各种输出或输出,可能是因为我们正在提供条件特征向量它可能会停留在范围有限的局部最小值......
    • 不幸的是我没有想到。这是我能做的最好的了
    猜你喜欢
    • 2021-11-28
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    • 2022-07-25
    相关资源
    最近更新 更多