一、定义
最近在研究DCGAN,全称为DEEP CONVOLUTIONAL
GENERATIVE ADVERSARIAL NETWORKS,是在GAN的基础上加入卷积层,使得模型在图像的生成上能够稳定而不是简单地对样本输入产生记忆。GAN采用的是全连接神经网络,训练时不稳定,容易崩溃,而这篇论文针对原始GAN进行了改进,并针对生成器的结构进行了设计,使得生成的图片更加稳定。
作者的工作体现在以下几个方面:
-
在DCGAN中提出了一系列的结构设置使得模型的训练更加稳定。
-
利用训练好的判别器进行图像分类任务,效果要好于其他的无监督算法。
-
将GAN学习到的感受野进行可视化,证明了特定的感受野能够生成特定的物体。
-
展示了生成器的向量运算性质,这体现在对于生成样例的简单的语义操作上。
图像生成模型可以分为两类,一类是无参数的模型,这类模型一般是在已有的图片数据库中进行匹配,主要是利用图块,这种模型可以用于纹理合成,超分辨率和图像修复;另一类是参数模型,这类模型还存在一些问题,比如图片模糊,物体不稳定等。
CNN架构设计 -
使用步长卷积代替池化操作,判别器使用步长卷积,生成器使用反卷积
-
去掉了模型深层的全连接层
-
在生成器和判别器中加入BN层
-
生成器使用ReLU激活,输出层采用Tanh;判决器全部采用Leaky ReLU激活
参数设置 -
将输入参数压缩至[-1,1]
-
采用小批量随机梯度下降,batch size=128
-
所有权重利用 μ = 0 , σ = 0.02 \mu=0,\sigma=0.02 μ=0,σ=0.02的正态分布初始化
-
Leaky ReLU的 α = 0.2 \alpha=0.2 α=0.2
-
使用Adam优化器,学习率为0.0002, β 1 = 0.5 \beta_1=0.5 β1=0.5
二、实现
代码采用keras实现,基本设置和论文一致,数据集为mnist。
生成器
生成器的输入是100维的向量,每一维的取值为
μ
=
0
,
σ
=
1
\mu=0,\sigma=1
μ=0,σ=1的正太分布,输出是28*28的手写数字图片
代码如下:
def build_generator(self):
model = Sequential()
model.add(Dense(128 * 7 * 7, activation="relu", input_dim=self.latent_dim))
model.add(Reshape((7, 7, 128)))
model.add(UpSampling2D())
model.add(Conv2D(128, kernel_size=3, padding="same"))
model.add(BatchNormalization(momentum=0.8))
model.add(Activation("relu"))
model.add(UpSampling2D())
model.add(Conv2D(64, kernel_size=3, padding="same"))
model.add(BatchNormalization(momentum=0.8))
model.add(Activation("relu"))
model.add(Conv2D(self.channels, kernel_size=3, padding="same"))
model.add(Activation("tanh"))
model.summary()
noise = Input(shape=(self.latent_dim,))
img = model(noise)
return Model(noise, img)
生成器采用了两次上采样,将输出由77变为2828,卷积层采用same padding,保证输出维度不会变。
判别器
判别器的输入是28*28的图片,输出是一维的判别结果,1表示真,0表示假。
def build_discriminator(self):
model = Sequential()
model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=self.img_shape, padding="same"))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.25))
model.add(Conv2D(64, kernel_size=3, strides=2, padding="same"))
model.add(ZeroPadding2D(padding=((0,1),(0,1))))
model.add(BatchNormalization(momentum=0.8))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.25))
model.add(Conv2D(128, kernel_size=3, strides=2, padding="same"))
model.add(BatchNormalization(momentum=0.8))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.25))
model.add(Conv2D(256, kernel_size=3, strides=1, padding="same"))
model.add(BatchNormalization(momentum=0.8))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
model.summary()
img = Input(shape=self.img_shape)
validity = model(img)
return Model(img, validity)
没有池化层,全部用步长卷积代替。
三、效果
训练了4000轮,最后的结果如下:
以下是mnist图片:
已经和原图片很接近了,虽然还有一些不太自然的地方,数字0和数字8的生成效果不太好。
以下是用GAN生成的图片:
与GAN相比,DCGAN生成的样本噪点更少,图片更加清晰,因为CNN网络更能提取图片的空间特征。