Funkcja korygująca przepływ Tensor dla danych niezrównoważonych

12

Mam problem z klasyfikacją bardzo niezrównoważonych danych. Przeczytałem, że nadmierne i niepełne próbkowanie, a także zmiana kosztu niedostatecznie reprezentowanych wyników kategorycznych doprowadzą do lepszego dopasowania. Zanim to nastąpi, tensorflow klasyfikuje każde wejście jako grupę większościową (i zyskuje ponad 90% dokładności, jakkolwiek to bez znaczenia).

Zauważyłem, że log odwrotnej wartości procentowej każdej grupy jest najlepszym mnożnikiem, jakiego próbowałem. Czy istnieje bardziej standardowa manipulacja dla funkcji kosztu? Czy to jest poprawnie zaimplementowane?

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)
Kapusta
źródło
Czy macie jakieś naukowe odniesienia do tego, jak idealnie wybrać wagi dla funkcji straty? Nie dlatego, że ci nie wierzę, ale myślałem, że bardzo cię zainspirował ktoś inny?
Gerhard Hagerer
I jak już pytał davidparks21, wyniki twojego podejścia byłyby bardzo interesujące :).
Gerhard Hagerer

Odpowiedzi:

4

To wydaje się dobrym rozwiązaniem dla funkcji straty. Miałem ostatnio sukces z podobnym podejściem, ale myślę, że chcesz zmienić kolejność w miejscu, w którym się pomnażasz class_weight.

Myśląc logicznie, class_weightbędzie to ciągła wartość wyjściowa, więc będzie przenoszona i stosowana do gradientu w ten sam sposób, w jaki jest stosowana do funkcji kosztu. Jest jednak jeden problem.

Twój sposób class_weightwpłynie na wartość prognozy. Ale chcesz, aby wpłynęło to na skalę gradientu. Jeśli się nie mylę, myślę, że chcesz odwrócić kolejność operacji:

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

Byłbym bardzo zainteresowany, aby dowiedzieć się, jak to działa w porównaniu do zwykłego nadpróbkowania niedostatecznie reprezentowanej klasy, co jest bardziej typowe. Więc jeśli zdobędziesz trochę wglądu, opublikuj post na ten temat! :)

Co ciekawe niedawno z powodzeniem zastosowałem bardzo podobną technikę w innej dziedzinie problemowej (co doprowadziło mnie do tego postu):

Uczenie się wielozadaniowe, znajdowanie funkcji straty, która „ignoruje” niektóre próbki

davidparks21
źródło
2

Zamówienie tf.nn.weighted_cross_entropy_with_logits():

Oblicza ważoną entropię krzyżową.

Jest to podobne do sigmoid_cross_entropy_with_logits (), z tą różnicą, że pos_weight pozwala na kompromis przywołania i precyzji poprzez zwiększenie lub zmniejszenie kosztu błędu dodatniego względem błędu ujemnego.

To powinno pozwolić ci robić, co chcesz.

marcos pozzi
źródło
0

Mam 2 różne implementacje:

  1. z „zwykłym” softmaxem z logami: tf.nn.softmax_cross_entropy_w_logits

Tam, gdzie klasa_waga jest symbolem zastępczym, wypełniam każdą iterację każdej partii.

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

Tam, gdzie używam zaimplementowanej funkcji tensorflow, ale muszę obliczyć wagi dla partii. Dokumenty są nieco zagmatwane. Są dwa sposoby, aby to zrobić za pomocą tf.gather lub w ten sposób:

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)

tutaj jest miła dyskusja na ten temat

I w końcu, ponieważ nie chciałem żenić się z żadną z implemetnacji na stałe, dodałem trochę tf.case i przekazuję czas szkolenia na strategię, której chcę użyć.

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)
AI4U.ai
źródło