Вопрос или проблема
Я определил свой набор данных как (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, это может быть вызвано рядом причин, связанных с неправильно настроенным процессом обучения. Давайте рассмотрим возможные теоретические причины, изучим ваш сценарий с примером и применим возможные решения для устранения проблемы.
Теория
-
Несбалансированное обучение: В вашей программе генератор и дискриминатор должны обучаться сбалансировано. Дискриминатор может научиться различать реальные и сгенерированные данные слишком быстро, что оставляет генератор в невыгодном положении, и он не может эффективно улучшать свои результаты.
-
Шум и архитектура генератора: Качество шума, подаваемого в генератор, играет значительную роль в создании выходных данных. Если пространство шума неподходящее, генератор может учиться неправильно.
-
Функция активации: Использование фукнции
Tanh
в последнем слое генератора означает, что выходные значения стремятся к диапазону [-1, 1]. Это может быть проблемой, если сеть не правильно обучается распределять значения по всему этому диапазону. -
Параметры обучения: Скорость обучения и конструкция сети (например, число нейронов или слоев) могут существенно влиять на результат. Слишком высокая или низкая скорость обучения может привести к неустойчивости модели.
-
Функция потерь: Использование
BCELoss
предполагает, что выходные данные находятся в диапазоне [0, 1], аSigmoid
на выходе дискриминатора согласуется с этой целью. Однако функцияTanh
в генераторе может привести к конфликтации между сгенерированными и реальными данными.
Пример
Ваша нейронная сеть имеет недостатки, связанные с ее конфигурацией и процессом обучения. Рассмотрим несколько возможных проблем и их влияние на результат:
-
Несоответствие меток при обучении генератора: В вашем коде при обновлении генератора используется метка
label_fake
, которая установлена в 0. Однако генератор должен стремиться "обмануть" дискриминатор, думая, что сгенерированные данные реальные (т.е., метка должна быть 1). -
Архитектура генератора: Сеть проходит через несколько линейных слоев с релу активациями перед танхом. Это может ограничивать способность генератора исследовать полное пространство функции синуса в связи с аттрактором около нуля, что приводит к преимущественно отрицательным значениям.
Вот исправления, которые можно применить:
# Исправление функции потерь для тренировки генератора
# Используем label_real, чтобы дискриминатор думал, что сгенерированные данные реальные
lossG = criterion(output_fake, label_real)
OptimizerG.zero_grad()
lossG.backward()
OptimizerG.step()
Применение
Оценка и корректировка архитектуры и параметров:
-
Скорость обучения: Попробуйте эксперименты с разной скоростью обучения. Возможно, ваша текущая скорость делает модель слишком вялой или наоборот, приводит к большому скачкообразному изменению весов, что может дестабилизировать процесс обучения.
-
Шумовые данные: Увеличьте размерность шумового пространства. Дополнительные признаки в главном входе генератора могут позволить сгенерированным данным быть более разнообразными и реалистичными.
-
Функция активации: Рассмотрите возможность замены
Tanh
на другую функцию активации или добавления других нелинейностей, которые могли бы дать модели возможность лучше изучить распределение данных. -
Уравновешивание генератора и дискриминатора: Убедитесь, что оба компонента обучаются с согласованными темпами. Возможное решение — периодически проводить дополнительный шаг обучения только для одного из них, если другие параметры не помогут.
-
Целевая метка: Исправьте метку для обучения генератора, как указано в примере, чтобы генератор обучался обманывать дискриминатор, что обеспечит более реалистичные результаты.
С учетом вышеописанных корректировок и тщательным экспериментированием с параметрами, ваш генератор должен будет более эффективно изучать нужное пространство синусоидальных функций, обеспечивая выходную волну, приближенно схожую с настоящими данными.