Почему мой генератор вырабатывает синусоиду, которая преимущественно отрицательна и стремится к -1?

Вопрос или проблема

enter image description here

Я определил свой набор данных как (x,y), где x находится в диапазоне от 0 до 2pi, а y является sin(x). Поскольку это реальные данные, label_real = 1. Я передал их дискриминатору, а для генератора я создал шум, который дает мне выход (x,y), где x — это значение, а y — sin(x). Прошу прощения за эти запутанные утверждения.
вот мой код

Генератор:

class Generator(nn.Module):
  def __init__(self, noise_size):
    super(Generator, self).__init__()

    self.main = nn.Sequential(
            nn.Linear(noise_size, 32),
            nn.ReLU(),
            nn.Linear(32, 64),
            nn.ReLU(),
            nn.Linear(64, 2),
            nn.Tanh()
    )
  def forward(self,input):
      return self.main(input)

Дискриминатор:

class Discriminator(nn.Module):
  def __init__(self, input_features):
    super(Discriminator, self).__init__()
    self.main = nn.Sequential(
         nn.Linear(input_features, 64),
            nn.ReLU(),
            nn.Linear(64, 64),
            nn.Linear(64, 1),
            nn.Sigmoid(),
    )
  def forward(self,x):
      return self.main(x).squeeze()

обучение:

z_dim = 5 # размер шума
input_feat = 2 # x,y дискриминатора
generator = Generator(z_dim)
discriminator = Discriminator(input_feat) # значение синусоидальной волны 1

criterion = nn.BCELoss()

OptimizerG = optim.Adam(generator.parameters(),lr=0.0001)
OptimizerD = optim.Adam(discriminator.parameters(),lr=0.0001)


epochs = 1000

for epoch in range(epochs):
  for i, (data) in enumerate(real_dataloader):
    real_data = data # представляет данные размера 1 batch
    batch_size = real_data.size(0) # текущий размер batch (размер данных)


    # Обучение дискриминатора

    # Для обучения дискриминатора нам нужны сгенерированный вывод и реальное изображение
    #Создание фейковых данных
    noise = torch.randn(batch_size,z_dim)
    fake_data = generator(noise)

    # создание меток
    label_real = torch.full((batch_size,),1,dtype=torch.float32)
    label_fake = torch.full((batch_size,),0,dtype=torch.float32)

    #обучение дискриминатора
    # реальные данные
    output_real = discriminator(real_data)
    lossD_real = criterion(output_real, label_real)

    #фейковые данные
    output_fake = discriminator(fake_data.detach())
    lossD_fake = criterion(output_fake, label_fake)

    lossD = lossD_real + lossD_fake

    # минимизация потерянного
    OptimizerD.zero_grad()
    lossD.backward()
    OptimizerD.step()


    #Обучение генератора
    output_fake = discriminator(fake_data)
    lossG = criterion(output_fake, label_fake) #объект loss G будет обновлен, когда вызван .backward()

    OptimizerG.zero_grad()
    lossG.backward()
    OptimizerG.step()

  #Визуализация результатов
  if(epoch%10==0):
    with torch.no_grad():
        # Построить график только после того, как генератор создал данные
        for j in range(len(fake_data.detach())):
          plt.scatter(fake_data[j,0].detach().numpy(), fake_data[j,1].detach().numpy(), color="blue", label="Data points")

        # Добавить подписи и заголовок
        plt.xlabel('Подпись оси X')
        plt.ylabel('Подпись оси Y')
        plt.title('Простой диаграмма рассеяния')
        # Показать сетку
        plt.grid(True)
        # Добавить легенду
        # plt.legend()

        # Показать график
        plt.show()

Ответ или решение

Когда генератор создает синусоиду, которая преимущественно отрицательная и близка к -1, это может быть вызвано рядом причин, связанных с неправильно настроенным процессом обучения. Давайте рассмотрим возможные теоретические причины, изучим ваш сценарий с примером и применим возможные решения для устранения проблемы.

Теория

  1. Несбалансированное обучение: В вашей программе генератор и дискриминатор должны обучаться сбалансировано. Дискриминатор может научиться различать реальные и сгенерированные данные слишком быстро, что оставляет генератор в невыгодном положении, и он не может эффективно улучшать свои результаты.

  2. Шум и архитектура генератора: Качество шума, подаваемого в генератор, играет значительную роль в создании выходных данных. Если пространство шума неподходящее, генератор может учиться неправильно.

  3. Функция активации: Использование фукнции Tanh в последнем слое генератора означает, что выходные значения стремятся к диапазону [-1, 1]. Это может быть проблемой, если сеть не правильно обучается распределять значения по всему этому диапазону.

  4. Параметры обучения: Скорость обучения и конструкция сети (например, число нейронов или слоев) могут существенно влиять на результат. Слишком высокая или низкая скорость обучения может привести к неустойчивости модели.

  5. Функция потерь: Использование BCELoss предполагает, что выходные данные находятся в диапазоне [0, 1], а Sigmoid на выходе дискриминатора согласуется с этой целью. Однако функция Tanh в генераторе может привести к конфликтации между сгенерированными и реальными данными.

Пример

Ваша нейронная сеть имеет недостатки, связанные с ее конфигурацией и процессом обучения. Рассмотрим несколько возможных проблем и их влияние на результат:

  • Несоответствие меток при обучении генератора: В вашем коде при обновлении генератора используется метка label_fake, которая установлена в 0. Однако генератор должен стремиться "обмануть" дискриминатор, думая, что сгенерированные данные реальные (т.е., метка должна быть 1).

  • Архитектура генератора: Сеть проходит через несколько линейных слоев с релу активациями перед танхом. Это может ограничивать способность генератора исследовать полное пространство функции синуса в связи с аттрактором около нуля, что приводит к преимущественно отрицательным значениям.

Вот исправления, которые можно применить:

# Исправление функции потерь для тренировки генератора
# Используем label_real, чтобы дискриминатор думал, что сгенерированные данные реальные
lossG = criterion(output_fake, label_real) 

OptimizerG.zero_grad()
lossG.backward()
OptimizerG.step()

Применение

Оценка и корректировка архитектуры и параметров:

  1. Скорость обучения: Попробуйте эксперименты с разной скоростью обучения. Возможно, ваша текущая скорость делает модель слишком вялой или наоборот, приводит к большому скачкообразному изменению весов, что может дестабилизировать процесс обучения.

  2. Шумовые данные: Увеличьте размерность шумового пространства. Дополнительные признаки в главном входе генератора могут позволить сгенерированным данным быть более разнообразными и реалистичными.

  3. Функция активации: Рассмотрите возможность замены Tanh на другую функцию активации или добавления других нелинейностей, которые могли бы дать модели возможность лучше изучить распределение данных.

  4. Уравновешивание генератора и дискриминатора: Убедитесь, что оба компонента обучаются с согласованными темпами. Возможное решение — периодически проводить дополнительный шаг обучения только для одного из них, если другие параметры не помогут.

  5. Целевая метка: Исправьте метку для обучения генератора, как указано в примере, чтобы генератор обучался обманывать дискриминатор, что обеспечит более реалистичные результаты.

С учетом вышеописанных корректировок и тщательным экспериментированием с параметрами, ваш генератор должен будет более эффективно изучать нужное пространство синусоидальных функций, обеспечивая выходную волну, приближенно схожую с настоящими данными.

Оцените материал
Добавить комментарий

Капча загружается...