Внедрение контрастных потерь и триплетных потерь в Tensorflow
Я начал играть с TensorFlow два дня назад, и мне интересно, есть ли реализованные триплет и сравнительные потери.
Я просматривал документацию, но не нашел ни одного примера или описания этих вещей.
4 ответа
Обновление (2018/03/19): я написал сообщение в блоге, подробно описывающее, как реализовать потерю триплета в TensorFlow.
Вам нужно реализовать себе контрастную потерю или триплетную потерю, но как только вы узнаете пары или триплеты, это довольно легко.
Контрастная потеря
Предположим, у вас есть в качестве входных данных пары данных и их метка (положительная или отрицательная, то есть тот же класс или другой класс). Например, у вас есть изображения размером 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)
Тройная потеря
То же, что и с контрастной потерей, но с тройкой (якорная, положительная, отрицательная). Вам не нужны ярлыки здесь.
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)
Реальная проблема при реализации потери триплетов или контрастных потерь в TensorFlow заключается в том, как выбрать триплеты или пары. Я сосредоточусь на генерации триплетов, потому что это сложнее, чем генерация пар.
Самый простой способ - сгенерировать их вне графа Tensorflow, то есть в python, и передать их в сеть через заполнители. В основном вы выбираете 3 изображения одновременно, причем первые два из одного класса и третье из другого класса. Затем мы выполняем прямую связь с этими триплетами и вычисляем потерю триплетов.
Проблема здесь в том, что генерация триплетов сложна. Мы хотим, чтобы они были действительными триплетами, триплетами с положительной потерей (в противном случае потеря равна 0, и сеть не учится).
Чтобы узнать, хорош ли триплет или нет, вам нужно вычислить его потерю, чтобы вы уже сделали одну прямую связь через сеть...
Очевидно, что реализовать потерю триплетов в Tensorflow сложно, и есть способы сделать ее более эффективной, чем выборка в python, но для их объяснения потребуется целый пост в блоге!
Тройной убыток с полужестким отрицательным майнингом теперь реализован tf.contrib
, следующее:
triplet_semihard_loss(
labels,
embeddings,
margin=1.0
)
где:
Args:
метки: 1-D tf.int32 Тензор с формой [batch_size] мультиклассовых целочисленных меток.
вложения: 2-D float Тензор векторов вложения. Вложения должны быть l2 нормализованы.
- margin: Float, термин наценки в определении потери.
Возвращает:
- triplet_loss: tf.float32 скаляр.
Для получения дополнительной информации, проверьте ссылку ниже:
Тьяго, я не думаю, что ты используешь ту же формулу, что и Оливье. Вот правильный код (не уверен, что он будет работать, просто исправляя формулу):
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
По состоянию на 2021 год эти потери реализованы внутри tenorflow-аддонов: