Tensorflow Regolazione della funzione di costo per dati sbilanciati


12

Ho un problema di classificazione con dati altamente squilibrati. Ho letto che il sovracampionamento, il sottocampionamento e la modifica dei costi per risultati categorici sottorappresentati porteranno a un adattamento migliore. Prima che ciò avvenisse, Tensorflow avrebbe classificato ogni input come gruppo di maggioranza (e avrebbe ottenuto una precisione superiore al 90%, per quanto insignificante).

Ho notato che il registro della percentuale inversa di ciascun gruppo ha creato il miglior moltiplicatore che ho provato. Esiste una manipolazione più standard per la funzione di costo? Questo è implementato correttamente?

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)

Ragazzi, avete qualche riferimento scientifico su come scegliere idealmente i pesi per la funzione di perdita? Non che non ti creda, ma pensavo che fossi molto ispirato da qualcun altro?
Gerhard Hagerer,

E come già chiesto da DavidParks21, i risultati del tuo approccio sarebbero molto interessanti :).
Gerhard Hagerer,

Risposte:


4

Questa sembra una buona soluzione per la funzione di perdita. Di recente ho avuto successo con un approccio simile, ma penso che vorresti riordinare dove ti moltiplichi in class_weight.

Pensandoci logicamente, il risultato class_weightsarà una costante rispetto all'output, quindi verrà portato avanti e applicato al gradiente nello stesso modo in cui viene applicato alla funzione di costo. C'è un problema però.

Il modo in cui lo hai, class_weightinfluenzerebbe il valore di previsione. Ma vuoi che influisca sulla scala del gradiente. Se non sbaglio penso che vorresti invertire l'ordine delle operazioni:

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

Sarei molto interessato a sapere come si comporta rispetto al semplice sovracampionamento della classe sottorappresentata, che è più tipica. Quindi, se ottieni alcune informazioni, puoi pubblicare un post al riguardo! :)

È interessante notare che ho usato con successo una tecnica molto simile in un diverso dominio di problemi di recente (che mi ha portato a questo post):

Apprendimento multi-task, trovando una funzione di perdita che "ignora" alcuni campioni


2

Cassa tf.nn.weighted_cross_entropy_with_logits():

Calcola un'entropia crociata ponderata.

Questo è come sigmoid_cross_entropy_with_logits () tranne che pos_weight, consente di compensare il richiamo e la precisione aumentando o diminuendo la ponderazione del costo di un errore positivo rispetto a un errore negativo.

Questo dovrebbe farti fare quello che vuoi.


0

Ho 2 implementazioni diverse:

  1. con softmax "normale" con logit: tf.nn.softmax_cross_entropy_with_logits

Se class_weight è un segnaposto, compilo ogni volta l'iterazione batch.

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

Dove utilizzo la funzione tensorflow implementata ma devo calcolare i pesi per il batch. I documenti sono un po 'confusi al riguardo. Ci sono 2 modi per farlo con tf.gather o in questo modo:

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)

qui c'è una bella discussione a riguardo

E infine, poiché non volevo sposarmi con nessuna delle implementazioni perennemente, ho aggiunto un po 'di caso e passo il tempo di allenamento con la strategia che voglio usare.

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.