GFPGAN源码分析—第六篇
2021/12/7 1:16:59
本文主要是介绍GFPGAN源码分析—第六篇,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
2021SC@SDUSC
源码:archs\gfpganv1_clean_arch.py
本篇主要分析gfpganv1_clean_arch.py下的
class GFPGANv1Clean(nn.Module)类_init_()方法
目录
class GFPGANv1Clean(nn.Module)
init()
(1)channels的设置
(2)调用torch.nn.Conv2d()创建了一层卷积神经网络
(3)下采样(downsample)
(4)上采样(upsample)
(5)全连接层
(6)创建self.stylegan_decoder
(7)如果decoder_load_path不为空则读取
(8)for SFT(SFT layer)
class GFPGANv1Clean(nn.Module)
继承自nn.Module类,使得我们可以使用很多现成的类,比如本类中使用的Conv2d以及RelU激活函数等等。
init()
参数:
self, out_size, num_style_feat=512, channel_multiplier=1, decoder_load_path=None, fix_decoder=True, # for stylegan decoder num_mlp=8, input_is_latent=False, different_w=False, narrow=1, sft_half=False
在class GFPGANer()-init()中被调用时:
self.gfpgan = GFPGANv1Clean( out_size=512, num_style_feat=512, channel_multiplier=channel_multiplier, decoder_load_path=None, fix_decoder=False, num_mlp=8, input_is_latent=True, different_w=True, narrow=1, sft_half=True)
(1)channels的设置
实际调用的时候narrow=1,
channels保存了经过convolution层后的输出的通道数
unet_narrow = narrow * 0.5 channels = { '4': int(512 * unet_narrow), '8': int(512 * unet_narrow), '16': int(512 * unet_narrow), '32': int(512 * unet_narrow), '64': int(256 * channel_multiplier * unet_narrow), '128': int(128 * channel_multiplier * unet_narrow), '256': int(64 * channel_multiplier * unet_narrow), '512': int(32 * channel_multiplier * unet_narrow), '1024': int(16 * channel_multiplier * unet_narrow) }
(2)调用torch.nn.Conv2d()搭建卷积神经网络
#out_size=512,so log_size=9 self.log_size = int(math.log(out_size, 2)) #first_out_size = 512 first_out_size = 2 ** (int(math.log(out_size, 2))) #channels['512']=32*2*0.5=32 self.conv_body_first = nn.Conv2d(3, channels[f'{first_out_size}'], 1)
在这里介绍一下nn.Conv2d()的几个参数
in_channels: int,#输入的通道数目【必选】 out_channels: int,# 输出的通道数目【必选】 kernel_size: _size_2_t,#卷积核的大小,类型为int(方形边长) 或者元组(长和宽)【必选】 stride: _size_2_t = 1,#步长 padding: Union[str, _size_2_t] = 0,#边界增益,可以控制输出结果的尺寸 dilation: _size_2_t = 1,#控制卷积核之间的间距 groups: int = 1, bias: bool = True, padding_mode: str = 'zeros', # TODO: refine this type device=None, dtype=None
那么可以得知
self.conv_body_first = nn.Conv2d(3, channels[f'{first_out_size}'], 1)
#实际上是传入通道为3(RGB)的输入,使用边长为1的卷积核,最后获得通道为32的输出
#由于卷积核边长为1,我们输入与输入的图片大小仍然保持一致,但增加了通道数
(3)下采样(downsample)
可以看到实际上是调用ResBlock做了下采样
# 输入图片的通道数(实际为32) in_channels = channels[f'{first_out_size}'] #创建ModuleList容器 self.conv_body_down = nn.ModuleList() # i从self.log_size(9)->3 :7次循环 for i in range(self.log_size, 2, -1): out_channels = channels[f'{2 ** (i - 1)}'] #调用ResBlock残差网络做下采样,并将该module添加到设置的ModuleList self.conv_body_down.append(ResBlock(in_channels, out_channels, mode='down')) #这一层的输出管道数作为下一层输入的管道数 in_channels = out_channels
介绍一下nn.ModuleList()
nn.ModuleList,它是一个储存不同module,并自动将每个 module 的 parameters 添加到网络之中的容器。你可以把任意 nn.Module 的子类 (比如 nn.Conv2d, nn.Linear 之类的) 加到这个 list 里面,方法和 Python 自带的 list 一样,无非是 extend,append 等操作。但不同于一般的 list,加入到 nn.ModuleList 里面的 module 是会自动注册到整个网络上的,同时 module 的 parameters 也会自动添加到整个网络中。
#注意nn.ModuleList则没有实现内部forward函数,所以需要手动实现
最后一层卷积层的搭建:
#最终输出通道数为channels['4']=256,使用边长为3的卷积核,步长为1,padding为1,保证维度不变 self.final_conv = nn.Conv2d(in_channels, channels['4'], 3, 1, 1)
(4)上采样(upsample)
#输入通道数为channels['4']=256,即下采样的输出的通道数 in_channels = channels['4'] #创建ModuleList容器 self.conv_body_up = nn.ModuleList() # i从3->self.log_size(9) :7次循环 for i in range(3, self.log_size + 1): # 定义输出的通道数 out_channels = channels[f'{2 ** i}'] # 调用带有上采样ResBlock残差网络,并将该module添加到设置的ModuleList self.conv_body_up.append(ResBlock(in_channels, out_channels, mode='up')) #这一层的输出管道数作为下一层输入的管道数 in_channels = out_channels
(5)全连接层
根据传入的参数different_w,选择每个输出样本的大小,并搭建相应的全连接层。
if different_w: #16*512=8192 linear_out_channel = (int(math.log(out_size, 2)) * 2 - 2) * num_style_feat print(linear_out_channel) else: #512 linear_out_channel = num_style_feat #全连接层size of each input sample:4096,size of each output sample:8192 self.final_linear = nn.Linear(channels['4'] * 4 * 4, linear_out_channel)
(6)创建self.stylegan_decoder
self.stylegan_decoder = StyleGAN2GeneratorCSFT( out_size=out_size, num_style_feat=num_style_feat, num_mlp=num_mlp, channel_multiplier=channel_multiplier, narrow=narrow, sft_half=sft_half)
(7)如果decoder_load_path不为空则读取
if decoder_load_path: self.stylegan_decoder.load_state_dict( torch.load(decoder_load_path, map_location=lambda storage, loc: storage)['params_ema']) if fix_decoder: for name, param in self.stylegan_decoder.named_parameters(): param.requires_grad = False
(8)for SFT(SFT layer)
#ModuleList self.condition_scale = nn.ModuleList() self.condition_shift = nn.ModuleList() # i从3->self.log_size(9) :7次循环 for i in range(3, self.log_size + 1): # 定义输出的通道数 out_channels = channels[f'{2 ** i}'] #输出通道数是否减半 if sft_half: sft_out_channels = out_channels else: sft_out_channels = out_channels * 2 #使用nn.Sequential搭建网络,并添加到ModuleList self.condition_scale.append( nn.Sequential( #卷积核边长为3,步长为1,输出与输出保持相同维度 nn.Conv2d(out_channels, out_channels, 3, 1, 1), nn.LeakyReLU(0.2, True), nn.Conv2d(out_channels, sft_out_channels, 3, 1, 1))) self.condition_shift.append( nn.Sequential( nn.Conv2d(out_channels, out_channels, 3, 1, 1), nn.LeakyReLU(0.2, True), nn.Conv2d(out_channels, sft_out_channels, 3, 1, 1)))
nn.Sequential是一个有序的容器,其中传入的是构造器类(各种用来处理input的类),最终input会被Sequential中的构造器依次执行。
这篇关于GFPGAN源码分析—第六篇的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南