classification - taguchi - Función de pérdida para clasificador binario desequilibrado de clase en flujo de tensor
taguchi biografia (6)
Estoy tratando de aplicar el aprendizaje profundo para un problema de clasificación binaria con un desequilibrio de clase alta entre las clases objetivo (500k, 31K). Quiero escribir una función de pérdida personalizada que debería ser como: minimizar (100 - ((predicted_smallerclass) / (total_smallerclass)) * 100)
Aprecio cualquier indicador sobre cómo puedo construir esta lógica.
El código que propusiste me parece incorrecto. La pérdida debe multiplicarse por el peso, estoy de acuerdo.
Pero si multiplica el logit por los pesos de la clase, termina 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 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
Hice 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)
Puede agregar ponderaciones 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]))
Entonces, al multiplicar los logits, está 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 los pesos de la clase a un peso por ejemplo (con forma [lote_tamaño]). Ver documentación aquí .
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 resulta en la pérdida para cada muestra en el lote que se escala por el elemento de peso correspondiente. Por ejemplo, considere el caso de un problema de clasificación en el que 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)
Tuve que trabajar con un conjunto de datos desequilibrado similar de varias clases y así es como lo trabajé, espero que ayude a alguien a buscar una solución similar:
Esto va dentro de su 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
Utilice
tf.nn.weighted_cross_entropy_with_logits()
y establezca
pos_weight
en 1 / (relación esperada de positivos).