Función de pérdida para clasificador binario desequilibrado de clase en flujo tensor


Estoy tratando de aplicar el aprendizaje profundo para un problema de clasificación binaria con un desequilibrio de clase alto entre las clases objetivo (500k, 31K). Quiero escribir una función de pérdida personalizada que debería ser como: minimize (100 - ((predicted_smallerclass)/(total_smallerclass))*100)

Aprecio cualquier consejo sobre cómo puedo construir esta lógica.

Author: Venkata Dikshit Pappu, 2016-02-02

6 answers

Puede agregar pesos de clase a la función de pérdida, multiplicando logits. La pérdida de entropía cruzada regular es la siguiente:

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

En caso ponderado:

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

Así que multiplicando logits, usted está re-escalando las predicciones de cada clase por su peso de clase.

Por ejemplo:

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")

Ahora hay una función de pérdidas estándar que admite pesos por lote:

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

Donde los pesos deben transformarse de pesos de clase a un peso por ejemplo (con forma [batch_size]). Ver documentación aquí.

 30
Author: ilblackdragon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-30 20:00:03

El código que propuso me parece incorrecto. La pérdida debe multiplicarse por el peso, estoy de acuerdo.

Pero si multiplicas el logit por los pesos de la clase, terminas con:

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

El segundo término no es igual a:

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

Para mostrar esto, podemos reescribir este último como:

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

Así que aquí está el código que estoy proponiendo:

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
 36
Author: JL Meunier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-16 14:35:44

Uso tf.nn.weighted_cross_entropy_with_logits() y establecer pos_weight a 1 / (relación esperada de positivos).

 9
Author: Malay Haldar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-25 19:43:10

Puede consultar las guías en tensorflow https://www.tensorflow.org/api_guides/python/contrib.losses

...

Al especificar una pérdida escalar reescala la pérdida sobre todo el lote, a veces queremos reescalar la pérdida por muestra de lote. Por ejemplo, si tenemos ciertos ejemplos que nos importan más para obtener correctamente, es posible que deseemos tener una pérdida mayor que otras muestras cuyos errores importan menos. En este caso, podemos proporcionar un vector de peso de longitud batch_size que resulta en la pérdida de cada muestra en el lote siendo escalado por el elemento de peso correspondiente. Por ejemplo, consideremos el caso de un problema de clasificación donde queremos maximizar nuestra precisión, pero estamos especialmente interesados en obtener una alta precisión para una clase específica:

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)
 3
Author: Victor Mondejar-Guerra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-05 14:56:50

Tuve que trabajar con un conjunto de datos desequilibrado similar de múltiples clases y así es como trabajé a través de él, espero que ayude a alguien que busca una solución similar:

Esto va dentro de tu módulo de entrenamiento:

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)

Esto va dentro de la definición de su clase modelo:

#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
 2
Author: bitspersecond,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-01 17:00:46

Did ops tf.nn.weighted_cross_entropy_with_logits () para dos clases:

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)
 1
Author: Denis Shcheglov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-10 15:34:17