web-dev-qa-db-ja.com

PyTorchを使用した新しい画像の生成

入力した例に基づいて画像を生成するプログラムの例を示した1つのコースを修了したGANを勉強しています。

例はここにあります:

https://github.com/davidsonmizael/gan

そこで、それを使って顔の正面写真のデータセットに基づいて新しい画像を生成することにしましたが、成功していません。上記の例とは異なり、入力には実際の画像が含まれているのに対し、コードはノイズのみを生成します。

実際、コードが正しい方向を指し、画像から学ぶために何を変更すればよいかについての手がかりはありません。例で提供されているコードの単一の値を変更していませんが、機能しません。

誰かが私がこれを理解し、正しい方向に私を向けるのを手伝ってくれるなら、とても役に立ちます。前もって感謝します。

私の弁別器:

class D(nn.Module):

    def __init__(self):
        super(D, self).__init__()
        self.main = nn.Sequential(
                nn.Conv2d(3, 64, 4, 2, 1, bias = False),
                nn.LeakyReLU(0.2, inplace = True),
                nn.Conv2d(64, 128, 4, 2, 1, bias = False),
                nn.BatchNorm2d(128),
                nn.LeakyReLU(0.2, inplace = True),
                nn.Conv2d(128, 256, 4, 2, 1, bias = False),
                nn.BatchNorm2d(256),
                nn.LeakyReLU(0.2, inplace = True),
                nn.Conv2d(256, 512, 4, 2, 1, bias = False),
                nn.BatchNorm2d(512),
                nn.LeakyReLU(0.2, inplace = True),
                nn.Conv2d(512, 1, 4, 1, 0, bias = False),
                nn.Sigmoid()
                )

    def forward(self, input):
        return self.main(input).view(-1)

私のジェネレーター:

class G(nn.Module):

    def __init__(self):
        super(G, self).__init__()
        self.main = nn.Sequential(
                nn.ConvTranspose2d(100, 512, 4, 1, 0, bias = False),
                nn.BatchNorm2d(512),
                nn.ReLU(True),
                nn.ConvTranspose2d(512, 256, 4, 2, 1, bias = False),
                nn.BatchNorm2d(256),
                nn.ReLU(True),
                nn.ConvTranspose2d(256, 128, 4, 2, 1, bias = False),
                nn.BatchNorm2d(128),
                nn.ReLU(True),
                nn.ConvTranspose2d(128, 64, 4, 2, 1, bias = False),
                nn.BatchNorm2d(64),
                nn.ReLU(True),
                nn.ConvTranspose2d(64, 3, 4, 2, 1, bias = False),
                nn.Tanh()
                )

    def forward(self, input):
        return self.main(input)

ウェイトを開始する私の関数:

def weights_init(m):
    classname = m.__class__.__name__
    if classname.find('Conv') != -1:
        m.weight.data.normal_(0.0, 0.02)
    Elif classname.find('BatchNorm') != -1:
        m.weight.data.normal_(1.0, 0.02)
        m.bias.data.fill_(0)

完全なコードはここで見ることができます:

https://github.com/davidsonmizael/criminal-gan

エポック番号25で発生するノイズ: Noise generated on Epoch number 25

実際の画像で入力: Input with real images.

19
davis

あなたの例のコード( https://github.com/davidsonmizael/gan )は、あなたが示しているのと同じノイズを私に与えました。発電機の損失はあまりにも急速に減少しました。

バグがいくつかありましたが、もう何がわからないのですが、違いを自分で理解するのは簡単だと思います。比較のために、このチュートリアルもご覧ください: PyTorchの50行のGAN

.... same as your code
print("# Starting generator and descriminator...")
netG = G()
netG.apply(weights_init)

netD = D()
netD.apply(weights_init)

if torch.cuda.is_available():
    netG.cuda()
    netD.cuda()

#training the DCGANs
criterion = nn.BCELoss()
optimizerD = optim.Adam(netD.parameters(), lr = 0.0002, betas = (0.5, 0.999))
optimizerG = optim.Adam(netG.parameters(), lr = 0.0002, betas = (0.5, 0.999))

epochs = 25

timeElapsed = []
for Epoch in range(epochs):
    print("# Starting Epoch [%d/%d]..." % (Epoch, epochs))
    for i, data in enumerate(dataloader, 0):
        start = time.time()
        time.clock()  

        #updates the weights of the discriminator nn
        netD.zero_grad()

        #trains the discriminator with a real image
        real, _ = data

        if torch.cuda.is_available():
            inputs = Variable(real.cuda()).cuda()
            target = Variable(torch.ones(inputs.size()[0]).cuda()).cuda()
        else:
            inputs = Variable(real)
            target = Variable(torch.ones(inputs.size()[0]))

        output = netD(inputs)
        errD_real = criterion(output, target)
        errD_real.backward() #retain_graph=True

        #trains the discriminator with a fake image
        if torch.cuda.is_available():
            D_noise = Variable(torch.randn(inputs.size()[0], 100, 1, 1).cuda()).cuda()
            target = Variable(torch.zeros(inputs.size()[0]).cuda()).cuda()
        else:
            D_noise = Variable(torch.randn(inputs.size()[0], 100, 1, 1))
            target = Variable(torch.zeros(inputs.size()[0]))
        D_fake = netG(D_noise).detach()
        D_fake_ouput = netD(D_fake)
        errD_fake = criterion(D_fake_ouput, target)
        errD_fake.backward()

        # NOT:backpropagating the total error
        # errD = errD_real + errD_fake

        optimizerD.step()

    #for i, data in enumerate(dataloader, 0):

        #updates the weights of the generator nn
        netG.zero_grad()

        if torch.cuda.is_available():
            G_noise = Variable(torch.randn(inputs.size()[0], 100, 1, 1).cuda()).cuda()
            target = Variable(torch.ones(inputs.size()[0]).cuda()).cuda()
        else:
            G_noise = Variable(torch.randn(inputs.size()[0], 100, 1, 1))
            target = Variable(torch.ones(inputs.size()[0]))

        fake = netG(G_noise)
        G_output = netD(fake)
        errG  = criterion(G_output, target)

        #backpropagating the error
        errG.backward()
        optimizerG.step()


        if i % 50 == 0:
            #prints the losses and save the real images and the generated images
            print("# Progress: ")
            print("[%d/%d][%d/%d] Loss_D: %.4f Loss_G: %.4f" % (Epoch, epochs, i, len(dataloader), errD_real.data[0], errG.data[0]))

            #calculates the remaining time by taking the avg seconds that every loop
            #and multiplying by the loops that still need to run
            timeElapsed.append(time.time() - start)
            avg_time = (sum(timeElapsed) / float(len(timeElapsed)))
            all_dtl = (Epoch * len(dataloader)) + i
            rem_dtl = (len(dataloader) - i) + ((epochs - Epoch) * len(dataloader))
            remaining =  (all_dtl - rem_dtl) * avg_time
            print("# Estimated remaining time: %s" % (time.strftime("%H:%M:%S", time.gmtime(remaining))))

        if i % 100 == 0:
            vutils.save_image(real, "%s/real_samples.png" % "./results", normalize = True)
            vutils.save_image(fake.data, "%s/fake_samples_Epoch_%03d.png" % ("./results", Epoch), normalize = True)

print ("# Finished.")

CIFAR-10で25エポック(バッチサイズ256)後の結果: enter image description here

4
Forcetti

GANトレーニングはそれほど速くありません。事前にトレーニングされたモデルを使用していないと想定していますが、最初から学習しています。エポック25では、サンプルに意味のあるパターンが見られないのはごく普通のことです。 githubプロジェクトは、25エポック後に何かクールなものを示していることを理解していますが、それはデータセットのサイズにも依存します。 CIFAR-10(githubページで使用されたもの)には60000枚の画像があります。 25エポックは、ネットがそれらすべてを25回見たことを意味します。

使用しているデータセットはわかりませんが、小さい場合は、ネットで表示される画像が少なくなるため、結果が表示されるまでにエポックが長くなる可能性があります。データセット内の画像の解像度が高い場合は、さらに時間がかかる可能性があります。

数千エポックではないにしても、少なくとも数百エポック後にもう一度確認する必要があります。


例えば。 25エポック後の正面顔写真データセット: enter image description here

そして50エポックの後: enter image description here

1
RunOrVeith