原始GAN的思想非常伟大,但是我们在实际运用中很少会直接使用最基础的版本,比如在视觉问题中,如果使用原始的基于DNN的GAN,则会出现许多问题。
如果输入GAN的随机噪声为100维的随机噪声,输出图像为256 * 256大小的话,也就是说,要将100维的信息映射为65536维。如果单纯用DNN来实现,那么整个模型参数会非常巨大,而且学习难度很大(低维度映射到高维度需要添加许多信息)。
因此,原始GAN的一个扩展网络:深度卷积生成对抗网络(DCGAN,Deep Convolutional Generative Adversarial Networks)就登上了舞台。DCGAN也是在生成对抗网络基础上建立的第一个被广泛使用的图像生成网络。
DCGAN在训练过程中状态比较稳定,并可以有效实现高质量的图片生成及相关的生成模型应用。由于其具有非常强的实用性,在它之后的大量GAN模型都是基于DCGAN进行的改良版本。
DCGAN的网络结构图如下图所示:
结合上图的模型结构,我们可以知道DCGAN将传统的GAN的生成器和判别器均采用CNN实现。并且为了更好地适应于卷积神经网络架构,使用了以下的架构设计规则(tricks):
下面我们详细说明这几点:
第一点:
下面两幅图分别是是第一个设计规则的带步长的卷积和转置卷积:
上面的图表示了卷积层如何在判别器中进行空间下采样(spatial downsampling),输入数据为5 * 5的矩阵,使用了3 * 3的过滤器,步长为2 * 2,最终输出矩阵为3 * 3。
上图表示的是卷积层在生成器中进行上采样(spatial upsampling),输入为3 * 3矩阵,同样使用了3 * 3过滤器,反向步长为2 * 2,故在每个输入矩阵的点之间填充一个0,最终输出为5 * 5的矩阵。
使用上述两种卷积层替代池化层的目的是为了能够让网络自身去学习空间上采样与下采样,使得判别器和生成器都能够有效具备相应的能力。
第二点:
由于深度学习的神经网络层数很多,每一层都会使得输出数据的分布发生变化,随着层数的增加网络的整体偏差会越来越大。批归一化的目标则是为了解决这一问题,通过对每一层的输入进行归一化处理,能够有效使得数据服从某个固定的数据分布。
第三点:
目前的研究趋势中我们会发现非常多的研究都是试图去除全连接层,常规的卷积神经网络往往会在卷积层后添加全连接层用以输出最终向量,但我们知道全连接层的缺点是参数过多,当神经网络层数深了以后运算速度会变得非常慢,此外全连接层也会使得网络容易过度拟合。有研究使用了全局平均池化(global average pooling)来替代全连接层,可以使得模型更稳定,但也影响了收敛速度。论文中说的一种折中方案是将生成器的随机输入直接与卷积层特征输入进行连接,同样地对于判别器的输出层也是与卷积层的输出特征连接。
第四、五点:
激活函数的作用是为了在神经网络中进行非线性变换。
(1)首先,我们从最常用的Sigmoid函数说起。Sigmoid函数的公式为 f ( x ) = 1 1 + e − x f(x) = \frac{1}{1 + e^{-x}} f(x)=1+e−x1 。如下图所示,该函数的取值范围在1到1之间,当x大于零时输出结果会趋近于1,而当x小于零时,输出结果趋向于0,由于函数的特性,经常被用作二分类的输出端。
但是Sigmoid函数有两个比较大的缺陷:
(2)Tanh函数那数据压缩到-1到1的范围,解决了Sigmoid函数均值不为0的问题,所以在实践中通常Tanh函数都优于Sigmoid函数。在数学形式上其实Tanh只是对Sigmoid的一个缩放形式,公式为tanh(x) = 2f(2x) -1,下图为Tanh函数的图示:
(3)ReLU(Rectified Linear Unit)函数是最近几年非常流行的激活函数,它的计算公式非常简单f(x) = max(0,x)。
它有几个明显的优点:
但ReLU也存在问题,那就是在训练中可能会导致出现某些神经元永远无法更新的情况。
其中一种对ReLU函数的改进方式是LeakyReLU,该方法与ReLU不同的是在x小于0的时候取f(x) = ax,其中a是一个非常小的斜率(比如0.01)。这样的改进可以使得当x小于0的时候也不会导致反向传播时的梯度消失现象。
生成器中使用ReLU函数,但对于输出层使用了Tanh激活函数,因为研究者们在实验中观察到使用有边界的激活函数可以让模型更快地进行学习,并能快速覆盖色彩空间。而在判别器中对所有层均使用LeakyReLU,在实际使用中尤其适用于高分辨率的图像判别模型。
DCGAN的作者也使用饿了三种数据集对网络进行测试,分别为LSUN室内数据集,人脸数据集,Imagenet-1K数据集。下面的图展示了实验的结果:
论文作者除了对DCGAN做了基础的模型评估分析,还做了很多有意思的实验。
(1)研究者们发现的图像的隐含空间(latent space) ,随着输入Z的不断变化,输出的图像会平滑地转变成为另一幅图像。如下图所示:
(2)研究者对DCGAN网络内部层进行了可视化。我们知道传统的有监督的CNN网络通常在中间层能够学习到某些事物的特征,而对于无监督的DCGAN在基于大量图片数据的训练后同样能够学习到很多有趣的特征。如下图所示,GAN中判别器在训练后卷积层学习到的特征的可视化,已经可以隐约看到卧室中床和窗户的样子。
(3)为了研究这些特征在生成器中的作用,研究者们故意把生成器中对应“窗户”的filter去掉,得到的结果非常有意思,在原本应该生成窗户的地方,最终生成的图像中都使用了其他物品进行了替换。如下图所示,第一行是未经修改生成的图片,第二行是移除了“窗户”filter层生成的图片。
更多的实验表明,如果我们移除其他特征的filter,同样可以达到对应的效果。
我们发现在GAN的生成器中其实已经有了输入向量和输出向量的对应关系,我们可以把这个向量作为图像的向量表示进行图像的算术运算,如下图所示:
我们还可以用上面的方法进行图像演变的制作,当我们把某个图像的向量线性转换成另一个图像的向量的时候,对应的图像也会逐渐转移。如下图所示:
如上图所示,每行包含五张图片,第一列是数据库原始图片;第二列是随机去除80%像素点的图片;第三列是使用补全方法对第二列修复的结果;第四列是原始数据中被扣掉一大块的图片;第五列是使用补全方法对第四列修复的结果。
要使用生成对抗网络补全图像需要满足两个条件:第一个条件是使用DCGAN在大量头像数据训练后能够生成“骗过”判别器的照片;第二个条件是生成图像与原图像未丢失部分的差值要尽量最小。
这里提出了两个损失函数:
第一个损失函数是与丢失信息图片相关的上下文损失(contextual loss),它的定义是生成图片与原始图片在未丢失区域的差距大小。
式子中M相当于一个遮罩,也就是说在这个函数中我们只考虑未丢失图片的区域。
L c o n t e x t u a l ( z ) = ∣ ∣ M ⊙ G ( z ) − M ⊙ Y ∣ ∣ L_{contextual}(z) = ||M\odot G(z) - M\odot Y || Lcontextual(z)=∣∣M⊙G(z)−M⊙Y∣∣
第二个损失函数是DCGAN本身的感知损失(Perceptual loss),这个是对于DCGAN本身在大量人脸数据集上训练的损失函数,与之前GAN中生成器的损失函数一致。
L p e r c e p t u a l ( z ) = log ( 1 − D ( G ( z ) ) L_{perceptual}(z) = \log (1 - D(G(z)) Lperceptual(z)=log(1−D(G(z))
最终完整的损失函数与计算结果如下所示:
L ( z ) = L c o n t e x t u a l ( z ) + L p e r c e p t u a l ( z ) L(z) = L_{contextual}(z) + L_{perceptual}(z) L(z)=Lcontextual(z)+Lperceptual(z)
z ^ = arg min λ L ( z ) \hat{z} = \mathop{\arg\min}\limits_{\lambda} L(z) z^=λargminL(z)
其中 λ \lambda λ是超参数,用来调节两个损失函数的重要程度, z ^ \hat{z} z^是我们要求的生成器输入,图片补全公式如下:
x r e c o n s t r u c t e d = M ⊙ Y + ( 1 − M ) ⊙ G ( z ^ ) x_{reconstructed} = M\odot Y + (1 - M) \odot G(\hat{z}) xreconstructed=M⊙Y+(1−M)⊙G(z^)