Alex_McAvoy

想要成为渔夫的猎手

经典生成对抗网络之 DCGAN

【概述】

深度卷积生成对抗网络(Deep Convolution Generative Adversarial Networks,DCGAN)是 Alec Radfor 等人于 2015 年提出的一种深度生成模型

该模型在原始 GAN 的理论基础上,开创性地将 CNN 和 GAN 进行结合,以实现对图像的处理,并提出了一系列对网络结构的限制以提高网络的稳定性

DCGAN 的网络结构在之后的针对 GAN 的各种改进中得到了广泛的沿用,可以说是当今各类改进 GAN 的前身

【贡献】

DCGAN 将生成器 G 和判别器 D 设置为两个 CNN,同时对 CNN 的结构进行了一些改进,以提高样本的质量和收敛速度,主要改进有:

  1. 取消池化层:使用全卷积网络,生成器 G 中使用转置卷积替代池化层进行上采样,在判别器 D 中加入步幅卷积替代池化层,让网络自己学习下采样方式
  2. 取消全连接层:作者通过实验发现全局平均池化有助于模型的稳定性,但是降低了模型的收敛速度,因此取消了全连接层,使网络变为全卷积网络
  3. 批量归一化:作者实验中发现对所有的层都使用 BN 会造成采样的震荡和网络不稳定,因此只对生成器的输出层和判别器 D 的输入层使用 BN
  4. 激活函数:在生成器 G 中,除了最后的输出层使用 tanh,其他层全使用 ReLU 作为激活函数;在判别器 D 中,除了最后的输出层使用 sigmoid,所有层均采用 Leaky ReLU 作为激活函数

【网络结构】

通过上述改进,DCAGN 得到的生成器 G 的网络结构如下图所示

虽然 DCGAN 论文中没有给出判别器 D 的结构图,但是仍然可以从文中推理出判别器应该同样是 5 层的全卷积网络,输入层使用了 BN,除了最后的输出层使用 sigmoid,所有层均采用 Leaky ReLU 作为激活函数

【实现】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from torch import nn

# 生成器
class Generator(nn.Module):
def __init__(self, z_dim, ):

super().__init__()
self.z_dim = z_dim
net = []

channels_in = [self.z_dim, 512, 256, 128, 64]
channels_out = [512, 256, 128, 64, 3]
active = ["R", "R", "R", "R", "tanh"]
stride = [1, 2, 2, 2, 2]
padding = [0, 1, 1, 1, 1]
for i in range(len(channels_in)):
net.append(nn.ConvTranspose2d(in_channels=channels_in[i], out_channels=channels_out[i],
kernel_size=4, stride=stride[i], padding=padding[i], bias=False))
if active[i] == "R":
net.append(nn.BatchNorm2d(num_features=channels_out[i]))
net.append(nn.ReLU())
elif active[i] == "tanh":
net.append(nn.Tanh())

self.generator = nn.Sequential(*net)
self.weight_init()

# 权重初始化
def weight_init(self):
for m in self.generator.modules():
if isinstance(m, nn.ConvTranspose2d):
nn.init.normal_(m.weight.data, 0, 0.02)

elif isinstance(m, nn.BatchNorm2d):
nn.init.normal_(m.weight.data, 0, 0.02)
nn.init.constant_(m.bias.data, 0)

def forward(self, x):
out = self.generator(x)
return out

# 判别器
class Discriminator(nn.Module):
def __init__(self):
super().__init__()

net = []
channels_in = [3, 64, 128, 256, 512]
channels_out = [64, 128, 256, 512, 1]
padding = [1, 1, 1, 1, 0]
active = ["LR", "LR", "LR", "LR", "sigmoid"]
for i in range(len(channels_in)):
net.append(nn.Conv2d(in_channels=channels_in[i], out_channels=channels_out[i],
kernel_size=4, stride=2, padding=padding[i], bias=False))
if i == 0:
net.append(nn.LeakyReLU(0.2))
elif active[i] == "LR":
net.append(nn.BatchNorm2d(num_features=channels_out[i]))
net.append(nn.LeakyReLU(0.2))
elif active[i] == "sigmoid":
net.append(nn.Sigmoid())

self.discriminator = nn.Sequential(*net)
self.weight_init()

# 权重初始化
def weight_init(self):
for m in self.discriminator.modules():
if isinstance(m, nn.ConvTranspose2d):
nn.init.normal_(m.weight.data, 0, 0.02)

elif isinstance(m, nn.BatchNorm2d):
nn.init.normal_(m.weight.data, 0, 0.02)
nn.init.constant_(m.bias.data, 0)

def forward(self, x):
out = self.discriminator(x)
out = out.view(x.size(0), -1)
return out
感谢您对我的支持,让我继续努力分享有用的技术与知识点!