summaryrefslogtreecommitdiff
path: root/Code/loss_functions.py
diff options
context:
space:
mode:
authorMatt Cooper <matthew_cooper@brown.edu>2016-08-12 16:48:46 -0400
committerMatt Cooper <matthew_cooper@brown.edu>2016-08-12 16:48:46 -0400
commit0a3fd5b62065333669c7b391c626cb2505217617 (patch)
tree04be2e559272d62e22c08258d0c72d759a00265d /Code/loss_functions.py
First commit
Diffstat (limited to 'Code/loss_functions.py')
-rw-r--r--Code/loss_functions.py118
1 files changed, 118 insertions, 0 deletions
diff --git a/Code/loss_functions.py b/Code/loss_functions.py
new file mode 100644
index 0000000..994d226
--- /dev/null
+++ b/Code/loss_functions.py
@@ -0,0 +1,118 @@
+import tensorflow as tf
+import numpy as np
+
+from tfutils import log10
+import constants as c
+
+def combined_loss(gen_frames, gt_frames, d_preds, lam_adv=1, lam_lp=1, lam_gdl=1, l_num=2, alpha=2):
+ """
+ Calculates the sum of the combined adversarial, lp and GDL losses in the given proportion. Used
+ for training the generative model.
+
+ @param gen_frames: A list of tensors of the generated frames at each scale.
+ @param gt_frames: A list of tensors of the ground truth frames at each scale.
+ @param d_preds: A list of tensors of the classifications made by the discriminator model at each
+ scale.
+ @param lam_adv: The percentage of the adversarial loss to use in the combined loss.
+ @param lam_lp: The percentage of the lp loss to use in the combined loss.
+ @param lam_gdl: The percentage of the GDL loss to use in the combined loss.
+ @param l_num: 1 or 2 for l1 and l2 loss, respectively).
+ @param alpha: The power to which each gradient term is raised in GDL loss.
+
+ @return: The combined adversarial, lp and GDL losses.
+ """
+ batch_size = tf.shape(gen_frames[0])[0] # variable batch size as a tensor
+
+ loss = lam_lp * lp_loss(gen_frames, gt_frames, l_num)
+ loss += lam_gdl * gdl_loss(gen_frames, gt_frames, alpha)
+ if c.ADVERSARIAL: loss += lam_adv * adv_loss(d_preds, tf.ones([batch_size, 1]))
+
+ return loss
+
+
+def bce_loss(preds, targets):
+ """
+ Calculates the sum of binary cross-entropy losses between predictions and ground truths.
+
+ @param preds: A 1xN tensor. The predicted classifications of each frame.
+ @param targets: A 1xN tensor The target labels for each frame. (Either 1 or -1). Not "truths"
+ because the generator passes in lies to determine how well it confuses the
+ discriminator.
+
+ @return: The sum of binary cross-entropy losses.
+ """
+ return tf.squeeze(-1 * (tf.matmul(targets, log10(preds), transpose_a=True) +
+ tf.matmul(1 - targets, log10(1 - preds), transpose_a=True)))
+
+
+def lp_loss(gen_frames, gt_frames, l_num):
+ """
+ Calculates the sum of lp losses between the predicted and ground truth frames.
+
+ @param gen_frames: The predicted frames at each scale.
+ @param gt_frames: The ground truth frames at each scale
+ @param l_num: 1 or 2 for l1 and l2 loss, respectively).
+
+ @return: The lp loss.
+ """
+ # calculate the loss for each scale
+ scale_losses = []
+ for i in xrange(len(gen_frames)):
+ scale_losses.append(tf.reduce_sum(tf.abs(gen_frames[i] - gt_frames[i])**l_num))
+
+ # condense into one tensor and avg
+ return tf.reduce_mean(tf.pack(scale_losses))
+
+
+def gdl_loss(gen_frames, gt_frames, alpha):
+ """
+ Calculates the sum of GDL losses between the predicted and ground truth frames.
+
+ @param gen_frames: The predicted frames at each scale.
+ @param gt_frames: The ground truth frames at each scale
+ @param alpha: The power to which each gradient term is raised.
+
+ @return: The GDL loss.
+ """
+ # calculate the loss for each scale
+ scale_losses = []
+ for i in xrange(len(gen_frames)):
+ # create filters [-1, 1] and [[1],[-1]] for diffing to the left and down respectively.
+ pos = tf.constant(np.identity(3), dtype=tf.float32)
+ neg = -1 * pos
+ filter_x = tf.expand_dims(tf.pack([neg, pos]), 0) # [-1, 1]
+ filter_y = tf.pack([tf.expand_dims(pos, 0), tf.expand_dims(neg, 0)]) # [[1],[-1]]
+ strides = [1, 1, 1, 1] # stride of (1, 1)
+ padding = 'SAME'
+
+ gen_dx = tf.abs(tf.nn.conv2d(gen_frames[i], filter_x, strides, padding=padding))
+ gen_dy = tf.abs(tf.nn.conv2d(gen_frames[i], filter_y, strides, padding=padding))
+ gt_dx = tf.abs(tf.nn.conv2d(gt_frames[i], filter_x, strides, padding=padding))
+ gt_dy = tf.abs(tf.nn.conv2d(gt_frames[i], filter_y, strides, padding=padding))
+
+ grad_diff_x = tf.abs(gt_dx - gen_dx)
+ grad_diff_y = tf.abs(gt_dy - gen_dy)
+
+ scale_losses.append(tf.reduce_sum((grad_diff_x ** alpha + grad_diff_y ** alpha)))
+
+ # condense into one tensor and avg
+ return tf.reduce_mean(tf.pack(scale_losses))
+
+
+def adv_loss(preds, labels):
+ """
+ Calculates the sum of BCE losses between the predicted classifications and true labels.
+
+ @param preds: The predicted classifications at each scale.
+ @param labels: The true labels. (Same for every scale).
+
+ @return: The adversarial loss.
+ """
+ # calculate the loss for each scale
+ scale_losses = []
+ for i in xrange(len(preds)):
+ loss = bce_loss(preds[i], labels)
+ scale_losses.append(loss)
+
+ # condense into one tensor and avg
+ return tf.reduce_mean(tf.pack(scale_losses))