基于GAN生成ID-VG曲线样本:生成数据与真实样本不符问题
GAN生成ID-VG曲线样本无法拟合真实样本中数值低于-1的部分
我在实现GAN模型生成ID-VG曲线样本时,发现生成的Fake data与真实样本存在明显差异,尤其无法拟合真实样本中数值低于-1的部分。
实现说明
本示例通过generate_real_samples函数生成真实样本,用define_generator和define_discriminator分别定义生成器与判别器网络,再通过define_gan构建GAN模型。调用train函数在真实数据集上训练模型后评估性能,但生成的虚假数据始终无法拟合真实样本中低于-1的部分。
实现代码
# train a generative adversarial network on a one-dimensional function from numpy import hstack import numpy as np from numpy import zeros from numpy import ones from numpy.random import rand from numpy.random import randn from keras.models import Sequential from keras import Input from keras.layers import Dense,LSTM from matplotlib import pyplot import matplotlib.pyplot as plt LENGTH_INPUT=50 # gate length un=900 cox=5e-3 import numpy as np # generate n real samples with class labels def generate_real_samples(n): L = np.arange(0.012,300,0.08) W = np.arange(0.02,300,0.8) vt=0.3 # freqs = np.linspace(1,2,1000) X2 = np.linspace(0.4,0.7,LENGTH_INPUT) X1 = [] for x in range(n): noise = np.random.normal(size=len(X2)) # id=un*cox*(W/L)*(i-vt)**2 X1.append(np.log(un*cox*( np.random.choice(W)/ np.random.choice(L))*(X2-vt)**2)+0.1*noise) X1 = np.array(X1).reshape(n, LENGTH_INPUT) # generate class labels y = ones((n, 1)) return X1, y import numpy as np from keras.models import Sequential from keras.layers import Dense, Reshape, Flatten from keras.layers import ELU, PReLU, LeakyReLU from keras.optimizers import Adam # Set the length input to 50 LENGTH_INPUT = 50 # Set the values for un and cox un = 900 cox = 5e-3 # Define the generator model def define_generator(latent_dim): model = Sequential() model.add(Dense(128, input_dim=latent_dim)) model.add(LeakyReLU(alpha=0.2)) model.add(Dense(256)) model.add(LeakyReLU(alpha=0.2)) model.add(Dense(LENGTH_INPUT, activation='tanh')) return model # Define the discriminator model def define_discriminator(input_shape): model = Sequential() model.add(Flatten(input_shape=input_shape)) model.add(Dense(128)) model.add(LeakyReLU(alpha=0.2)) model.add(Dense(64)) model.add(LeakyReLU(alpha=0.2)) model.add(Dense(1, activation='sigmoid')) opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy']) return model # Define the GAN model def define_gan(generator, discriminator): discriminator.trainable = False model = Sequential() model.add(generator) model.add(discriminator) opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt) return model # Generate n real samples with class labels def generate_real_samples(n): L = np.arange(0.012, 300, 0.08) W = np.arange(0.02, 300, 0.8) vt = 0.3 X2 = np.linspace(0.4, 0.7, LENGTH_INPUT) X1 = [] for x in range(n): noise = np.random.normal(size=LENGTH_INPUT) X1.append(np.log(un * cox * (np.random.choice(W) / np.random.choice(L)) * (X2 - vt) ** 2) + 0 * noise) X1 = np.array(X1).reshape(n, LENGTH_INPUT) y = np.ones((n, 1)) return X1, y # Generate latent points def generate_latent_points(latent_dim, n): x_input = np.random.randn(latent_dim * n) x_input = x_input.reshape(n, latent_dim) return x_input # Use the generator to generate n fake samples with class labels def generate_fake_samples(generator, latent_dim, n): x_input = generate_latent_points(latent_dim, n) X = generator.predict(x_input) y = np.zeros((n, 1)) return X, y # Train the generator and discriminator models def train(g_model, d_model, gan_model, latent_dim, n_epochs, n_batch): half_batch = int(n_batch / 2) n_eval=50 for i in range(n_epochs): # Train discriminator on real samples X_real, y_real = generate_real_samples(half_batch) d_loss_real, _ = d_model.train_on_batch(X_real, y_real) # Train discriminator on fake samples X_fake, y_fake = generate_fake_samples(g_model, latent_dim, half_batch) d_loss_fake, _ = d_model.train_on_batch(X_fake, y_fake) # Train generator via the GAN model x_gan = generate_latent_points(latent_dim, n_batch) y_gan = np.ones((n_batch, 1)) g_loss = gan_model.train_on_batch(x_gan, y_gan) # Print progress print('Epoch %d/%d, Discriminator Loss: [Real: %.3f, Fake: %.3f], Generator Loss: %.3f' % (i+1, n_epochs, d_loss_real, d_loss_fake, g_loss)) if (i+1) % n_eval == 0: plt.title('Number of epochs = %i'%(i+1)) pred_data = generate_fake_samples(generator,latent_dim,latent_dim)[0] real_data = generate_real_samples(latent_dim)[0] plt.plot(pred_data[0],'.',label='Random Fake Sample',color='firebrick') plt.plot(real_data[0],'.',label = 'Random Real Sample',color='navy') plt.legend(fontsize=10) plt.show() # Define the size of the latent space latent_dim = 100 # Create the generator, discriminator, and GAN models generator = define_generator(latent_dim) discriminator = define_discriminator((LENGTH_INPUT,)) gan_model = define_gan(generator, discriminator) # Train the GAN model n_epochs = 60000 n_batch = 128 train(generator, discriminator, gan_model, latent_dim, n_epochs, n_batch) # 结果说明:虚假数据无法拟合真实样本中低于-1的部分
问题分析与解决建议
核心问题定位
- 生成器输出激活函数限制:生成器最后一层使用
tanh激活,其输出范围固定为[-1,1],而真实样本中存在低于-1的数值,这直接导致生成器无法输出该区间的数据。 - 数据分布匹配缺失:真实样本的对数输出分布跨度较大,但当前生成器的网络结构和训练目标没有针对性覆盖低数值区间的特征。
具体优化方案
- 替换生成器激活函数:将生成器最后一层的
tanh替换为无边界限制的线性激活(即不设置激活函数),确保生成器可以输出任意范围的数值,完全匹配真实样本的分布。修改示例:def define_generator(latent_dim): model = Sequential() model.add(Dense(128, input_dim=latent_dim)) model.add(LeakyReLU(alpha=0.2)) model.add(Dense(256)) model.add(LeakyReLU(alpha=0.2)) model.add(Dense(LENGTH_INPUT)) # 移除tanh激活,使用默认线性输出 return model - 数据归一化调整(备选):如果坚持使用有界激活函数,可先对真实样本做归一化处理(比如将所有数据映射到
[-1,1]区间),训练完成后再反归一化还原数值范围。但这种方式可能损失部分精度,不如直接使用无界激活直接高效。 - 增强判别器对低数值的敏感度:在判别器中添加针对低数值区间的特征提取分支,或者在训练时给低数值样本赋予更高权重,让判别器更关注该区间的差异,倒逼生成器学习该部分分布。
- 切换GAN变体:尝试使用WGAN(Wasserstein GAN)替代传统GAN,WGAN对样本分布的覆盖能力更强,尤其是在样本分布不均匀时,能更好地生成覆盖全区间的样本。
内容的提问来源于stack exchange,提问作者Jaisingh Pal
相关产品推荐
相关产品推荐

