Implementing contrastive loss and triplet loss in Tensorflow

匿名 (未验证) 提交于 2019-12-03 07:50:05

问题:

I started to play with TensorFlow two days ago and I'm wondering if there is the triplet and the contrastive losses implemented.

I've been looking at the documentation, but I haven't found any example or description about these things.

回答1:

You need to implement yourself the contrastive loss or the triplet loss, but once you know the pairs or triplets this is quite easy.


Contrastive Loss

Suppose you have as input the pairs of data and their label (positive or negative, i.e. same class or different class). For instance you have images as input of size 28x28x1:

left = tf.placeholder(tf.float32, [None, 28, 28, 1]) right = tf.placeholder(tf.float32, [None, 28, 28, 1]) label = tf.placeholder(tf.int32, [None, 1]). # 0 if same, 1 if different margin = 0.2  left_output = model(left)  # shape [None, 128] right_output = model(right)  # shape [None, 128]  d = tf.reduce_sum(tf.square(left_output - right_output), 1) d_sqrt = tf.sqrt(d)  loss = label * tf.square(tf.maximum(0., margin - d_sqrt)) + (1 - label) * d  loss = 0.5 * tf.reduce_mean(loss) 

Triplet Loss

Same as with contrastive loss, but with triplets (anchor, positive, negative). You don't need labels here.

anchor_output = ...  # shape [None, 128] positive_output = ...  # shape [None, 128] negative_output = ...  # shape [None, 128]  d_pos = tf.reduce_sum(tf.square(anchor_output - positive_output), 1) d_neg = tf.reduce_sum(tf.square(anchor_output - negative_output), 1)  loss = tf.maximum(0., margin + d_pos - d_neg) loss = tf.reduce_mean(loss) 

The real trouble when implementing triplet loss or contrastive loss in TensorFlow is how to sample the triplets or pairs. I will focus on generating triplets because it is harder than generating pairs.

The easiest way is to generate them outside of the Tensorflow graph, i.e. in python and feed them to the network through the placeholders. Basically you select images 3 at a time, with the first two from the same class and the third from another class. We then perform a feedforward on these triplets, and compute the triplet loss.

The issue here is that generating triplets is complicated. We want them to be valid triplets, triplets with a positive loss (otherwise the loss is 0 and the network doesn't learn).
To know whether a triplet is good or not you need to compute its loss, so you already make one feedforward through the network...

Clearly, implementing triplet loss in Tensorflow is hard, and there are ways to make it more efficient than sampling in python but explaining them would require a whole blog post !



回答2:

Triplet loss with semihard negative mining is now implemented in tf.contrib, as follows:

triplet_semihard_loss(     labels,     embeddings,     margin=1.0 ) 

where:

Args:

  • labels: 1-D tf.int32 Tensor with shape [batch_size] of multiclass integer labels.

  • embeddings: 2-D float Tensor of embedding vectors.Embeddings should be l2 normalized.

  • margin: Float, margin term in theloss definition.

Returns:

  • triplet_loss: tf.float32 scalar.

For further information, check the link bellow:

https://www.tensorflow.org/versions/master/api_docs/python/tf/contrib/losses/metric_learning/triplet_semihard_loss



回答3:

Tiago, I don't think you are using the same formula Olivier gave. Here is the right code (not sure it will work though, just fixing the formula) :

def compute_euclidean_distance(x, y):     """     Computes the euclidean distance between two tensorflow variables     """      d = tf.reduce_sum(tf.square(tf.sub(x, y)),1)     return d   def compute_contrastive_loss(left_feature, right_feature, label, margin):      """     Compute the contrastive loss as in       L = 0.5 * Y * D^2 + 0.5 * (Y-1) * {max(0, margin - D)}^2      **Parameters**      left_feature: First element of the pair      right_feature: Second element of the pair      label: Label of the pair (0 or 1)      margin: Contrastive margin      **Returns**      Return the loss operation      """      label = tf.to_float(label)     one = tf.constant(1.0)      d = compute_euclidean_distance(left_feature, right_feature)     d_sqrt = tf.sqrt(compute_euclidean_distance(left_feature, right_feature))     first_part = tf.mul(one-label, d)# (Y-1)*(d)      max_part = tf.square(tf.maximum(margin-d_sqrt, 0))     second_part = tf.mul(label, max_part)  # (Y) * max(margin - d, 0)      loss = 0.5 * tf.reduce_mean(first_part + second_part)      return loss 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!