Подтвердить что ты не робот

Функция потерь для двоичного классификатора класса с дисбалансом в тензорном потоке

Я пытаюсь применить глубокое изучение проблемы двоичной классификации с дисбалансом высокого класса между целевыми классами (500k, 31K). Я хочу написать пользовательскую функцию потерь, которая должна быть такой: свести к минимуму (100 - ((predicted_smallerclass)/(total_smallerclass)) * 100)

Оцените любые указатели на то, как я могу построить эту логику.

4b9b3361

Ответ 1

Вы можете добавить вес класса к функции потерь, умножив логиты. Регулярная потеря кросс-энтропии такова:

loss(x, class) = -log(exp(x[class]) / (\sum_j exp(x[j])))
               = -x[class] + log(\sum_j exp(x[j]))

в взвешенном случае:

loss(x, class) = weights[class] * -x[class] + log(\sum_j exp(weights[class] * x[j]))

Таким образом, умножая логиты, вы повторно масштабируете прогнозы каждого класса по его весу класса.

Например:

ratio = 31.0 / (500.0 + 31.0)
class_weight = tf.constant([ratio, 1.0 - ratio])
logits = ... # shape [batch_size, 2]
weighted_logits = tf.mul(logits, class_weight) # shape [batch_size, 2]
xent = tf.nn.softmax_cross_entropy_with_logits(
  weighted_logits, labels, name="xent_raw")

Теперь существует стандартная функция потерь, поддерживающая весы в партии:

tf.losses.sparse_softmax_cross_entropy(labels=label, logits=logits, weights=weights)

Где веса должны быть преобразованы из весов классов в вес на пример (с формой [batch_size]). См. здесь.

Ответ 2

Код, который вы предложили, кажется мне неправильным. Я согласен. Потеря должна быть умножена на вес.

Но если вы умножаете логит на весы классов, вы заканчиваете:

weights[class] * -x[class] + log( \sum_j exp(x[j] * weights[class]) )

второй член не равен:

weights[class] * log(\sum_j exp(x[j]))

Чтобы показать это, мы можем переписать последнее как:

log( (\sum_j exp(x[j]) ^ weights[class] )

Итак, вот код, который я предлагаю:

ratio = 31.0 / (500.0 + 31.0)
class_weight = tf.constant([[ratio, 1.0 - ratio]])
logits = ... # shape [batch_size, 2]

weight_per_label = tf.transpose( tf.matmul(labels
                           , tf.transpose(class_weight)) ) #shape [1, batch_size]
# this is the weight for each datapoint, depending on its label

xent = tf.mul(weight_per_label
         , tf.nn.softmax_cross_entropy_with_logits(logits, labels, name="xent_raw") #shape [1, batch_size]
loss = tf.reduce_mean(xent) #shape 1

Ответ 3

Используйте tf.nn.weighted_cross_entropy_with_logits() и установите pos_weight в 1/(ожидаемое отношение положительных результатов).

Ответ 4

Вы можете проверить направляющие на tensorflow https://www.tensorflow.org/api_guides/python/contrib.losses

...

При указании скалярной потери перемасштабирование потери по всей партии, мы иногда хотим перемасштабировать потерю за образец партии. Например, если у нас есть некоторые примеры, которые важнее для нас, чтобы получить правильное решение, мы можем захотеть получить более высокую потерю, чем другие образцы, ошибки которых имеют меньшее значение. В этом случае мы можем предоставить весовой вектор длины batch_size, который приводит к потере для каждого образца в партии, масштабируемой соответствующим весовым элементом. Например, рассмотрим случай проблемы классификации, где мы хотим максимизировать нашу точность, но мы особенно заинтересованы в получении высокой точности для конкретного класса:

inputs, labels = LoadData(batch_size=3)
logits = MyModelPredictions(inputs)

# Ensures that the loss for examples whose ground truth class is `3` is 5x
# higher than the loss for all other examples.
weight = tf.multiply(4, tf.cast(tf.equal(labels, 3), tf.float32)) + 1

onehot_labels = tf.one_hot(labels, num_classes=5)
tf.contrib.losses.softmax_cross_entropy(logits, onehot_labels, weight=weight)

Ответ 5

Сделал ops tf.nn.weighted_cross_entropy_with_logits() для двух классов:

classes_weights = tf.constant([0.1, 1.0])
cross_entropy = tf.nn.weighted_cross_entropy_with_logits(logits=logits, targets=labels, pos_weight=classes_weights)

Ответ 6

Мне пришлось работать с подобным несбалансированным набором данных из нескольких классов, и именно так я работал с ним, надеюсь, что это поможет кому-то искать подобное решение:

Это входит в ваш учебный модуль:

from sklearn.utils.class_weight import compute_sample_weight
#use class weights for handling unbalanced dataset
if mode == 'INFER' #test/dev mode, not weighing loss in test mode
   sample_weights = np.ones(labels.shape)
else:
   sample_weights = compute_sample_weight(class_weight='balanced', y=labels)

Это входит в определение вашего модельного класса:

#an extra placeholder for sample weights
#assuming you already have batch_size tensor
self.sample_weight = tf.placeholder(dtype=tf.float32, shape=[None],
                       name='sample_weights')
cross_entropy_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(
                       labels=self.label, logits=logits, 
                       name='cross_entropy_loss')
cross_entropy_loss = tf.reduce_sum(cross_entropy_loss*self.sample_weight) / batch_size