一个简单的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通道的矩阵,结构如图:
二、网络搭建
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))
三、训练模型
训练过程需要同时对两个网络进行训练:
- 先在真实数据上训练判别器:最大化
;
- 再在假数据上训练判别器:最大化
;
- 最后使用假数据训练生成器:最小化:
;
贴一张100个epoch时的模型效果:
四、数据集
所用数据集来自: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~