diff --git a/core/leras/models/PatchDiscriminator.py b/core/leras/models/PatchDiscriminator.py index da297b6..edc1fe4 100644 --- a/core/leras/models/PatchDiscriminator.py +++ b/core/leras/models/PatchDiscriminator.py @@ -131,11 +131,26 @@ class UNetPatchDiscriminator(nn.ModelBase): return s[q][2] def on_build(self, patch_size, in_ch, base_ch = 16): + + class ResidualBlock(nn.ModelBase): + def on_build(self, ch, kernel_size=3 ): + self.conv1 = nn.Conv2D( ch, ch, kernel_size=kernel_size, padding='SAME') + self.conv2 = nn.Conv2D( ch, ch, kernel_size=kernel_size, padding='SAME') + + def forward(self, inp): + x = self.conv1(inp) + x = tf.nn.leaky_relu(x, 0.2) + x = self.conv2(x) + x = tf.nn.leaky_relu(inp + x, 0.2) + return x + prev_ch = in_ch self.convs = [] - self.res = [] + self.res1 = [] + self.res2 = [] self.upconvs = [] - self.upres = [] + self.upres1 = [] + self.upres2 = [] layers = self.find_archi(patch_size) level_chs = { i-1:v for i,v in enumerate([ min( base_ch * (2**i), 512 ) for i in range(len(layers)+1)]) } @@ -144,26 +159,38 @@ class UNetPatchDiscriminator(nn.ModelBase): for i, (kernel_size, strides) in enumerate(layers): self.convs.append ( nn.Conv2D( level_chs[i-1], level_chs[i], kernel_size=kernel_size, strides=strides, padding='SAME') ) + + self.res1.append ( ResidualBlock(level_chs[i]) ) + self.res2.append ( ResidualBlock(level_chs[i]) ) + self.upconvs.insert (0, nn.Conv2DTranspose( level_chs[i]*(2 if i != len(layers)-1 else 1), level_chs[i-1], kernel_size=kernel_size, strides=strides, padding='SAME') ) + + self.upres1.insert (0, ResidualBlock(level_chs[i-1]*2) ) + self.upres2.insert (0, ResidualBlock(level_chs[i-1]*2) ) self.out_conv = nn.Conv2D( level_chs[-1]*2, 1, kernel_size=1, padding='VALID') self.center_out = nn.Conv2D( level_chs[len(layers)-1], 1, kernel_size=1, padding='VALID') self.center_conv = nn.Conv2D( level_chs[len(layers)-1], level_chs[len(layers)-1], kernel_size=1, padding='VALID') + def forward(self, x): x = tf.nn.leaky_relu( self.in_conv(x), 0.2 ) encs = [] - for conv in self.convs:#, self.res): + for conv, res1,res2 in zip(self.convs, self.res1, self.res2): encs.insert(0, x) x = tf.nn.leaky_relu( conv(x), 0.2 ) - + x = res1(x) + x = res2(x) + center_out, x = self.center_out(x), tf.nn.leaky_relu( self.center_conv(x), 0.2 ) - for i, (upconv, enc,) in enumerate(zip(self.upconvs, encs)):# self.upres + for i, (upconv, enc, upres1, upres2 ) in enumerate(zip(self.upconvs, encs, self.upres1, self.upres2)): x = tf.nn.leaky_relu( upconv(x), 0.2 ) x = tf.concat( [enc, x], axis=nn.conv2d_ch_axis) + x = upres1(x) + x = upres2(x) return center_out, self.out_conv(x) diff --git a/models/Model_SAEHD/Model.py b/models/Model_SAEHD/Model.py index 6e30934..eb46658 100644 --- a/models/Model_SAEHD/Model.py +++ b/models/Model_SAEHD/Model.py @@ -138,7 +138,7 @@ Examples: df, liae, df-d, df-ud, liae-ud, ... default_gan_power = self.options['gan_power'] = self.load_or_def_option('gan_power', 0.0) default_gan_patch_size = self.options['gan_patch_size'] = self.load_or_def_option('gan_patch_size', self.options['resolution'] // 8) - default_gan_dims = self.options['gan_dims'] = self.load_or_def_option('gan_dims', 32) + default_gan_dims = self.options['gan_dims'] = self.load_or_def_option('gan_dims', 16) if self.is_first_run() or ask_override: self.options['models_opt_on_gpu'] = io.input_bool ("Place models and optimizer on GPU", default_models_opt_on_gpu, help_message="When you train on one GPU, by default model and optimizer weights are placed on GPU to accelerate the process. You can place they on CPU to free up extra VRAM, thus set bigger dimensions.") @@ -149,13 +149,13 @@ Examples: df, liae, df-d, df-ud, liae-ud, ... self.options['random_warp'] = io.input_bool ("Enable random warp of samples", default_random_warp, help_message="Random warp is required to generalize facial expressions of both faces. When the face is trained enough, you can disable it to get extra sharpness and reduce subpixel shake for less amount of iterations.") - self.options['gan_power'] = np.clip ( io.input_number ("GAN power", default_gan_power, add_info="0.0 .. 1.0", help_message="Train the network in Generative Adversarial manner. Forces the neural network to learn small details of the face. Enable it only when the face is trained enough with lr_dropout(on) and random_warp(off), and don't disable. Typical fine value is 0.1"), 0.0, 1.0 ) + self.options['gan_power'] = np.clip ( io.input_number ("GAN power", default_gan_power, add_info="0.0 .. 1.0", help_message="Forces the neural network to learn small details of the face. Enable it only when the face is trained enough with lr_dropout(on) and random_warp(off), and don't disable. The higher the value, the higher the chances of artifacts. Typical fine value is 0.1"), 0.0, 1.0 ) if self.options['gan_power'] != 0.0: gan_patch_size = np.clip ( io.input_int("GAN patch size", default_gan_patch_size, add_info="3-640", help_message="The higher patch size, the higher the quality, the more VRAM is required. Typical fine value is resolution / 8." ), 3, 640 ) self.options['gan_patch_size'] = gan_patch_size - gan_dims = np.clip ( io.input_int("GAN dimensions", default_gan_dims, add_info="16-512", help_message="Change this value only if you want to experiment. Typical fine value is 32." ), 16, 512 ) + gan_dims = np.clip ( io.input_int("GAN dimensions", default_gan_dims, add_info="16-512", help_message="The dimensions of the GAN network. Change this value only if you want to experiment. Typical fine value is 16." ), 16, 512 ) self.options['gan_dims'] = gan_dims if 'df' in self.options['archi']: @@ -496,7 +496,7 @@ Examples: df, liae, df-d, df-ud, liae-ud, ... if masked_training: - # Minimal src-src-bg rec with total_variation_mse with clip to suppress random bright dots from gan + # Minimal src-src-bg rec with total_variation_mse to suppress random bright dots from gan gpu_G_loss += 0.000001*nn.total_variation_mse(gpu_pred_src_src) gpu_G_loss += 0.02*tf.reduce_mean(tf.square(gpu_pred_src_src_anti_masked-gpu_target_src_anti_masked),axis=[1,2,3] )