2021SC@SDUSC
源码:archs\gfpganv1_clean_arch.py
本篇主要分析gfpganv1_clean_arch.py下的以下两个类
class StyleGAN2GeneratorCSFT (StyleGAN2GeneratorClean):StyleGan
class ResBlock(nn.Module):残差网络
目录
class StyleGAN2GeneratorCSFT (StyleGAN2GeneratorClean):
(1) style codes -> latents with Style MLP layer
(4)get style latent with injection
class StyleGAN2GeneratorCSFT (StyleGAN2GeneratorClean):
继承了StyleGAN2GeneratorClean类
_init_( )
def __init__(self, out_size, num_style_feat=512, num_mlp=8, channel_multiplier=2, narrow=1, sft_half=False):
super(StyleGAN2GeneratorCSFT, self).__init__(
out_size,
num_style_feat=num_style_feat,
num_mlp=num_mlp,
channel_multiplier=channel_multiplier,
narrow=narrow)
self.sft_half = sft_half
forward( )
参数:
(self,
styles,#(list[Tensor]): Sample codes of styles.
conditions,
input_is_latent=False,#(bool): Whether input is latent style.
noise=None,#(Tensor | None): Input noise or None.
randomize_noise=True,#(bool): Randomize noise, used when 'noise' is False.
truncation=1,
truncation_latent=None,
inject_index=None,#The injection index for mixing noise.
return_latents=False)# Whether to return style latents.
(1) style codes -> latents with Style MLP layer
if not input_is_latent:
styles = [self.style_mlp(s) for s in styles]
(2)noise
if noise is None:
if randomize_noise:
noise = [None] * self.num_layers # for each style conv layer
else: # use the stored noise
noise = [getattr(self.noises, f'noise{i}') for i in range(self.num_layers)]
(3) style truncation
if truncation < 1:
style_truncation = []
for style in styles:
style_truncation.append(truncation_latent + truncation * (style -
truncation_latent))
styles = style_truncation
(4)get style latent with injection
if len(styles) == 1:
inject_index = self.num_latent
if styles[0].ndim < 3:
# repeat latent code for all the layers
latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
else: # used for encoder with different latent code for each layer
latent = styles[0]
elif len(styles) == 2: # mixing noises
if inject_index is None:
inject_index = random.randint(1, self.num_latent - 1)
latent1 = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
latent2 = styles[1].unsqueeze(1).repeat(1, self.num_latent - inject_index, 1)
latent = torch.cat([latent1, latent2], 1)
class ResBlock(nn.Module):
带有上/下采样的残差网络
Residual block with upsampling/downsampling
实际的一个单元(unit)即:con-relu-padding-con-relu
resNet本质上是为网络加了一个shortcut,相当于部分层数变成了一个直连接,从而防止出现升高神经网络层数反而效果变差的情况。所以需要让输入与输出的shape,channels都要保持一致。至于是否要退化部分网络,是由网络根据训练效果自身去选择的。
_init_( )
def __init__(self, in_channels, out_channels, mode='down'):
super(ResBlock, self).__init__()
#输入的通道数:in_channels
#输出的通道数:out_channels
#搭建卷积神经网络:卷积核[in_channels,3,3];步长为1;使用padding=1,边界增加一圈
#padding=1保持输出与输入大小保持一致
self.conv1 = nn.Conv2d(in_channels, in_channels, 3, 1, 1)
self.conv2 = nn.Conv2d(in_channels, out_channels, 3, 1, 1)
#卷积核[in_channels,1,1],bias=False不使用偏置(默认为True)
self.skip = nn.Conv2d(in_channels, out_channels, 1, bias=False)
#为上采样、下采样设置不同的scale_factor
if mode == 'down':
self.scale_factor = 0.5
elif mode == 'up':
self.scale_factor = 2
forward( )
前向传播函数
def forward(self, x):
#使用relu函数做非线性变换
out = F.leaky_relu_(self.conv1(x), negative_slope=0.2)
# upsample/downsample:做上/下采样
out = F.interpolate(out, scale_factor=self.scale_factor, mode='bilinear', align_corners=False)
#再次使用relu函数对采样后的输出做非线性变换
out = F.leaky_relu_(self.conv2(out), negative_slope=0.2)
# skip,对传入的x进行处理
x = F.interpolate(x, scale_factor=self.scale_factor, mode='bilinear', align_corners=False)
skip = self.skip(x)
out = out + skip
return out