Función de costo de ajuste de Tensorflow para datos desequilibrados


12

Tengo un problema de clasificación con datos altamente desequilibrados. He leído que sobremuestrear y submuestrear, así como cambiar el costo de resultados categóricos subrepresentados, conducirá a una mejor adaptación. Antes de que esto se hiciera, tensorflow clasificaría cada entrada como el grupo mayoritario (y obtendría más del 90% de precisión, por insignificante que sea).

He notado que el registro del porcentaje inverso de cada grupo ha hecho el mejor multiplicador que he probado. ¿Existe una manipulación más estándar para la función de costo? ¿Se implementa esto correctamente?

from collections import Counter
counts = Counter(category_train)
weightsArray =[]
for i in range(n_classes):
    weightsArray.append(math.log(category_train.shape[0]/max(counts[i],1))+1)

class_weight = tf.constant(weightsArray)
weighted_logits = tf.mul(pred, class_weight)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(weighted_logits, y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

¿Tienen alguna referencia científica sobre cómo elegir idealmente los pesos para la función de pérdida? No es que no te crea, ¿pero pensé que estabas muy inspirado por alguien más?
Gerhard Hagerer

Y como davidparks21 ya preguntó, los resultados de su enfoque serían muy interesantes :).
Gerhard Hagerer

Respuestas:


4

Esto parece una buena solución para la función de pérdida. He tenido éxito con un enfoque similar recientemente, pero creo que querrías reordenar donde multiplicas en class_weight.

Pensando en ello lógicamente, class_weightserá una constante wrt la salida, por lo que se llevará a lo largo y se aplicará al gradiente de la misma manera que se aplica a la función de costo. Sin embargo, hay un problema.

De la forma en que lo tenga, class_weightafectaría el valor de predicción. Pero desea que afecte la escala del gradiente. Si no me equivoco, creo que querría invertir el orden de las operaciones:

# Take the cost like normal
error = tf.nn.softmax_cross_entropy_with_logits(pred, y)

# Scale the cost by the class weights
scaled_error = tf.mul(error, class_weight)

# Reduce
cost = tf.reduce_mean(scaled_error)

Me interesaría saber cómo funciona esto en comparación con simplemente sobremuestrear la clase subrepresentada, lo cual es más típico. Entonces, si obtienes alguna idea, ¡publica al respecto! :)

Curiosamente, utilicé con éxito una técnica muy similar en un dominio de problemas diferente recientemente (lo que me trajo a esta publicación):

Aprendizaje de tareas múltiples, encontrar una función de pérdida que "ignora" ciertas muestras


2

Pago tf.nn.weighted_cross_entropy_with_logits():

Calcula una entropía cruzada ponderada.

Esto es como sigmoid_cross_entropy_with_logits (), excepto que pos_weight, permite intercambiar el recuerdo y la precisión ponderando hacia arriba o hacia abajo el costo de un error positivo en relación con un error negativo.

Esto debería permitirte hacer lo que quieras.


0

Tengo 2 implementaciones diferentes:

  1. con softmax 'regular' con logits: tf.nn.softmax_cross_entropy_with_logits

Donde class_weight es un marcador de posición, lo relleno en la iteración por lotes de everey.

self.class_weight  = tf.placeholder(tf.float32, shape=self.batch_size,self._num_classes], name='class_weight')    
self._final_output = tf.matmul(self._states,self._weights["linear_layer"]) + self._biases["linear_layer"] 
self.scaled_logits = tf.multiply(self._final_output, self.class_weight)
self.softmax = tf.nn.softmax_cross_entropy_with_logits(logits=self.scaled_logits,labels= self._labels)
  1. con tf.nn.softmax_cross_entropy_with_logits

Donde uso la función de tensorflow implementada pero necesito calcular los pesos para el lote. Los documentos son un poco confusos al respecto. Hay 2 formas de hacerlo con tf.gather o de esta manera:

self.scaled_class_weights=tf.reduce_sum(tf.multiply(self._labels,self.class_weight),1)
self.softmax = tf.losses.softmax_cross_entropy(logits=self._final_output,
                                                   onehot_labels=self._labels,weights=self.scaled_class_weights)

aquí hay una buena discusión al respecto

Y, finalmente, como no quería casarme con ninguna de las implementaciones de manera permanente, agregué un poco de tf.case y pasé el tiempo de entrenamiento a la estrategia que quiero usar.

self.sensitive_learning_strategy = tf.placeholder(tf.int32 , name='sensitive_learning_strategy')
self.softmax =tf.case([
            (tf.equal(self.sensitive_learning_strategy, 0), lambda: self.softmax_0),
            (tf.equal(self.sensitive_learning_strategy, 1), lambda: self.softmax_1),
            (tf.equal(self.sensitive_learning_strategy, 2), lambda: self.softmax_2)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.