在尝试训练用于图像生成的GAN时,我遇到了一个无法解释的问题。
在训练生成器时,train_on_batch
返回的损失值在仅仅2到3次迭代后就直接降为零。经过调查,我发现train_on_batch
方法的一些奇怪行为:
当我检查以下内容时:
noise = np.random.uniform(-1.0, 1.0, size=[batch_size, gen_noise_length])predictions = GAN.stackedModel.predict(noise)
返回的值几乎都接近于零,这正如我所预期的,因为生成器尚未被训练。
然而:
y = np.ones([batch_size, 1])noise = np.random.uniform(-1.0, 1.0, size=[batch_size, gen_noise_length])loss = GAN.stackedModel.train_on_batch(noise, y)
这里的损失值几乎为零,尽管我的预期目标是显而易见的。当我运行:
y = np.ones([batch_size, 1])noise = np.random.uniform(-1.0, 1.0, size=[batch_size, gen_noise_length])loss = GAN.stackedModel.test_on_batch(noise, y)
返回的损失值很高,正如我所预期的。
train_on_batch
方法到底发生了什么?我真的毫无头绪…
编辑
我的损失函数是二元交叉熵,我的模型构建方式如下:
def createStackedModel(self): # 构建堆叠的GAN模型 gan_in = Input([self.noise_length]) H = self.genModel(gan_in) gan_V = self.disModel(H) GAN = Model(gan_in, gan_V) opt = RMSprop(lr=0.0001, decay=3e-8) GAN.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy']) return GAN
编辑2
生成器是由一些包含BatchNormalization的块堆叠而成的:
self.G.add(UpSampling2D()) self.G.add(Conv2DTranspose(int(depth/8), 5, padding='same')) self.G.add(BatchNormalization(momentum=0.5)) self.G.add(Activation('relu'))
编辑3
我已经将我的代码上传到https://gitlab.com/benjamingraf24/DCGAN/显然问题出在我构建GAN网络的方式上。所以在GANBuilder.py中一定有什么问题。然而,我找不到它…
回答:
BatchNormalization
层在训练和测试阶段的行为不同。
在训练阶段,它们将使用当前批次的激活值的均值和方差进行归一化。
然而,在测试阶段,它们使用的是在训练过程中收集的移动均值和移动方差。在没有足够的前期训练的情况下,这些收集的值可能与实际批次统计数据相差甚远,从而导致显著的损失值差异。
请参考Keras的BatchNormalization文档。momentum
参数用于定义移动均值和移动平均值在训练过程中适应新批次收集值的速度。