it-swarm.com.de

Verlustfunktion für klassenunausgeglichene binäre Klassifizierer im Tensorfluss

Ich versuche tiefes Lernen für ein binäres Klassifizierungsproblem mit hochklassigem Ungleichgewicht zwischen Zielklassen (500.000, 31.000) anzuwenden. Ich möchte eine benutzerdefinierte Verlustfunktion schreiben, die wie folgt aussehen sollte: Minimieren (100 - ((predicted_smallerclass)/(total_smallerclass)) * 100)

Ich schätze alle Hinweise darauf, wie ich diese Logik aufbauen kann. 

43

Sie können der Verlustfunktion Klassengewichte hinzufügen, indem Sie Logits multiplizieren. .__ Regelmäßiger Kreuzentropieverlust ist dies:

loss(x, class) = -log(exp(x[class]) / (\sum_j exp(x[j])))
               = -x[class] + log(\sum_j exp(x[j]))

im gewichteten Fall:

loss(x, class) = weights[class] * -x[class] + log(\sum_j exp(weights[class] * x[j]))

Durch das Multiplizieren von Logits skalieren Sie also Vorhersagen für jede Klasse mit ihrem Klassengewicht.

Zum Beispiel:

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

Es gibt jetzt eine Standardverlustfunktion, die Gewichte pro Charge unterstützt:

tf.losses.sparse_softmax_cross_entropy(labels=label, logits=logits, weights=weights)

Wo Gewichte von Klassengewichten in ein Gewicht pro Beispiel (mit Form [batch_size]) umgewandelt werden Dokumentation hier .

38
ilblackdragon

Der von Ihnen vorgeschlagene Code scheint mir falsch zu sein. Der Verlust sollte mit dem Gewicht multipliziert werden, stimme ich zu.

Wenn Sie jedoch das Logit mit den Klassengewichtungen multiplizieren, enden Sie mit:

weights[class] * -x[class] + log( \sum_j exp(x[j] * weights[class]) )

Der zweite Begriff ist nicht gleich: 

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

Um dies zu zeigen, können wir das letztere wie folgt umschreiben: 

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

Hier ist der Code, den ich vorschlage:

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
38
JL Meunier

Verwenden Sie tf.nn.weighted_cross_entropy_with_logits() und setzen Sie pos_weight auf 1/(erwartetes positives Verhältnis).

10
Malay Haldar

Sie können die Anleitungen unter tensorflow überprüfen https://www.tensorflow.org/api_guides/python/contrib.losses

...

Wenn Sie einen Skalarverlust angeben, wird der Verlust über die gesamte Charge neu skaliert. Manchmal möchten wir jedoch den Verlust pro Stapelprobe neu skalieren. Wenn wir zum Beispiel bestimmte Beispiele haben, die für uns wichtiger sind, um richtig zu kommen, möchten wir möglicherweise einen höheren Verlust als andere Proben, deren Fehler weniger wichtig sind. In diesem Fall können wir einen Gewichtsvektor der Länge batch_size bereitstellen, der dazu führt, dass der Verlust für jede Probe in der Charge durch das entsprechende Gewichtselement skaliert wird. Betrachten wir zum Beispiel den Fall eines Klassifizierungsproblems, bei dem wir unsere Genauigkeit maximieren möchten, insbesondere aber an einer hohen Genauigkeit für eine bestimmte Klasse interessiert sind:

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)

Ich musste mit einem ähnlichen, unausgewogenen Dataset aus mehreren Klassen arbeiten, und so habe ich es durchgearbeitet. Ich hoffe, es hilft jemandem, der nach einer ähnlichen Lösung sucht:

Dies geht in Ihr Trainingsmodul: 

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)

Dies geht in Ihre Modellklassendefinition ein:

#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
3
bitspersecond

Haben ops tf.nn.weighted_cross_entropy_with_logits () für zwei Klassen:

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)
1
Denis Shcheglov