//  [python]
def add_gan_loss(generated_prediction, real_prediction, generated_image, real_image, discriminator_network_fn,
                   name_postfix='', discriminator_var_scope=DISCRIMINATOR_SCOPE, only_real_fake_loss=False,
                   overall_weight=1.0):
    """This function takes the combined end_points and adds gan losses to the corresponding loss collections."""
    assert (generated_prediction is not None and
            real_prediction is not None and
            generated_image is not None and
            real_image is not None)
    # Generator fool discriminator loss.
    generator_loss_name = 'generator_fool_loss%s' % (name_postfix)
    generated_prediction = tf.cast(generated_prediction, tf.float32)
    real_prediction = tf.cast(real_prediction, tf.float32)

    if FLAGS.loss_architecture in ['wgan_gp', 'wgan', 'hinge']:
      # Note the losses below are not returned because it's added to the loss collection already.
      generator_fool_loss = tf.negative(tf.reduce_mean(generated_prediction), name=generator_loss_name)
      generator_fool_loss = tf.losses.compute_weighted_loss(generator_fool_loss,
                                                            weights=FLAGS.gan_weight * overall_weight,
                                                            scope=generator_loss_name,
                                                            loss_collection=GENERATOR_LOSS_COLLECTION)
    else:
      assert FLAGS.loss_architecture == 'gan' or FLAGS.loss_architecture == 'dragan'
      # Equivalent to maximizing log D(G(z)).
      generator_fool_loss = tf.losses.sigmoid_cross_entropy(tf.ones_like(generated_prediction), generated_prediction,
                                                            weights=FLAGS.gan_weight * overall_weight,
                                                            scope=generator_loss_name,
                                                            loss_collection=GENERATOR_LOSS_COLLECTION)

    discriminator_loss_name = 'discriminator_loss%s' % (name_postfix)

    if FLAGS.loss_architecture == 'wgan_gp' or FLAGS.loss_architecture == 'wgan':
      # Discriminator loss from WGAN
      discriminator_loss = tf.subtract(tf.reduce_mean(generated_prediction), tf.reduce_mean(real_prediction),
                                       name=discriminator_loss_name)
      discriminator_loss = tf.losses.compute_weighted_loss(discriminator_loss,
                                                           weights=FLAGS.gan_weight * overall_weight,
                                                           scope=discriminator_loss_name,
                                                           loss_collection=DISCRIMINATOR_LOSS_COLLECTION)
      if only_real_fake_loss:
        return

      # Adds additional penalty term to keep the scores from drifting too far from zero.
      if FLAGS.wgan_drift_loss_weight:
        discriminator_drift_loss_name = 'discriminator_drift_loss%s' % (name_postfix)
        discriminator_drift_loss = (tf.constant(FLAGS.wgan_drift_loss_weight, dtype=real_prediction.dtype)
                                    * tf.reduce_mean(tf.square(real_prediction, name='discriminator_drift_loss')))
        discriminator_drift_loss = tf.losses.compute_weighted_loss(discriminator_drift_loss,
                                                                   weights=1.0 * overall_weight,
                                                                   scope=discriminator_drift_loss_name,
                                                                   loss_collection=DISCRIMINATOR_LOSS_COLLECTION)

      ########################
      # WGAN GP loss         #
      ########################
      if FLAGS.loss_architecture == 'wgan_gp':
        scope_name = 'discriminator_gradient_penalty%s' % (name_postfix)
        gradient_penalty = GanModel._add_wgan_gp_loss(real_image,
                                                      generated_image,
                                                      discriminator_network_fn,
                                                      loss_scope=scope_name,
                                                      discriminator_var_scope=discriminator_var_scope,
                                                      overall_weight=overall_weight)

    elif FLAGS.loss_architecture == 'hinge':
      # Discriminator loss from WGAN
      discriminator_loss = tf.add(tf.reduce_mean(tf.nn.relu(1+generated_prediction)),
                                  tf.reduce_mean(tf.nn.relu(1-real_prediction)),
                                  name=discriminator_loss_name)
      discriminator_loss = tf.losses.compute_weighted_loss(discriminator_loss,
                                                           weights=FLAGS.gan_weight * overall_weight,
                                                           scope=discriminator_loss_name,
                                                           loss_collection=DISCRIMINATOR_LOSS_COLLECTION)
    elif FLAGS.loss_architecture == 'gan' or FLAGS.loss_architecture == 'dragan':
      # Equivalent to minimizing -(log D(x) + log (1 - D(G(z))))
      discriminator_fake_loss = tf.losses.sigmoid_cross_entropy(tf.zeros_like(generated_prediction),
                                                                generated_prediction,
                                                                weights=FLAGS.gan_weight * overall_weight,
                                                                scope='discriminator_fake_loss%s' % (name_postfix),
                                                                loss_collection=DISCRIMINATOR_LOSS_COLLECTION)
      discriminator_real_loss = tf.losses.sigmoid_cross_entropy(tf.ones_like(real_prediction),
                                                                real_prediction,
                                                                weights=FLAGS.gan_weight * overall_weight,
                                                                scope='discriminator_real_loss%s' % (name_postfix),
                                                                loss_collection=DISCRIMINATOR_LOSS_COLLECTION)
      if only_real_fake_loss:
        return
      if FLAGS.loss_architecture == 'dragan':
        scope_name = 'discriminator_gradient_penalty%s' % (name_postfix)
        gradient_penalty = GanModel._add_dragan_loss(real_image,
                                                     discriminator_network_fn,
                                                     loss_scope=scope_name,
                                                     var_scope=discriminator_var_scope,
                                                     overall_weight=overall_weight)
    else:
      raise NotImplementedError('unsupported loss architecture: %s' %FLAGS.loss_architecture)