Несбалансированные данные и взвешенная перекрестная энтропия

Я пытаюсь обучить сеть с несбалансированными данными. У меня есть A (198 сэмплов), B (436 сэмплов), C (710 сэмплов), D (272 сэмпла), и я прочитал о "weighted_cross_entropy_with_logits", но все примеры, которые я нашел, предназначены для двоичной классификации, поэтому я не очень уверен в том, как установить эти веса.

Всего образцов: 1616

A_weight: 198/1616 = 0,12?

Идея, лежащая в основе, если я понял, состоит в том, чтобы наказывать за ошибки в классе мэрии и оценивать более позитивно хиты в меньшинстве, верно?

Мой кусок кода:

weights = tf.constant([0.12, 0.26, 0.43, 0.17])
cost = tf.reduce_mean(tf.nn.weighted_cross_entropy_with_logits(logits=pred, targets=y, pos_weight=weights))

Я читал этот и другие примеры с бинарной классификацией, но все еще не очень ясно.

Заранее спасибо.

4 ответа

Решение

Обратите внимание, что weighted_cross_entropy_with_logits это взвешенный вариант sigmoid_cross_entropy_with_logits, Сигмоидальная перекрестная энтропия обычно используется для бинарной классификации. Да, он может обрабатывать несколько меток, но сигмоидальная перекрестная энтропия в основном принимает (двоичное) решение по каждому из них - например, для сети распознавания лиц эти (не взаимоисключающие) метки могут быть такими: "Носит ли субъект очки?","Является ли субъект женщиной?"И т. Д.

В двоичной классификации каждый выходной канал соответствует двоичному (мягкому) решению. Следовательно, взвешивание должно происходить при расчете потерь. Это то, что weighted_cross_entropy_with_logits делает, взвешивая один член кросс-энтропии над другим.

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

Таким образом, взвешивание перед окончательным решением - это простой вопрос изменения оценок перед их сравнением, обычно путем умножения на веса. Например, для задачи троичной классификации,

# your class weights
class_weights = tf.constant([[1.0, 2.0, 3.0]])
# deduce weights for batch samples based on their true label
weights = tf.reduce_sum(class_weights * onehot_labels, axis=1)
# compute your (unweighted) softmax cross entropy loss
unweighted_losses = tf.nn.softmax_cross_entropy_with_logits(onehot_labels, logits)
# apply the weights, relying on broadcasting of the multiplication
weighted_losses = unweighted_losses * weights
# reduce the result to get your final loss
loss = tf.reduce_mean(weighted_losses)

Вы также можете положиться на tf.losses.softmax_cross_entropy обрабатывать последние три шага.

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

Обратите внимание, что в приведенном выше примере мы оштрафовали потери на основе истинной маркировки образцов. Мы могли бы также оштрафовать убыток, основываясь на оценочных ярлыках, просто определив

weights = class_weights

и остальная часть кода не должна изменяться благодаря магии вещания.

В общем случае вам нужны веса, которые зависят от типа ошибки, которую вы делаете. Другими словами, для каждой пары ярлыков X а также YВы можете выбрать, как оштрафовать, выбрав ярлык X когда истинный ярлык Y, В итоге вы получаете целую матрицу весов, что приводит к weights выше быть полным (num_samples, num_classes) тензор. Это выходит за рамки того, что вы хотите, но, тем не менее, полезно знать, что в приведенном выше коде нужно изменить только ваше определение весового тензора.

Посмотрите этот ответ для альтернативного решения, которое работает с sparse_softmax_cross_entropy

Ответ, совместимый с Tensorflow 2.0: перенос кода, указанного в ответе P-Gn, на версию 2.0 в интересах сообщества.

# your class weights
class_weights = tf.compat.v2.constant([[1.0, 2.0, 3.0]])
# deduce weights for batch samples based on their true label
weights = tf.compat.v2.reduce_sum(class_weights * onehot_labels, axis=1)
# compute your (unweighted) softmax cross entropy loss
unweighted_losses = tf.compat.v2.nn.softmax_cross_entropy_with_logits(onehot_labels, logits)
# apply the weights, relying on broadcasting of the multiplication
weighted_losses = unweighted_losses * weights
# reduce the result to get your final loss
loss = tf.reduce_mean(weighted_losses)

Для получения дополнительной информации о миграции кода с Tensorflow версии 1.x на 2.x обратитесь к этому руководству по миграции.

Фактически вы можете сохранить категориальную потерю кроссэнтропии и тренироваться, используяclass_weightпараметр. В описании сказано:

Необязательные индексы классов сопоставления словаря (целые числа) со значением веса (с плавающей запятой), используемым для взвешивания функции потерь (только во время обучения). Это может быть полезно, чтобы сказать модели «уделять больше внимания» образцам из недостаточно представленного класса. Если указан class_weight и целевые объекты имеют ранг 2 или выше, либо y должен быть закодирован в горячем виде, либо для разреженных меток классов должно быть включено явное конечное измерение 1.

Я использовал его сtotal_samples / (2 * class_occurences)и сработало, то есть ваш список разделен на 2, но вашweightslist также должен помочь, просто проверьте, какое значение подходит вам лучше всего.

Здесь есть хорошее руководство по TF для работы с несбалансированными данными .

Другие вопросы по тегам