Почему не меняются потери Дискриминатора и Генератора?

Я пытаюсь реализовать генерирующую состязательную сеть (GAN) для набора данных MNIST. Для этого я использую Pytorch. Моя проблема в том, что после одной эпохи потери Дискриминатора и Генератора не меняются.

Я уже пробовал два других метода построения сети, но они вызывают все те же проблемы: /

import os
import torch
import matplotlib.pyplot as plt
import matplotlib.gridspec as grd
import numpy as np
import torch.optim as optim
import torch.nn as nn 
import torch.nn.functional as F 
import torchvision #Datasets
from torchvision.utils import save_image
import torchvision.transforms as transforms
from torch.autograd import Variable
import pylab

#Parameter
batch_size = 64
epochs = 50000
image_size = 784
hidden_size = 392
sample_dir = 'samples'
save_dir = 'save'
noise_size = 100
lr = 0.001

# Image processing
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,),(0.5,))])

# Discriminator
D = nn.Sequential(
    nn.Linear(image_size, hidden_size),
    nn.ReLU(),
    nn.Linear(hidden_size, 1),
    nn.Sigmoid()
)

# Generator
G = nn.Sequential(
    nn.Linear(noise_size, hidden_size),
    nn.ReLU(),
    nn.Linear(hidden_size, image_size),
    nn.Sigmoid()
)

# Lossfunction and optimizer (sigmoid cross entropy with logits and Adam)
criterion = nn.BCEWithLogitsLoss()
d_optimizer = torch.optim.Adam(D.parameters(), lr = lr)
g_optimizer = torch.optim.Adam(G.parameters(), lr = lr)

def reset_grad():
    d_optimizer.zero_grad()
    g_optimizer.zero_grad()

# Statistics to be saved
d_losses = np.zeros(epochs)
g_losses = np.zeros(epochs)
real_scores = np.zeros(epochs)
fake_scores = np.zeros(epochs)

# Start training
total_step = len(data_loader)
for epoch in range(epochs):
    for i, (images, _) in enumerate(data_loader):
        if images.shape[0] != 64:
            continue
        images = images.view(batch_size, -1).cuda()
        images = Variable(images)
        # Create the labels which are later used as input for the BCE loss
        real_labels = torch.ones(batch_size, 1).cuda()
        real_labels = Variable(real_labels)
        fake_labels = torch.zeros(batch_size, 1).cuda()
        fake_labels = Variable(fake_labels)

        # Train discriminator

        # Compute BCE_WithLogitsLoss using real images 
        outputs = D(images)
        d_loss_real = criterion(outputs, real_labels)
        real_score = outputs

        # Compute BCE_WithLogitsLoss using fake images
        # First term of the loss is always zero since fake_labels == 0
        z = torch.randn(batch_size, noise_size).cuda()
        z = Variable(z)
        fake_images = G(z)
        outputs = D(fake_images)
        d_loss_fake = criterion(outputs, fake_labels)
        fake_score = outputs

        # Backprop and optimize
        # If D is trained so well, then don't update
        d_loss = d_loss_real + d_loss_fake
        reset_grad()
        d_loss.backward()
        d_optimizer.step()

        # Train generator 

        # Compute loss with fake images
        z = torch.randn(batch_size, noise_size).cuda()
        z = Variable(z)
        fake_images = G(z)
        outputs = D(fake_images)

        # We train G to maximize log(D(G(z)) instead of minimizing log(1 -D(G(z)))
        # For the reason, see the last paragraph of section 3. https://arxiv.org/pdf/1406.2661.pdf
        g_loss = criterion(outputs, real_labels)

        # Backprop and optimize
        # if G is trained so well, then don't update
        reset_grad()
        g_loss.backward()
        g_optimizer.step()

        # Update statistics

        d_losses[epoch] = d_losses[epoch]*(i/(i+1.)) + d_loss.item()*(1./(i+1.))
        g_losses[epoch] = g_losses[epoch]*(i/(i+1.)) + g_loss.item()*(1./(i+1.))
        real_scores[epoch] = real_scores[epoch]*(i/(i+1.)) + real_score.mean().item()*(1./(i+1.))
        fake_scores[epoch] = fake_scores[epoch]*(i/(i+1.)) + fake_score.mean().item()*(1./(i+1.))

    # print results
    print('Epoch [{}/{}], d_loss: {:.4f}, g_loss: {:.4f}, D(x): {:.2f}, D(G(z)): {:.2f}' 
            .format(epoch, epochs, d_loss.item(), g_loss.item(), 
                    real_score.mean().item(), fake_score.mean().item()))

Потери Генератора и Дискриминатора должны меняться от эпохи к эпохе, но это не так.

Epoch [0/50000], d_loss: 1.0069, g_loss: 0.6927, D(x): 1.00, D(G(z)): 0.00
Epoch [1/50000], d_loss: 1.0065, g_loss: 0.6931, D(x): 1.00, D(G(z)): 0.00
Epoch [2/50000], d_loss: 1.0064, g_loss: 0.6931, D(x): 1.00, D(G(z)): 0.00
Epoch [3/50000], d_loss: 1.0064, g_loss: 0.6931, D(x): 1.00, D(G(z)): 0.00
Epoch [4/50000], d_loss: 1.0064, g_loss: 0.6931, D(x): 1.00, D(G(z)): 0.00
Epoch [5/50000], d_loss: 1.0064, g_loss: 0.6931, D(x): 1.00, D(G(z)): 0.00

Спасибо за вашу помощь.


person Felijasha    schedule 01.05.2019    source источник
comment
Одна из возможных причин, которая приходит на ум, заключается в том, что вы одновременно тренируете дискриминатор и генератор. Это приведет к тому, что дискриминатор станет намного сильнее, поэтому генератору сложнее (почти невозможно) превзойти его, и нет места для улучшения дискриминатора. Обычно генераторная сеть обучается чаще, чем дискриминатор.   -  person Bahman Rouhani    schedule 01.05.2019
comment
Спасибо за Ваш ответ. Я использовал шаблон из другого GAN для создания своего. Шаблон работает нормально. Я просто изменил глубину моделей, а также функцию активации и потерь, чтобы восстановить реализацию тензорного потока из дипломной работы бакалавра, которую я должен использовать в своей диссертации в PyTorch. И шаблон, и реализация тензорного потока работают нормально.   -  person Felijasha    schedule 01.05.2019
comment
Почему real_score и fake_score равны 1.0 и 0.0 соответственно? Эти оценки представляют собой средние оценки сигмовидной кишки. Как их среднее может быть 1,0 и 0,0? Также вы проверяли, меняются ли весовые параметры вашей модели?   -  person Wasi Ahmad    schedule 02.05.2019


Ответы (1)


Я нашел решение проблемы. BCEWithLogitsLoss () и Sigmoid () не работают вместе, потому что BCEWithLogitsLoss () включает активацию Sigmoid. Таким образом, вы можете использовать BCEWithLogitsLoss () без Sigmoid () или вы можете использовать Sigmoid () и BCELoss ()

person Felijasha    schedule 01.05.2019
comment
Однако я бы не рекомендовал использовать Sigmoid для дискриминатора GAN. - person Thư Sinh; 26.06.2021