code: def build_perceptual_model(self, generator, discriminator=None):
      # Learning rate
      global_step = tf.Variable(
          0, dtype=tf.int32, trainable=False, name="global_step"
      )
      incremented_global_step = tf.assign_add(global_step, 1)
      self._reset_global_step = tf.assign(global_step, 0)
      self.learning_rate = tf.train.exponential_decay(
          self.lr,
          incremented_global_step,
          self.decay_steps,
          self.decay_rate,
          staircase=True,
      )
      self.sess.run([self._reset_global_step])
  
      if self.discriminator_loss is not None:
          self.discriminator = discriminator
  
      generated_image_tensor = generator.generated_image
      generated_image = tf.image.resize_nearest_neighbor(
          generated_image_tensor,
          (self.img_size, self.img_size),
          align_corners=True,
      )
      self.generated_img = generated_image
      self.ref_img = tf.get_variable(
          "ref_img",
          shape=generated_image.shape,
          dtype="float32",
          initializer=tf.initializers.zeros(),
      )
      self.ref_weight = tf.get_variable(
          "ref_weight",
          shape=generated_image.shape,
          dtype="float32",
          initializer=tf.initializers.zeros(),
      )
      self.add_placeholder("ref_img")
      self.add_placeholder("ref_weight")
  
      if self.vgg_loss is not None:
          vgg16 = VGG16(
              include_top=False,
              input_shape=(self.img_size, self.img_size, 3),
          )
          self.perceptual_model = Model(
              vgg16.input, vgg16.layers[self.layer].output
          )
          generated_img_features = self.perceptual_model(
              preprocess_input(self.ref_weight * generated_image)
          )
          dummy_im = np.zeros(
              [self.args.batch_size, self.img_size, self.img_size, 3],
              np.float32,
          )
          self.perceptual_model.predict_on_batch(dummy_im)
          self.ref_img_features = tf.get_variable(
              "ref_img_features",
              shape=generated_img_features.shape,
              dtype="float32",
              initializer=tf.initializers.zeros(),
          )
          self.features_weight = tf.get_variable(
              "features_weight",
              shape=generated_img_features.shape,
              dtype="float32",
              initializer=tf.initializers.zeros(),
          )
          self.sess.run(
              [
                  self.features_weight.initializer,
                  self.features_weight.initializer,
              ]
          )
          self.add_placeholder("ref_img_features")
          self.add_placeholder("features_weight")
  
      landmark_model = Landmark_Handler(
          self.args, self.sess, generated_image / 255
      )
      landmark_model.load_model()
      ibug84to68_ind = list(range(0, 33, 2)) + list(range(33, 84))
      self.generated_heatmaps = tf.gather(
          landmark_model.lms_heatmap_prediction, ibug84to68_ind, axis=3
      )
      self.generated_landmarks = tf.gather(
          landmark_model.pts_predictions, ibug84to68_ind, axis=1
      )
  
      self.ref_heatmaps = tf.get_variable(
          "ref_heatmaps",
          shape=self.generated_heatmaps.shape,
          dtype="float32",
          initializer=tf.initializers.zeros(),
      )
      self.add_placeholder("ref_heatmaps")
  
      self.generated_id, vars, _ = arcface_handler.get_input_features(
          generated_image / 255, self.generated_landmarks[:, :, ::-1]
      )
      self.init_id_vars = tf.variables_initializer(vars)
  
      self.org_features = tf.get_variable(
          "org_features",
          shape=self.generated_id.shape,
          dtype="float32",
          initializer=tf.initializers.zeros(),
      )
      self.add_placeholder("org_features")
      self.id_loss = tf.get_variable(
          "id_loss",
          shape=(),
          dtype="float32",
          initializer=tf.initializers.zeros(),
      )
      self.add_placeholder("id_loss")
  
      if self.perc_model is not None and self.lpips_loss is not None:
          img1 = tflib.convert_images_from_uint8(
              self.ref_weight * self.ref_img, nhwc_to_nchw=True
          )
          img2 = tflib.convert_images_from_uint8(
              self.ref_weight * generated_image, nhwc_to_nchw=True
          )
  
      self.loss = 0
      # L1 loss on VGG16 features
      if self.vgg_loss is not None:
          if self.adaptive_loss:
              self.loss += self.vgg_loss * tf_custom_adaptive_loss(
                  self.features_weight * self.ref_img_features,
                  self.features_weight * generated_img_features,
              )
          else:
              self.loss += self.vgg_loss * tf_custom_logcosh_loss(
                  self.features_weight * self.ref_img_features,
                  self.features_weight * generated_img_features,
              )
      # + logcosh loss on image pixels
      if self.pixel_loss is not None:
          if self.adaptive_loss:
              self.loss += (
                  self.pixel_loss
                  * tf_custom_adaptive_rgb_loss(
                      self.ref_weight * self.ref_img,
                      self.ref_weight * generated_image,
                  )
              )
          else:
              self.loss += self.pixel_loss * tf_custom_logcosh_loss(
                  self.ref_weight * self.ref_img,
                  self.ref_weight * generated_image,
              )
      # + MS-SIM loss on image pixels
      if self.mssim_loss is not None:
          self.loss += self.mssim_loss * tf.math.reduce_mean(
              1
              - tf.image.ssim_multiscale(
                  self.ref_weight * self.ref_img,
                  self.ref_weight * generated_image,
                  1,
              )
          )
      # + extra perceptual loss on image pixels
      if self.perc_model is not None and self.lpips_loss is not None:
          self.loss += self.lpips_loss * tf.math.reduce_mean(
              self.perc_model.get_output_for(img1, img2)
          )
      # + L1 penalty on dlatent weights
      if self.l1_penalty is not None:
          self.loss += (
              self.l1_penalty
              * 512
              * tf.math.reduce_mean(
                  tf.math.abs(
                      generator.dlatent_variable
                      - generator.get_dlatent_avg()
                  )
              )
          )
      # discriminator loss (realism)
      if self.discriminator_loss is not None:
          self.loss += self.discriminator_loss * tf.math.reduce_mean(
              self.discriminator.get_output_for(
                  tflib.convert_images_from_uint8(
                      generated_image_tensor, nhwc_to_nchw=True
                  ),
                  self.stub,
              )
          )
      # - discriminator_network.get_output_for(tflib.convert_images_from_uint8(ref_img, nhwc_to_nchw=True), stub)
      if self.landmark_loss is not None:
          self.loss += self.landmark_loss * tf.math.reduce_mean(
              tf.reduce_sum(
                  tf.pow(
                      self.ref_heatmaps - self.generated_heatmaps, 2
                  ),
                  2,
              )
          )
      if self.id_loss is not None:
          self.id_loss_comp = tf.losses.cosine_distance(
              self.generated_id, self.org_features, 1
          )
          self.loss += self.id_loss * self.id_loss_comp
  
      # Define Optimizer
      vars_to_optimize = generator.dlatent_variable
      vars_to_optimize = (
          vars_to_optimize
          if isinstance(vars_to_optimize, list)
          else [vars_to_optimize]
      )
      if self.args.optimizer == "lbfgs":
          self.optimizer = tf.contrib.opt.ScipyOptimizerInterface(
              self.loss,
              var_list=vars_to_optimize,
              method="L-BFGS-B",
              options={"maxiter": self.args.iterations},
          )
      else:
          if self.args.optimizer == "ggt":
              self.optimizer = tf.contrib.opt.GGTOptimizer(
                  learning_rate=self.learning_rate
              )
          else:
              self.optimizer = tf.train.AdamOptimizer(
                  learning_rate=self.learning_rate
              )
          self.min_op = self.optimizer.minimize(
              self.loss, var_list=[vars_to_optimize]
          )
          self.sess.run(
              tf.variables_initializer(self.optimizer.variables())
          )
      # min_op = optimizer.minimize(self.sess)
      # optim_results = tfp.optimizer.lbfgs_minimize(make_val_and_grad_fn(get_loss), initial_position=vars_to_optimize, num_correction_pairs=10, tolerance=1e-8)
      K.manual_variable_initialization(True)
      self.sess.graph.finalize()
  
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import tensorflow
  import bz2
  import PIL.Image
  from PIL import ImageFilter
  import numpy
  from keras.models import Model
  from keras.applications.vgg16 import VGG16, preprocess_input
  import keras.backend
  import traceback
  import external.stylegan2.dnnlib.tflib
  from core.landmark_handler import Landmark_Handler
  from core import arcface_handler
label_desc: Use image node_id 4 for calling the PerceptualModel obj's underlying member method code with example usage: obj.build_perceptual_model(generator, discriminator) without return types