Реализация контрастных потерь и триплетных потерь в Tensorflow

24

Я начал играть с TensorFlow два дня назад, и мне интересно, есть ли триплет и контрастные потери.

Я смотрел документацию , но я не нашли никакого примера или описания об этих вещах.

    
задан Tiago Freitas Pereira 08.07.2016 в 08:20
источник

3 ответа

49

Обновление (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, т. е. на питоне и передавать их в сеть через заполнители. В основном вы выбираете изображения 3 за раз, причем первые два из одного и того же класса и третий из другого класса. Затем мы выполняем прямое соединение этих триплетов и вычисляем потерю триплета.

Проблема в том, что генерация триплетов сложна. Мы хотим, чтобы они были действительными тройками , триплетами с положительной потерей (в противном случае потеря равна 0, а сеть не учится). Чтобы узнать, хорош ли триплет или нет, вам нужно вычислить его потерю, поэтому вы уже делаете одну прямую через сеть ...

Ясно, что реализация триплетной потери в Tensorflow сложна, и есть способы сделать ее более эффективной, чем выборка на python, но для объяснения им потребуется целая запись в блоге!

    
ответ дан Olivier Moindrot 08.07.2016 в 17:23
источник
  • Привет @Olivier, меня очень интересует часть выборки. Не могли бы вы или вы опубликовали для него блог? Я делаю то, что вы сказали, чтобы прокормить вперед один раз и вычислить потери для всех возможных триплетов, отфильтровать недопустимые и пробовать пакет, чтобы сделать еще один вперед + назад ... –  weitang114 02.08.2016 в 08:13
  • Не писал ни одного сообщения в блоге. Одним из ключевых понятий является вычисление всех возможных триплетов, как описано в OpenFace, мой ответ выше содержит старое решение. Чтобы удалить вызов средней sess.run (), вы можете добавить операцию tf.py_func внутри графика, чтобы отфильтровать плохие триплеты. –  Olivier Moindrot 08.08.2016 в 23:49
  • @ weitang114: Другой способ для второй части - просто вычислить потерю для всех триплетов, удалив только недействительные триплеты (т. е. (+, +, +)), которые могут быть вычислены заранее. Это удивительно сходится. –  Olivier Moindrot 08.08.2016 в 23:52
  • благодарю вас за этот совет. В тот момент я не понял, но нашел это очень полезным в последнее время. Этот процесс, реализованный в tf, помог мне сократить время обучения от 5 дней до 1 дня. :) –  weitang114 29.10.2016 в 16:05
  • @HelloLili: Я, наконец, написал это сообщение в блоге. Вот он: omoindrot.github.io/triplet-loss –  Olivier Moindrot 20.03.2018 в 05:41
Показать остальные комментарии
7

Потеря триплета с полужесткой отрицательной добычей теперь реализована в tf.contrib следующим образом:

triplet_semihard_loss(
    labels,
    embeddings,
    margin=1.0
)

, где:

  

Args:

  • метки: 1-D tf.int32 Тензор с формой [batch_size] многоклассов целые метки.

  • Вложения: двухмерный плавающий тензор векторов вложения. нормирована на l2.

  • margin: Float, margin term in the loss definition.
  

Возврат:

  • triplet_loss: сканер tf.float32.

Для получения дополнительной информации, проверьте приведенную ниже ссылку:

Ссылка

    
ответ дан Corey Lynch 10.01.2018 в 02:49
источник
  • Ссылка только на ответы? Включите некоторые соответствующие части из ссылки здесь. –  Sunil 10.01.2018 в 03:06
  • Хотя эта ссылка может предоставить некоторую ограниченную немедленную помощь, ответ должен включать достаточный контекст вокруг ссылки, чтобы ваши друзья-пользователи имели представление о том, что это такое и почему оно есть. Всегда указывайте наиболее значимую часть важной ссылки, чтобы сделать ее более полезной для будущих читателей с другими аналогичными вопросами. Кроме того, другие пользователи склонны отрицательно реагировать на ответы, которые являются едва ли более чем ссылкой на внешний сайт, и они могут быть удалены. –  Machavity 10.01.2018 в 03:07
  • Хотя эта ссылка может ответить на вопрос, лучше включить здесь основные части ответа и предоставить ссылку для справки. Ответные ссылки могут стать недействительными, если связанная страница изменится. - Из обзора –  Aryan 10.01.2018 в 04:02
4

Тьяго, я не думаю, что вы используете ту же формулу, которую дал Оливье. Вот правильный код (не уверен, что он будет работать, хотя и исправляя формулу):

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
    
ответ дан Wassim Gr 17.07.2016 в 01:51
источник
  • Привет Вассим, спасибо за исправление, просто патч в вашем коде. d_sqrt = tf.sqrt (compute_euclidean_distance (left_feature, right_feature)) Но даже с этим исправлением я получаю очень низкую точность (но убыток уменьшается, как ожидалось). –  Tiago Freitas Pereira 17.07.2016 в 20:34
  • @TiagoFreitasPereira У меня такая же проблема с реализацией триплетной потери. Я сообщу вам, если найду решение ... –  Wassim Gr 17.07.2016 в 20:52
  • Эй @ Вассим, спасибо. Если это проще, вы можете попытаться загрузить мой проект (github.com/tiagofrepereira2012/examples.tensorflow). –  Tiago Freitas Pereira 18.07.2016 в 06:37
  • @TiagoFreitasPereira, похоже, что это связано с тем, как мы реализуем вычисления точности. Похоже, что при использовании потери триплета или контрастной потери вы не можете вычислить точность с помощью проверки меток (потому что сеть не была обучена дифференциации 10 классов), однако вам нужно вычислить точность, оценив, полагает ли сеть, что два элемента из того же класса или нет. –  Wassim Gr 18.07.2016 в 20:21
  • См. разделы 4 и 5.6 настоящего документа arxiv.org/pdf/1503.03832v3.pdf –  Wassim Gr 19.07.2016 в 04:17
Показать остальные комментарии