python - raspberry - Datos no balanceados y entropía cruzada ponderada
tensorflow mnist (2)
Estoy tratando de entrenar una red con datos no balanceados. Tengo A (198 muestras), B (436 muestras), C (710 muestras), D (272 muestras) y he leído sobre "weighted_cross_entropy_with_logits", pero todos los ejemplos que encontré son para clasificación binaria, así que no soy muy confía en cómo establecer esos pesos.
Muestras totales: 1616
A_weight: 198/1616 = 0.12?
La idea detrás, si entendí, es penalizar los errores de la clase mayoritaria y valorar más positivamente los golpes en la minoría, ¿verdad?
Mi pieza de código:
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))
He leído este y otros ejemplos con clasificación binaria, pero aún no está muy claro.
Gracias por adelantado.
Tenga en cuenta que
weighted_cross_entropy_with_logits
es la variante ponderada de
sigmoid_cross_entropy_with_logits
.
La entropía cruzada sigmoidea se usa típicamente para la clasificación
binaria
.
Sí, puede manejar múltiples etiquetas, pero la entropía cruzada sigmoidea básicamente toma una decisión (binaria) sobre cada una de ellas; por ejemplo, para una red de reconocimiento facial, esas etiquetas (no mutuamente excluyentes) podrían ser "
¿El sujeto usa anteojos?
","
¿El sujeto es femenino?
", Etc.
En las clasificaciones binarias, cada canal de salida corresponde a una decisión binaria (suave).
Por lo tanto, la ponderación debe ocurrir dentro del cálculo de la pérdida.
Esto es lo que hace
weighted_cross_entropy_with_logits
, al ponderar un término de la entropía cruzada sobre el otro.
En la clasificación multicabel mutuamente excluyente, utilizamos
softmax_cross_entropy_with_logits
, que se comporta de manera diferente: cada canal de salida corresponde a la puntuación de un candidato de clase.
La decisión viene
después
, comparando las salidas respectivas de cada canal.
Por lo tanto, ponderar antes de la decisión final es una simple cuestión de modificar los puntajes antes de compararlos, generalmente por multiplicación con pesas. Por ejemplo, para una tarea de clasificación ternaria,
# 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)
También puede confiar en
tf.losses.softmax_cross_entropy
para manejar los últimos tres pasos.
En su caso, donde necesita abordar el desequilibrio de datos, los pesos de clase podrían ser inversamente proporcionales a su frecuencia en los datos de su tren. También tiene sentido normalizarlos para que sumen uno o el número de clases.
Tenga en cuenta que en lo anterior, penalizamos la pérdida en función de la etiqueta real de las muestras. También podríamos haber penalizado la pérdida en función de las etiquetas estimadas simplemente definiendo
weights = class_weights
y el resto del código no necesita cambiar gracias a la transmisión de magia.
En el caso general, querrá pesos que dependan del tipo de error que cometa.
En otras palabras, para cada par de etiquetas
X
e
Y
, puede elegir cómo penalizar la elección de la etiqueta
X
cuando la etiqueta verdadera es
Y
(num_samples, num_classes)
con una matriz de peso anterior completa, lo que da como resultado que los
weights
anteriores sean un tensor completo
(num_samples, num_classes)
.
Esto va un poco más allá de lo que desea, pero podría ser útil saber que solo su definición del tensor de peso debe cambiar en el código anterior.
Vea esta respuesta para una solución alternativa que funciona con sparse_softmax_cross_entropy:
import tensorflow as tf
import numpy as np
np.random.seed(123)
sess = tf.InteractiveSession()
# let''s say we have the logits and labels of a batch of size 6 with 5 classes
logits = tf.constant(np.random.randint(0, 10, 30).reshape(6, 5), dtype=tf.float32)
labels = tf.constant(np.random.randint(0, 5, 6), dtype=tf.int32)
# specify some class weightings
class_weights = tf.constant([0.3, 0.1, 0.2, 0.3, 0.1])
# specify the weights for each sample in the batch (without having to compute the onehot label matrix)
weights = tf.gather(class_weights, labels)
# compute the loss
tf.losses.sparse_softmax_cross_entropy(labels, logits, weights).eval()