web-dev-qa-db-fra.com

Données déséquilibrées et entropie croisée pondérée

J'essaie de former un réseau avec des données non équilibrées. J'ai A (198 échantillons), B (436 échantillons), C (710 échantillons), D (272 échantillons) et j'ai lu des articles sur "weighted_cross_entropy_with_logits", mais tous les exemples que j'ai trouvés sont destinés à une classification binaire, de sorte que je ne suis pas très confiant dans la façon de définir ces poids.

Total des échantillons: 1616

A_weight: 198/1616 = 0,12?

L'idée derrière, si j'ai bien compris, est de pénaliser les erreurs de la classe de maire et de valoriser plus positivement les succès de la minorité, non?

Mon morceau de code:

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

J'ai lu celui-ci et d'autres exemples avec une classification binaire mais toujours pas très clair.

Merci d'avance.

43
Sergiodiaz53

Notez que weighted_cross_entropy_with_logits est la variante pondérée de sigmoid_cross_entropy_with_logits. L'entropie croisée sigmoïde est généralement utilisée pour la classification binaire . Oui, il peut gérer plusieurs étiquettes, mais l'entropie croisée sigmoïde prend une décision (binaire) sur chacune d'elles - par exemple, pour un réseau de reconnaissance faciale, ces étiquettes (qui ne s'excluent pas mutuellement) pourraient être " Le sujet porte-t-il des lunettes? "," Le sujet est-il une femme? ", etc.

Dans les classifications binaires, chaque canal de sortie correspond à une décision binaire (souple). Par conséquent, la pondération doit être prise en compte dans le calcul de la perte. C'est quoi weighted_cross_entropy_with_logits _, en pondérant un terme de l'entropie croisée par rapport à l'autre.

Dans la classification multilabel mutuellement exclusive, nous utilisons softmax_cross_entropy_with_logits, qui se comporte différemment: chaque canal de sortie correspond au score d'un candidat de la classe. La décision vient après , en comparant les sorties respectives de chaque canal.

La pondération avant la décision finale consiste donc simplement à modifier les scores avant de les comparer, généralement par multiplication avec des pondérations. Par exemple, pour une tâche de classification ternaire,

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

Vous pouvez également compter sur tf.losses.softmax_cross_entropy pour gérer les trois dernières étapes.

Dans votre cas, où vous devez remédier au déséquilibre des données, les poids de classe pourraient en effet être inversement proportionnels à leur fréquence dans les données de votre train. Les normaliser de manière à ce qu'ils totalisent une ou plusieurs classes a également du sens.

Notez que dans ce qui précède, nous avons pénalisé la perte sur la base de la véritable étiquette des échantillons. Nous aurions également pu pénaliser la perte sur la base des étiquettes estimées en définissant simplement

weights = class_weights

et le reste du code n'a pas besoin de changer grâce à la magie de diffusion.

Dans le cas général, vous voudriez des poids qui dépendent du type d'erreur que vous faites. En d'autres termes, pour chaque paire d'étiquettes X et Y, vous pouvez choisir comment pénaliser le choix de l'étiquette X lorsque le véritable libellé est Y. Vous vous retrouvez avec une matrice de poids complète antérieure, ce qui a pour résultat que weights ci-dessus est un entier (num_samples, num_classes) tenseur. Cela va un peu au-delà de ce que vous voulez, mais il peut être utile de savoir néanmoins que seule votre définition du tenseur de poids doit changer dans le code ci-dessus.

65
P-Gn

Voir cette réponse pour une solution alternative fonctionnant avec 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()
0
DankMasterDan