按照我原来的想法,Triplet Loss 三元组应该是这样选择的:
(1) 前馈操作: cnn 先执行forward 操作,获取到embedding 的具体值后,再去用非 tf 函数去处理embedding并生成三元组
(2) 训练操作: 用(1) 生成的三元组进行训练
今天看了下别人的实现代码,直接用Tensorflow 在一次cnn操作中,直接选取并获取最终的loss值。(而我想象的那样,不是一次前馈+一次训练)
很多很巧妙的思路(如果让我写,我想不出来的那种):
(1) 获取所有三元组的loss,已知d[i,j] 是第i个和第j embedding 的距离,dx[i,j,1] = d[i,1,k] = d[i,j]
通过以下一句就可以实现获取所有三元组的loss值
#triplet_loss[i,j,k] = dx[i,j,1] - dy[i,1,k] +margin = d[i,j] - d[i,k] +margin
triplet_loss = anchor_positive_dist - anchor_negative_dist + margin
(2) 通过reduce_max / reduce_min 等操作,省略选取三元组中的各种if 操作
代码来源:https://github.com/omoindrot/tensorflow-triplet-loss/blob/master/model/triplet_loss.py
以下代码加了我的注释:
"""Define functions to create the triplet loss with online triplet mining."""
import tensorflow as tf
# (*) 返回embeddings 两两之间的距离
def _pairwise_distances(embeddings, squared=False):
"""Compute the 2D matrix of distances between all the embeddings.
Args:
embeddings: tensor of shape (batch_size, embed_dim)
squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.
If false, output is the pairwise euclidean distance matrix.
Returns:
pairwise_distances: tensor of shape (batch_size, batch_size)
"""
# Get the dot product between all embeddings
# shape (batch_size, batch_size)
dot_product = tf.matmul(embeddings, tf.transpose(embeddings))
# Get squared L2 norm for each embedding. We can just take the diagonal of `dot_product`.
# This also provides more numerical stability (the diagonal of the result will be exactly 0).
# shape (batch_size,)
square_norm = tf.diag_part(dot_product)
# Compute the pairwise distance matrix as we have:
# ||a - b||^2 = ||a||^2 - 2 <a, b> + ||b||^2
# shape (batch_size, batch_size)
distances = tf.expand_dims