Tensorflow-Anpassung der Kostenfunktion für unausgeglichene Daten


12

Ich habe ein Klassifizierungsproblem mit stark unausgeglichenen Daten. Ich habe gelesen, dass Über- und Unterabtastung sowie die Änderung der Kosten für unterrepräsentierte kategoriale Ausgaben zu einer besseren Anpassung führen. Bevor dies durchgeführt wurde, kategorisierte Tensorflow jede Eingabe als Mehrheitsgruppe (und gewann eine Genauigkeit von über 90%, so bedeutungslos das auch ist).

Ich habe festgestellt, dass das Protokoll des inversen Prozentsatzes jeder Gruppe den besten Multiplikator ergibt, den ich versucht habe. Gibt es eine Standardmanipulation für die Kostenfunktion? Ist das richtig implementiert?

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)

Habt ihr eine wissenschaftliche Referenz dafür, wie ihr die Gewichte für die Verlustfunktion ideal wählt? Nicht dass ich dir nicht glaube, aber ich dachte du bist sehr inspiriert von jemand anderem?
Gerhard Hagerer

Und wie davidparks21 bereits gefragt hat, wären die Ergebnisse Ihres Ansatzes sehr interessant :).
Gerhard Hagerer

Antworten:


4

Dies scheint eine gute Lösung für die Verlustfunktion zu sein. Ich hatte kürzlich Erfolg mit einem ähnlichen Ansatz, aber ich denke, Sie möchten neu ordnen, wo Sie sich in der multiplizieren class_weight.

class_weightWenn man logisch darüber nachdenkt , wird dies eine Konstante für die Ausgabe sein, so dass es mitgeführt und auf den Gradienten angewendet wird, genauso wie es auf die Kostenfunktion angewendet wird. Es gibt jedoch ein Problem.

Die Art und Weise, wie Sie es haben, class_weightwürde den Vorhersagewert beeinflussen. Sie möchten jedoch, dass sich dies auf die Skalierung des Verlaufs auswirkt. Wenn ich mich nicht irre, sollten Sie die Reihenfolge der Operationen umkehren:

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

Es würde mich sehr interessieren, wie sich dies im Vergleich zu einer einfachen Überabtastung der unterrepräsentierten Klasse verhält, was typischer ist. Wenn du also einen Einblick bekommst, poste darüber! :) :)

Interessanterweise habe ich erst kürzlich erfolgreich eine sehr ähnliche Technik in einem anderen Problembereich angewendet (was mich zu diesem Beitrag geführt hat):

Multitasking-Lernen, Finden einer Verlustfunktion, die bestimmte Proben "ignoriert"


2

Kasse tf.nn.weighted_cross_entropy_with_logits():

Berechnet eine gewichtete Kreuzentropie.

Dies ist wie sigmoid_cross_entropy_with_logits (), mit der Ausnahme, dass pos_weight es ermöglicht, Rückruf und Präzision abzuwägen, indem die Kosten eines positiven Fehlers relativ zu einem negativen Fehler hoch- oder runtergewichtet werden.

So sollten Sie tun können, was Sie wollen.


0

Ich habe 2 verschiedene Implementierungen:

  1. mit 'normalem' softmax mit logits: tf.nn.softmax_cross_entropy_with_logits

Wo das class_weight ein Platzhalter ist, fülle ich es bei jeder Batch-Iteration aus.

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. mit tf.nn.softmax_cross_entropy_with_logits

Wo ich die implementierte Tensorflow-Funktion verwende, aber die Gewichte für die Charge berechnen muss. Die Dokumente sind etwas verwirrend. Es gibt zwei Möglichkeiten, dies mit tf.gather oder ähnlichem zu tun:

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)

Hier gibt es eine nette Diskussion darüber

Und schließlich, da ich nicht dauerhaft mit einer der Implementierungen heiraten wollte, fügte ich einen kleinen Fall hinzu und gab die Trainingszeit an die Strategie weiter, die ich verwenden möchte.

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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.