DCGAN入门:以人脸生成为例

一个简单的DCGAN实现,使用的是Pytorch,完整代码已经放到GitHub,欢迎试玩:https://github.com/qq995431104/DCGAN-Pytorch.git。

一、DCGAN简介

DCGAN是CNN在无监督学习领域的一个典型应用,是Radford在2016年发表的论文—— Unsupervised Representation Learning With Deep Convolutional Generative Adversarial Networks提出的网络结构,首次将CNN应用到GAN中。

2014年Goodfellow发表的GANs,首次提出了生成对抗网络的结构,通过两个网络(一个判别器D、一个生成器G)对抗学习。判别器是一个二分类网络,它用来分辨输入的数据是真是假(real or fake);生成器用来从一组噪声中重构出假数据(fake data),并从训练数据中学到其特征;通过联合训练判别器和生成器,生成器产生的假数据越来越像真的,从而在判别器那里蒙混过关;最终,判别器无法分辨出真假数据,生成器生成的假数据能够以假乱真,则两个模型达到了一个平衡,即可结束训练。

DCGAN,在GAN的基础上,引入了CNN结构,从而扩展了CNN的无监督应用。其主要贡献有:

  • 提出了一组可以稳定训练的卷积GANs,命名为深度卷积GANs(DCGANs);
  • 使用训练好的判别器进行图像分类任务,与其他无监督算法相比,显示出了有竞争力的性能;
  • 可视化GANs中的滤波器,实验表明特定滤波器可以绘制特征的对象;
  • 得到的生成器,具有一些有趣的向量属性,能够对生成的例子进行一些简单操作;

判别器D,是一个全卷积神经网络,并去掉Pooling层,只用卷积层进行下采样,网络结构与传统分类网络类似;

生成器G的网络设计比较有意思,输入是一组噪声,经过reshape、转置卷积上采样,最后输出为3通道的矩阵,结构如图:

DCGAN入门:以人脸生成为例_第1张图片

 二、网络搭建

1. 判别器

class Discriminator(nn.Module):
    def __init__(self, ndf, nc):
        super(Discriminator, self).__init__()
        self.net = nn.Sequential(
            # input shape: [bs, nc, 64, 64]
            nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            # state shape: [bs, ndf, 32, 32]

            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 2),
            nn.LeakyReLU(0.2, inplace=True),
            # state shape: [bs, ndf*2, 16, 16]

            nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 4),
            nn.LeakyReLU(0.2, inplace=True),
            # state shape: [bs, ndf*4, 8, 8]

            nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 8),
            nn.LeakyReLU(0.2, inplace=True),
            # state shape: [bs, ndf*8, 4, 4]

            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()
            # state shape: [bs, 1, 1, 1]
        )

    def forward(self, x):
        return self.net(x)

其中,ndf代表输入的featuremap尺寸,nc为输入的通道。

2. 生成器

class Generator(nn.Module):
    """
    input: [bs, 100, 1, 1]
    output: [bs, nc, 64, 64]
    """
    def __init__(self, nz, ngf, nc):
        super(Generator, self).__init__()
        self.net = nn.Sequential(
            nn.ConvTranspose2d(nz, ngf * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(ngf * 8),
            nn.ReLU(True),
            # state shape: [bs, ngf*8, 4, 4]

            nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 4),
            nn.ReLU(True),
            # state shape: [bs, ngf*4, 8, 8]

            nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 2),
            nn.ReLU(True),
            # state shape: [bs, ngf*2, 16, 16]

            nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf),
            nn.ReLU(True),
            # state shape: [bs, ngf, 32, 32]

            nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),
            nn.Tanh()
            # state shape: [bs, nc, 64, 64]
        )

    def forward(self, x):
        return self.net(x)

其中,nz为输入噪声的长度,ngf为输出的featuremap尺寸,nc为输出featuremap通道数。

3. 损失函数和优化器

这里损失函数使用的是BCELoss;优化器为Adam,但是需要分别定义,分别优化判别器和生成器:

    # criterion
    criterion = nn.BCELoss()

    # set optimizer
    optimizerD = optim.Adam(D.parameters(), lr=args.lr, betas=(0.5, 0.999))
    optimizerG = optim.Adam(G.parameters(), lr=args.lr, betas=(0.5, 0.999))

三、训练模型

训练过程需要同时对两个网络进行训练:

  • 先在真实数据上训练判别器:最大化\log D(x)
  • 再在假数据上训练判别器:最大化\log (1-D(G(z)))
  • 最后使用假数据训练生成器:最小化:\log (1-D(G(z)))

贴一张100个epoch时的模型效果:

DCGAN入门:以人脸生成为例_第2张图片

四、数据集

所用数据集来自:http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html,如果不方便下载,可以使用百度网盘链接:

链接:https://pan.baidu.com/s/1dOG4_o--oK-4vFIguBzp4w 
提取码:ztv3 
 

完整代码,见GitHub:https://github.com/qq995431104/DCGAN-Pytorch.git,欢迎star~

你可能感兴趣的:(DeepLearning,DCGAN,人脸生成,生成对抗网络,生成器,判别器)