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