culture commited on
Commit
39f1cda
·
1 Parent(s): 3df44eb

Upload gfpgan/archs/gfpganv1_clean_arch.py

Browse files
Files changed (1) hide show
  1. gfpgan/archs/gfpganv1_clean_arch.py +324 -0
gfpgan/archs/gfpganv1_clean_arch.py ADDED
@@ -0,0 +1,324 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import random
3
+ import torch
4
+ from basicsr.utils.registry import ARCH_REGISTRY
5
+ from torch import nn
6
+ from torch.nn import functional as F
7
+
8
+ from .stylegan2_clean_arch import StyleGAN2GeneratorClean
9
+
10
+
11
+ class StyleGAN2GeneratorCSFT(StyleGAN2GeneratorClean):
12
+ """StyleGAN2 Generator with SFT modulation (Spatial Feature Transform).
13
+
14
+ It is the clean version without custom compiled CUDA extensions used in StyleGAN2.
15
+
16
+ Args:
17
+ out_size (int): The spatial size of outputs.
18
+ num_style_feat (int): Channel number of style features. Default: 512.
19
+ num_mlp (int): Layer number of MLP style layers. Default: 8.
20
+ channel_multiplier (int): Channel multiplier for large networks of StyleGAN2. Default: 2.
21
+ narrow (float): The narrow ratio for channels. Default: 1.
22
+ sft_half (bool): Whether to apply SFT on half of the input channels. Default: False.
23
+ """
24
+
25
+ def __init__(self, out_size, num_style_feat=512, num_mlp=8, channel_multiplier=2, narrow=1, sft_half=False):
26
+ super(StyleGAN2GeneratorCSFT, self).__init__(
27
+ out_size,
28
+ num_style_feat=num_style_feat,
29
+ num_mlp=num_mlp,
30
+ channel_multiplier=channel_multiplier,
31
+ narrow=narrow)
32
+ self.sft_half = sft_half
33
+
34
+ def forward(self,
35
+ styles,
36
+ conditions,
37
+ input_is_latent=False,
38
+ noise=None,
39
+ randomize_noise=True,
40
+ truncation=1,
41
+ truncation_latent=None,
42
+ inject_index=None,
43
+ return_latents=False):
44
+ """Forward function for StyleGAN2GeneratorCSFT.
45
+
46
+ Args:
47
+ styles (list[Tensor]): Sample codes of styles.
48
+ conditions (list[Tensor]): SFT conditions to generators.
49
+ input_is_latent (bool): Whether input is latent style. Default: False.
50
+ noise (Tensor | None): Input noise or None. Default: None.
51
+ randomize_noise (bool): Randomize noise, used when 'noise' is False. Default: True.
52
+ truncation (float): The truncation ratio. Default: 1.
53
+ truncation_latent (Tensor | None): The truncation latent tensor. Default: None.
54
+ inject_index (int | None): The injection index for mixing noise. Default: None.
55
+ return_latents (bool): Whether to return style latents. Default: False.
56
+ """
57
+ # style codes -> latents with Style MLP layer
58
+ if not input_is_latent:
59
+ styles = [self.style_mlp(s) for s in styles]
60
+ # noises
61
+ if noise is None:
62
+ if randomize_noise:
63
+ noise = [None] * self.num_layers # for each style conv layer
64
+ else: # use the stored noise
65
+ noise = [getattr(self.noises, f'noise{i}') for i in range(self.num_layers)]
66
+ # style truncation
67
+ if truncation < 1:
68
+ style_truncation = []
69
+ for style in styles:
70
+ style_truncation.append(truncation_latent + truncation * (style - truncation_latent))
71
+ styles = style_truncation
72
+ # get style latents with injection
73
+ if len(styles) == 1:
74
+ inject_index = self.num_latent
75
+
76
+ if styles[0].ndim < 3:
77
+ # repeat latent code for all the layers
78
+ latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
79
+ else: # used for encoder with different latent code for each layer
80
+ latent = styles[0]
81
+ elif len(styles) == 2: # mixing noises
82
+ if inject_index is None:
83
+ inject_index = random.randint(1, self.num_latent - 1)
84
+ latent1 = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
85
+ latent2 = styles[1].unsqueeze(1).repeat(1, self.num_latent - inject_index, 1)
86
+ latent = torch.cat([latent1, latent2], 1)
87
+
88
+ # main generation
89
+ out = self.constant_input(latent.shape[0])
90
+ out = self.style_conv1(out, latent[:, 0], noise=noise[0])
91
+ skip = self.to_rgb1(out, latent[:, 1])
92
+
93
+ i = 1
94
+ for conv1, conv2, noise1, noise2, to_rgb in zip(self.style_convs[::2], self.style_convs[1::2], noise[1::2],
95
+ noise[2::2], self.to_rgbs):
96
+ out = conv1(out, latent[:, i], noise=noise1)
97
+
98
+ # the conditions may have fewer levels
99
+ if i < len(conditions):
100
+ # SFT part to combine the conditions
101
+ if self.sft_half: # only apply SFT to half of the channels
102
+ out_same, out_sft = torch.split(out, int(out.size(1) // 2), dim=1)
103
+ out_sft = out_sft * conditions[i - 1] + conditions[i]
104
+ out = torch.cat([out_same, out_sft], dim=1)
105
+ else: # apply SFT to all the channels
106
+ out = out * conditions[i - 1] + conditions[i]
107
+
108
+ out = conv2(out, latent[:, i + 1], noise=noise2)
109
+ skip = to_rgb(out, latent[:, i + 2], skip) # feature back to the rgb space
110
+ i += 2
111
+
112
+ image = skip
113
+
114
+ if return_latents:
115
+ return image, latent
116
+ else:
117
+ return image, None
118
+
119
+
120
+ class ResBlock(nn.Module):
121
+ """Residual block with bilinear upsampling/downsampling.
122
+
123
+ Args:
124
+ in_channels (int): Channel number of the input.
125
+ out_channels (int): Channel number of the output.
126
+ mode (str): Upsampling/downsampling mode. Options: down | up. Default: down.
127
+ """
128
+
129
+ def __init__(self, in_channels, out_channels, mode='down'):
130
+ super(ResBlock, self).__init__()
131
+
132
+ self.conv1 = nn.Conv2d(in_channels, in_channels, 3, 1, 1)
133
+ self.conv2 = nn.Conv2d(in_channels, out_channels, 3, 1, 1)
134
+ self.skip = nn.Conv2d(in_channels, out_channels, 1, bias=False)
135
+ if mode == 'down':
136
+ self.scale_factor = 0.5
137
+ elif mode == 'up':
138
+ self.scale_factor = 2
139
+
140
+ def forward(self, x):
141
+ out = F.leaky_relu_(self.conv1(x), negative_slope=0.2)
142
+ # upsample/downsample
143
+ out = F.interpolate(out, scale_factor=self.scale_factor, mode='bilinear', align_corners=False)
144
+ out = F.leaky_relu_(self.conv2(out), negative_slope=0.2)
145
+ # skip
146
+ x = F.interpolate(x, scale_factor=self.scale_factor, mode='bilinear', align_corners=False)
147
+ skip = self.skip(x)
148
+ out = out + skip
149
+ return out
150
+
151
+
152
+ @ARCH_REGISTRY.register()
153
+ class GFPGANv1Clean(nn.Module):
154
+ """The GFPGAN architecture: Unet + StyleGAN2 decoder with SFT.
155
+
156
+ It is the clean version without custom compiled CUDA extensions used in StyleGAN2.
157
+
158
+ Ref: GFP-GAN: Towards Real-World Blind Face Restoration with Generative Facial Prior.
159
+
160
+ Args:
161
+ out_size (int): The spatial size of outputs.
162
+ num_style_feat (int): Channel number of style features. Default: 512.
163
+ channel_multiplier (int): Channel multiplier for large networks of StyleGAN2. Default: 2.
164
+ decoder_load_path (str): The path to the pre-trained decoder model (usually, the StyleGAN2). Default: None.
165
+ fix_decoder (bool): Whether to fix the decoder. Default: True.
166
+
167
+ num_mlp (int): Layer number of MLP style layers. Default: 8.
168
+ input_is_latent (bool): Whether input is latent style. Default: False.
169
+ different_w (bool): Whether to use different latent w for different layers. Default: False.
170
+ narrow (float): The narrow ratio for channels. Default: 1.
171
+ sft_half (bool): Whether to apply SFT on half of the input channels. Default: False.
172
+ """
173
+
174
+ def __init__(
175
+ self,
176
+ out_size,
177
+ num_style_feat=512,
178
+ channel_multiplier=1,
179
+ decoder_load_path=None,
180
+ fix_decoder=True,
181
+ # for stylegan decoder
182
+ num_mlp=8,
183
+ input_is_latent=False,
184
+ different_w=False,
185
+ narrow=1,
186
+ sft_half=False):
187
+
188
+ super(GFPGANv1Clean, self).__init__()
189
+ self.input_is_latent = input_is_latent
190
+ self.different_w = different_w
191
+ self.num_style_feat = num_style_feat
192
+
193
+ unet_narrow = narrow * 0.5 # by default, use a half of input channels
194
+ channels = {
195
+ '4': int(512 * unet_narrow),
196
+ '8': int(512 * unet_narrow),
197
+ '16': int(512 * unet_narrow),
198
+ '32': int(512 * unet_narrow),
199
+ '64': int(256 * channel_multiplier * unet_narrow),
200
+ '128': int(128 * channel_multiplier * unet_narrow),
201
+ '256': int(64 * channel_multiplier * unet_narrow),
202
+ '512': int(32 * channel_multiplier * unet_narrow),
203
+ '1024': int(16 * channel_multiplier * unet_narrow)
204
+ }
205
+
206
+ self.log_size = int(math.log(out_size, 2))
207
+ first_out_size = 2**(int(math.log(out_size, 2)))
208
+
209
+ self.conv_body_first = nn.Conv2d(3, channels[f'{first_out_size}'], 1)
210
+
211
+ # downsample
212
+ in_channels = channels[f'{first_out_size}']
213
+ self.conv_body_down = nn.ModuleList()
214
+ for i in range(self.log_size, 2, -1):
215
+ out_channels = channels[f'{2**(i - 1)}']
216
+ self.conv_body_down.append(ResBlock(in_channels, out_channels, mode='down'))
217
+ in_channels = out_channels
218
+
219
+ self.final_conv = nn.Conv2d(in_channels, channels['4'], 3, 1, 1)
220
+
221
+ # upsample
222
+ in_channels = channels['4']
223
+ self.conv_body_up = nn.ModuleList()
224
+ for i in range(3, self.log_size + 1):
225
+ out_channels = channels[f'{2**i}']
226
+ self.conv_body_up.append(ResBlock(in_channels, out_channels, mode='up'))
227
+ in_channels = out_channels
228
+
229
+ # to RGB
230
+ self.toRGB = nn.ModuleList()
231
+ for i in range(3, self.log_size + 1):
232
+ self.toRGB.append(nn.Conv2d(channels[f'{2**i}'], 3, 1))
233
+
234
+ if different_w:
235
+ linear_out_channel = (int(math.log(out_size, 2)) * 2 - 2) * num_style_feat
236
+ else:
237
+ linear_out_channel = num_style_feat
238
+
239
+ self.final_linear = nn.Linear(channels['4'] * 4 * 4, linear_out_channel)
240
+
241
+ # the decoder: stylegan2 generator with SFT modulations
242
+ self.stylegan_decoder = StyleGAN2GeneratorCSFT(
243
+ out_size=out_size,
244
+ num_style_feat=num_style_feat,
245
+ num_mlp=num_mlp,
246
+ channel_multiplier=channel_multiplier,
247
+ narrow=narrow,
248
+ sft_half=sft_half)
249
+
250
+ # load pre-trained stylegan2 model if necessary
251
+ if decoder_load_path:
252
+ self.stylegan_decoder.load_state_dict(
253
+ torch.load(decoder_load_path, map_location=lambda storage, loc: storage)['params_ema'])
254
+ # fix decoder without updating params
255
+ if fix_decoder:
256
+ for _, param in self.stylegan_decoder.named_parameters():
257
+ param.requires_grad = False
258
+
259
+ # for SFT modulations (scale and shift)
260
+ self.condition_scale = nn.ModuleList()
261
+ self.condition_shift = nn.ModuleList()
262
+ for i in range(3, self.log_size + 1):
263
+ out_channels = channels[f'{2**i}']
264
+ if sft_half:
265
+ sft_out_channels = out_channels
266
+ else:
267
+ sft_out_channels = out_channels * 2
268
+ self.condition_scale.append(
269
+ nn.Sequential(
270
+ nn.Conv2d(out_channels, out_channels, 3, 1, 1), nn.LeakyReLU(0.2, True),
271
+ nn.Conv2d(out_channels, sft_out_channels, 3, 1, 1)))
272
+ self.condition_shift.append(
273
+ nn.Sequential(
274
+ nn.Conv2d(out_channels, out_channels, 3, 1, 1), nn.LeakyReLU(0.2, True),
275
+ nn.Conv2d(out_channels, sft_out_channels, 3, 1, 1)))
276
+
277
+ def forward(self, x, return_latents=False, return_rgb=True, randomize_noise=True):
278
+ """Forward function for GFPGANv1Clean.
279
+
280
+ Args:
281
+ x (Tensor): Input images.
282
+ return_latents (bool): Whether to return style latents. Default: False.
283
+ return_rgb (bool): Whether return intermediate rgb images. Default: True.
284
+ randomize_noise (bool): Randomize noise, used when 'noise' is False. Default: True.
285
+ """
286
+ conditions = []
287
+ unet_skips = []
288
+ out_rgbs = []
289
+
290
+ # encoder
291
+ feat = F.leaky_relu_(self.conv_body_first(x), negative_slope=0.2)
292
+ for i in range(self.log_size - 2):
293
+ feat = self.conv_body_down[i](feat)
294
+ unet_skips.insert(0, feat)
295
+ feat = F.leaky_relu_(self.final_conv(feat), negative_slope=0.2)
296
+
297
+ # style code
298
+ style_code = self.final_linear(feat.view(feat.size(0), -1))
299
+ if self.different_w:
300
+ style_code = style_code.view(style_code.size(0), -1, self.num_style_feat)
301
+
302
+ # decode
303
+ for i in range(self.log_size - 2):
304
+ # add unet skip
305
+ feat = feat + unet_skips[i]
306
+ # ResUpLayer
307
+ feat = self.conv_body_up[i](feat)
308
+ # generate scale and shift for SFT layers
309
+ scale = self.condition_scale[i](feat)
310
+ conditions.append(scale.clone())
311
+ shift = self.condition_shift[i](feat)
312
+ conditions.append(shift.clone())
313
+ # generate rgb images
314
+ if return_rgb:
315
+ out_rgbs.append(self.toRGB[i](feat))
316
+
317
+ # decoder
318
+ image, _ = self.stylegan_decoder([style_code],
319
+ conditions,
320
+ return_latents=return_latents,
321
+ input_is_latent=self.input_is_latent,
322
+ randomize_noise=randomize_noise)
323
+
324
+ return image, out_rgbs