ContrastiveLoss.py 2.22 KB
Newer Older
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
1 2 3 4 5 6
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>

import logging
import tensorflow as tf
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
7
from bob.learn.tensorflow.utils import compute_euclidean_distance
8

Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
9
logger = logging.getLogger(__name__)
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
10 11


Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
12
def contrastive_loss(left_embedding, right_embedding, labels, contrastive_margin=2.0):
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
13 14 15 16 17
    """
    Compute the contrastive loss as in

    http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf

18
    :math:`L = 0.5 * (1-Y) * D^2 + 0.5 * (Y) * {max(0, margin - D)}^2`
19

20
    where, `0` are assign for pairs from the same class and `1` from pairs from different classes.
21

Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
22 23

    **Parameters**
24

Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
25 26 27 28 29 30
    left_feature:
      First element of the pair

    right_feature:
      Second element of the pair

31
    labels:
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
32 33 34 35
      Label of the pair (0 or 1)

    margin:
      Contrastive margin
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
36 37 38

    """

39 40
    with tf.name_scope("contrastive_loss"):
        labels = tf.to_float(labels)
41

42
        left_embedding = tf.nn.l2_normalize(left_embedding, 1)
43
        right_embedding = tf.nn.l2_normalize(right_embedding, 1)
44 45

        d = compute_euclidean_distance(left_embedding, right_embedding)
46

47
        with tf.name_scope("within_class"):
48
            one = tf.constant(1.0)
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
49 50
            within_class = tf.multiply(one - labels, tf.square(d))  # (1-Y)*(d^2)
            within_class_loss = tf.reduce_mean(within_class, name="within_class")
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
51
            tf.add_to_collection(tf.GraphKeys.LOSSES, within_class_loss)
52 53 54

        with tf.name_scope("between_class"):
            max_part = tf.square(tf.maximum(contrastive_margin - d, 0))
55
            between_class = tf.multiply(
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
56 57 58
                labels, max_part
            )  # (Y) * max((margin - d)^2, 0)
            between_class_loss = tf.reduce_mean(between_class, name="between_class")
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
59
            tf.add_to_collection(tf.GraphKeys.LOSSES, between_class_loss)
60 61

        with tf.name_scope("total_loss"):
62
            loss = 0.5 * (within_class + between_class)
63
            loss = tf.reduce_mean(loss, name="contrastive_loss")
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
64
            tf.add_to_collection(tf.GraphKeys.LOSSES, loss)
65

Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
66 67 68
        tf.summary.scalar("contrastive_loss", loss)
        tf.summary.scalar("between_class", between_class_loss)
        tf.summary.scalar("within_class", within_class_loss)
69 70

        return loss