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 desequilibrio de clase alta entre las clases objective (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 sugerencia sobre cómo puedo construir esta lógica.

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

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 al multiplicar logits, estás volviendo a escalar 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í .

El código que propones me parece incorrecto. La pérdida debería multiplicarse por el peso, estoy de acuerdo.

Pero si multiplicas el logit por los pesos de 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 el último como:

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

Así que aquí está el código que propongo:

 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 

Utilice tf.nn.weighted_cross_entropy_with_logits() y establezca pos_weight en 1 / (proporción esperada de positivos).

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

Si bien la especificación de una pérdida escalar reescala la pérdida en 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 da como resultado la pérdida para cada muestra en el lote que está siendo escalado por el elemento de peso correspondiente. Por ejemplo, considere el caso de un problema de clasificación donde queremos maximizar nuestra precisión, pero nos interesa especialmente 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) 

Tuve que trabajar con un conjunto de datos desequilibrado similar de varias clases y así es como lo resolví, espero que ayude a alguien a buscar 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 su definición de clase de 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 

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