13.4 DCGAN

深度卷积GAN(Deep Convolutional GAN,DCGAN) [1] 是GAN的一种实现,它使用了深度卷积神经网络作为图像识别和生成的工具。下面我们将介绍如何基于DCGAN实现生成MNIST数据集的功能,相关代码在GitHub的code/keras-dcgan.py。

1.Generator

我们创建Generator,架构如图13-14所示,参数如下:

·输入层大小为100。

·两个全连接层,结点数分别为1024和128×7×7即6272,激活函数均为tanh。

·批量正则化(BatchNormalization)。

·改变形状为(7,7,128)。

·使用(2,2)进行上采样。

·使用64个大小为(5,5)进行卷积处理。

·使用(2,2)进行上采样。

·使用1个(5,5)进行卷积处理,生成一个(28,28,1)的图像数据。

代码如下:


def generator_model():
    model = Sequential()
    model.add(Dense(input_dim=100, units=1024))
    model.add(Activation('tanh'))
    model.add(Dense(128*7*7))
    model.add(BatchNormalization())
    model.add(Activation('tanh'))
    model.add(Reshape((7, 7, 128), input_shape=(128*7*7,)))
    model.add(UpSampling2D(size=(2, 2)))
    model.add(Conv2D(64, (5, 5), padding='same'))
    model.add(Activation('tanh'))
    model.add(UpSampling2D(size=(2, 2)))
    model.add(Conv2D(1, (5, 5), padding='same'))
    model.add(Activation('tanh'))
    return model

2.Discriminator

我们创建Discriminator,架构如图13-15所示,参数如下:

·输入层大小为(28,28,1)。

·64个大小为(5,5)的卷积处理。

·使用大小为(2,2)的池化处理,取最大值。

图13-14 DCGAN的Generator

图13-15 DCGAN的Discriminator

·使用128个大小为(5,5)的卷积处理。

·使用大小为(2,2)的池化处理,取最大值。

·压平为一维向量。

·结点数分别为1024和1的全连接。

·使用激活函数sigmoid输出一维的分类概率。

代码如下:


def discriminator_model():
    model = Sequential()
    model.add(Conv2D(64, (5, 5),padding='same',input_shape=(28, 28, 1)))
    model.add(Activation('tanh'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Conv2D(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

3.对抗模型

DCGAN的对抗模型实现非常简单,把Generator和Discriminator连接即可,不过需要将Discriminator参数设置为只允许手工更新,只有当设置trainable为True时才能根据训练结果自动更新参数,完整的对抗模型结构如图13-16所示。

代码如下:


def generator_containing_discriminator(g, d):
    model = Sequential()
    model.add(g)
    d.trainable = False
    model.add(d)
    return model

图13-16 DCGAN的对抗模型

4.训练过程

DCGAN的训练过程分为两步:第一步,生成一个大小为(BATCH_SIZE,100)的在-1~1平均分布的噪声,使用Generator生成图像样本,然后和同样大小的真实MNIST图像样本合并,分别标记为0和1,对Discriminator进行训练。这个过程中Discriminator的trainable状态为True,训练过程会更新其参数(见图13-17),代码如下:


noise = np.random.uniform(-1, 1, size=(BATCH_SIZE, 100))
image_batch = X_train[index*BATCH_SIZE:(index+1)*BATCH_SIZE]
generated_images = g.predict(noise, verbose=0)
X = np.concatenate((image_batch, generated_images))
y = [1] * BATCH_SIZE + [0] * BATCH_SIZE
d_loss = d.train_on_batch(X, y)
print("batch %d d_loss : %f" % (index, d_loss))

图13-17 DCGAN的训练过程(一)

第二步,生成一个大小为(BATCH_SIZE,100)的在-1~1平均分布的噪声,使用Generator生成图像样本,标记为1,欺骗Discriminator,这个过程针对对抗模型进行训练(图13-18)。这个过程中Discriminator的trainable状态为False,训练过程不会更新其参数。训练完成后将重新把Discriminator的trainable状态设为True(见图13-18),代码如下:


noise = np.random.uniform(-1, 1, (BATCH_SIZE, 100))
d.trainable = False
g_loss = d_on_g.train_on_batch(noise, [1] * BATCH_SIZE)
d.trainable = True
print("batch %d g_loss : %f" % (index, g_loss))

图13-18 DCGAN的训练过程(二)

5.训练结果

整个训练过程非常漫长,在我的Mac本上运行了1天也只完成40轮训练,生成结果如图13-19所示。

图13-19 DCGAN运行结果(一)

Rowel Atienza在其文章 [2] 中记录了使用类似的实现训练了若干轮以后的结果,如图13-20所示,可以发现训练时间越长,生成的图片越逼真。

图13-20 DCGAN运行结果(二)

[1] https://arxiv.org/pdf/1511.06434.pdf

[2] https://towardsdatascience.com/gan-by-example-using-keras-on-tensorflow-backend-1a6d515a60d0