DCGAN 的小尝试(2)
上一回我们只是简单地展示了基于 keras 框架、MNIST 数据集的 DCGAN 模型的结果,下面我们来详细地看一下这个代码的实现。
生成模型的结构
def generator_model():
model = Sequential()
model.add(Dense(input_dim=100, output_dim=1024))
model.add(Activation('tanh'))
model.add(Dense(out_dim=128*7*7))
model.add(BatchNormalization())
model.add(Activation('tanh'))
model.add(Reshape((128, 7, 7), input_shape=(128*7*7,)))
model.add(UpSampling2D(size=(2, 2)))
model.add(Convolution2D(out_channel=64, kernel_height=5, kernel_width=5, border_mode='same'))
model.add(Activation('tanh'))
model.add(UpSampling2D(size=(2, 2)))
model.add(Convolution2D(out_channel=1, kernel_height=5, kernel_width=5, border_mode='same'))
model.add(Activation('tanh'))
return model
直接上代码了。keras 的代码总体上比较直观,我在里面加了一些参数对应的描述,应该编译不过,但是会比较好理解。
这里需要说明的一点是,这个实现中的激活函数都是双曲正切,和论文中的描述不一样。当然,和论文中的模型架构也不一样,不过两者的数据集也不一样。
判别模型的结构
判别模型的结构如下所示,仔细地读一遍就可以理解,这里不需要赘述了。
def discriminator_model():
model = Sequential()
model.add(Convolution2D(
64, 5, 5,
border_mode='same',
input_shape=(1, 28, 28)))
model.add(Activation('tanh'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(128, 5, 5))
model.add(Activation('tanh'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(1024))
model.add(Activation('tanh'))
model.add(Dense(1))
model.add(Activation('sigmoid'))
return model
训练
这里的训练的一轮迭代可以用下面的流程表示:
- 利用 G 生成一批 generated_image
- 将真实的数据和 generated_image 合并,并放入 D 中进行一轮训练,其中真实数据的 label 为 1,generated_image 的 label 为 0。
- 利用 G 再生成一批 generated_image
- 这一次将 G 和 D 连起来,并给第 3 步的 gereated_image 的 label 设为 1,固定 D 的参数不变,进行一轮训练。
可以看出第 1,2 步是为了优化 D,第 3,4 步是为了优化 G,而两者之间还是存在着紧密的联系。
图像生成
图像生成的过程可以用如下两步表示:
- 利用 G 生成一大批 generated_image
- 利用 D 计算这些 generated_image 的分类结果,把得分高的一批选出来
最终我们看到的就是从 D 的眼皮下逃出的优质的生成数据。
好了,前面对代码的几个核心部分做了介绍,下面我们来看看实验过程中的一些问题。
图像的演变过程
在优化刚开始时,从随机生成的 100 维向量生成的图像是这样子的:
其实就是噪声。
经过 400 轮的迭代,生成模型可以生成下面的图像了:
可以看出数字的大体结构已经形成,但是能够表征数字细节的特征还没有出现。
经过 10 个 Epoch 后,生成模型的作品:
这时候有些数字已经成型,但是还有一些数字仍然存在欠缺。
然后是 20 轮 Epoch 的结果:
这个时候的数字已经具有很强的辨识度,但是与其同时,我们发现生成的数字中有大量的“1”。
当完成了所有的训练,我们拿出生成模型在最后一轮生成的图像,可以看到:
可以看出这里面的数字质量更高一些,但是里面的 1 也更多了。
从这个演化过程中,我们可以看出,从一开始的数字生成质量都很差但生成数字的多样性比较好,到后来的数字质量比较高但数字的多样性比较差,模型的特性在不断地发生变化。这也和两个模型的对抗有关系,而这个演变也和增强学习中的“探索-利用”困境有关系。
我们站在生成模型的角度去想,一开始生成模型会尽可能地生成各种各样形状的数字,而判别模型会识别出一些形状较差的模型,而放过一些形状较好的模型,随着学习的进程不断推进,判别模型的能力也在不断地加强,生成模型慢慢发现有一些固定的套路比较容易通过,而其他一些套路不那么容易通过,于是它就会尽可能地增大这些“套路”出现的概率,让自己的 loss 变小。这样,一个从探索为主的模型变成了一个以利用为主的模型,实际上它的数据分布已经不那么均匀了。
如果这个模型继续训练下去,生成模型有可能进一步地利用这个“套路”,这和我们传统意义上的过拟合也有很相近的地方。所以我们希望能够避免这样的过拟合。
这个小实验也到此结束了,下面我们将看看论文中关于 DCGAN 的介绍,以及关于模型的一些改进方案和其他框架的实现。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论