看一下FD-GAN的主模块
def conv_block(in_dim,out_dim):
return nn.Sequential(nn.Conv2d(in_dim,in_dim,kernel_size=3,stride=1,padding=1),
nn.ELU(True),
nn.Conv2d(in_dim,in_dim,kernel_size=3,stride=1,padding=1),
nn.ELU(True),
nn.Conv2d(in_dim,out_dim,kernel_size=1,stride=1,padding=0),
nn.AvgPool2d(kernel_size=2,stride=2))
首先 定义一个卷积块,卷积elu卷积elu卷积池化。其中池化将图像变为原来的1/2。
def deconv_block(in_dim,out_dim):
return nn.Sequential(nn.Conv2d(in_dim,out_dim,kernel_size=3,stride=1,padding=1),
nn.ELU(True),
nn.Conv2d(out_dim,out_dim,kernel_size=3,stride=1,padding=1),
nn.ELU(True),
nn.UpsamplingNearest2d(scale_factor=2))
定义反卷积块,卷积elu卷积elu,最近邻法将图像的高和宽变为原来的2倍。
def blockUNet1(in_c, out_c, name, transposed=False, bn=False, relu=True, dropout=False):
block = nn.Sequential()
if relu:
block.add_module('%s.relu' % name, nn.ReLU(inplace=True))
else:
block.add_module('%s.leakyrelu' % name, nn.LeakyReLU(0.2, inplace=True))
if not transposed:
block.add_module('%s.conv' % name, nn.Conv2d(in_c, out_c, 3, 1, 1, bias=False))
else:
block.add_module('%s.tconv' % name, nn.ConvTranspose2d(in_c, out_c, 3, 1, 1, bias=False))
if bn:
block.add_module('%s.bn' % name, nn.BatchNorm2d(out_c))
if dropout:
block.add_module('%s.dropout' % name, nn.Dropout2d(0.5, inplace=True))
return block
这部分拿出来运行会报错,KeyError: 'module name can\'t contain "."'
经过检查,将%s后面的 . 去掉。随便输入三个参数,3,5,layer1,结果为:Sequential( (layer1relu): ReLU(inplace=True) (layer1conv): Conv2d(3, 5, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) )
这部分就是通过if语句判断加入的模块。
def blockUNet(in_c, out_c, name, transposed=False, bn=False, relu=True, dropout=False):
block = nn.Sequential()
if relu:
block.add_module('%s.relu' % name, nn.ReLU(inplace=True))
else:
block.add_module('%s.leakyrelu' % name, nn.LeakyReLU(0.2, inplace=True))
if not transposed:
block.add_module('%s.conv' % name, nn.Conv2d(in_c, out_c, 4, 2, 1, bias=False))
else:
block.add_module('%s.tconv' % name, nn.ConvTranspose2d(in_c, out_c, 4, 2, 1, bias=False))
if bn:
block.add_module('%s.bn' % name, nn.BatchNorm2d(out_c))
if dropout:
block.add_module('%s.dropout' % name, nn.Dropout2d(0.5, inplace=True))
return block
这部分和上面的部分基本一致。
def conv3x3(in_planes, out_planes, stride=1):
"3x3 convolution with padding"
return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
padding=1, bias=False)
定义一个3*3卷积,padding为1。
class BasicBlock_res(nn.Module):
expansion = 1
def __init__(self, inplanes, planes, stride=1, downsample=None):
super(BasicBlock_res, self).__init__()
self.conv1 = conv3x3(inplanes, planes, stride)
self.bn1 = nn.BatchNorm2d(planes)
self.relu = nn.ReLU(inplace=True)
self.conv2 = conv3x3(planes, planes)
self.bn2 = nn.BatchNorm2d(planes)
self.downsample = downsample
self.stride = stride
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
if self.downsample is not None:
residual = self.downsample(x)
out += residual
out = self.relu(out)
return out
定义一个基本的残差连接。其中downsample决定了是否做一次下采样再进行连接。
class D1(nn.Module):
def __init__(self, nc, ndf, hidden_size):
super(D1, self).__init__()
# 256
self.conv1 = nn.Sequential(nn.Conv2d(nc,ndf,kernel_size=3,stride=1,padding=1),
nn.ELU(True))
# 256
self.conv2 = conv_block(ndf,ndf)
# 128
self.conv3 = conv_block(ndf, ndf*2)
# 64
self.conv4 = conv_block(ndf*2, ndf*3)
# 32
self.encode = nn.Conv2d(ndf*3, hidden_size, kernel_size=1,stride=1,padding=0)
self.decode = nn.Conv2d(hidden_size, ndf, kernel_size=1,stride=1,padding=0)
# 32
self.deconv4 = deconv_block(ndf, ndf)
# 64
self.deconv3 = deconv_block(ndf, ndf)
# 128
self.deconv2 = deconv_block(ndf, ndf)
# 256
self.deconv1 = nn.Sequential(nn.Conv2d(ndf,ndf,kernel_size=3,stride=1,padding=1),
nn.ELU(True),
nn.Conv2d(ndf,ndf,kernel_size=3,stride=1,padding=1),
nn.ELU(True),
nn.Conv2d(ndf, nc, kernel_size=3, stride=1, padding=1),
nn.Tanh())
"""
self.deconv1 = nn.Sequential(nn.Conv2d(ndf,nc,kernel_size=3,stride=1,padding=1),
nn.Tanh())
"""
def forward(self,x):
out1 = self.conv1(x)
out2 = self.conv2(out1)
out3 = self.conv3(out2)
out4 = self.conv4(out3)
out5 = self.encode(out4)
dout5= self.decode(out5)
dout4= self.deconv4(dout5)
dout3= self.deconv3(dout4)
dout2= self.deconv2(dout3)
dout1= self.deconv1(dout2)
return dout1
这里假设输入图像为256 * 256,先做conv1,卷积核大小为3 * 3,padding为1,自然图像大小不变。第二次卷积用了上面的卷积块,图像大小为原来的1/2,三次之后,图像大小为32。encode和decode没有改变图像大小,接着用三个上面定义的反卷积块,每块使图像变为原来的2倍,图像恢复256*256。最后的deconv1,对卷积elu做一个打包,最后用tanh收尾。这一部分对应论文中的编解码网络生成器部分,不过少了稠密连接和跳跃连接。后面会加上。
class NLayerDiscriminator(nn.Module):
def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d, use_sigmoid=True):
super(NLayerDiscriminator, self).__init__()
if type(norm_layer) == functools.partial:
use_bias = norm_layer.func == nn.InstanceNorm2d
else:
use_bias = norm_layer == nn.InstanceNorm2d
kw = 4
padw = 1
sequence = [
nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw),
nn.LeakyReLU(0.2, True)
]
nf_mult = 1
nf_mult_prev = 1
for n in range(1, n_layers):
nf_mult_prev = nf_mult
nf_mult = min(2 ** n, 8)
sequence += [
nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult,
kernel_size=kw, stride=2, padding=padw, bias=use_bias),
norm_layer(ndf * nf_mult),
nn.LeakyReLU(0.2, True)
]
nf_mult_prev = nf_mult
nf_mult = min(2 ** n_layers, 8)
sequence += [
nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult,
kernel_size=kw, stride=1, padding=padw, bias=use_bias),
norm_layer(ndf * nf_mult),
nn.LeakyReLU(0.2, True)
]
sequence += [nn.Conv2d(ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw)]
if use_sigmoid:
sequence += [nn.Sigmoid()]
self.model = nn.Sequential(*sequence)
def forward(self, input):
return self.model(input)
首先,在定义中只有一个参数input_nc是未知的,下面的if语句是不成立的,执行else,也就是use_bias的值为False。但是后面也可能赋值不同导致不同的结果。下面定义了一个列表,里面是一个卷积核为4*4,padding为1的卷积和lrelu函数。下面的for循环,这里的n_layers赋值为3,也就是n从1到2,这里如果n是1和2,那么min函数输出则为2和4。这里假设给定一个input_nc值32,那么调用这个类得到的既为:
NLayerDiscriminator(
(model): Sequential(
(0): Conv2d(32, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1))
(1): LeakyReLU(negative_slope=0.2, inplace=True)
(2): Conv2d(64, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(4): LeakyReLU(negative_slope=0.2, inplace=True)
(5): Conv2d(128, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(6): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(7): LeakyReLU(negative_slope=0.2, inplace=True)
(8): Conv2d(256, 512, kernel_size=(4, 4), stride=(1, 1), padding=(1, 1), bias=False)
(9): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(10): LeakyReLU(negative_slope=0.2, inplace=True)
(11): Conv2d(512, 1, kernel_size=(4, 4), stride=(1, 1), padding=(1, 1))
(12): Sigmoid()
)
)
可以看到,就是卷积归一激活函数相互穿插。就是说根据输入的参数不同而变化。
class D(nn.Module):
def __init__(self, nc, nf):
super(D, self).__init__()
main = nn.Sequential()
# 256
layer_idx = 1
name = 'layer%d' % layer_idx
main.add_module('%s.conv' % name, nn.Conv2d(nc, nf, 4, 2, 1, bias=False))
# 128
layer_idx += 1
name = 'layer%d' % layer_idx
main.add_module(name, blockUNet1(nf, nf*2, name, transposed=False, bn=True, relu=False, dropout=False))
# 64
layer_idx += 1
name = 'layer%d' % layer_idx
nf = nf * 2
main.add_module(name, blockUNet1(nf, nf*2, name, transposed=False, bn=True, relu=False, dropout=False))
# 32
layer_idx += 1
name = 'layer%d' % layer_idx
nf = nf * 2
main.add_module('%s.leakyrelu' % name, nn.LeakyReLU(0.2, inplace=True))
main.add_module('%s.conv' % name, nn.Conv2d(nf, nf*2, 4, 1, 1, bias=False))
#main.add_module('%s.bn' % name, nn.BatchNorm2d(nf*2))
# 31
layer_idx += 1
name = 'layer%d' % layer_idx
nf = nf * 2
main.add_module('%s.leakyrelu' % name, nn.LeakyReLU(0.2, inplace=True))
main.add_module('%s.conv' % name, nn.Conv2d(nf, 1, 4, 1, 1, bias=False))
main.add_module('%s.sigmoid' % name , nn.Sigmoid())
# 30 (sizePatchGAN=30)
self.main = main
def forward(self, x):
output = self.main(x)
return output
先定义main()这个序列,后面就是往main中放东西了。这里用到了前面的blockUNet1,给两个参数nc,nf赋值为3和4的话,结果是:
Sequential(
(layer1conv): Conv2d(3, 4, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(layer2): Sequential(
(layer2leakyrelu):