2016-02-02 26 views
24

Sto tentando di applicare l'apprendimento approfondito per un problema di classificazione binaria con uno squilibrio di alta classe tra classi target (500k, 31K). Voglio scrivere una funzione di perdita personalizzata che dovrebbe essere come: minimizzare (100 - ((predicted_smallerclass)/(total_smallerclass)) * 100)Funzione di perdita per classificatore binario con sbilanciamento di classe nel flusso del tensore

Apprezzare qualsiasi suggerimento su come posso costruire questa logica.

risposta

24

È possibile aggiungere pesi di classe alla funzione di perdita, moltiplicando i log. regolare la perdita di entropia croce è questo:

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

in caso ponderata:

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

Quindi, logit moltiplicano, si sono previsioni di ciascuna classe di ridimensionamento per la sua classe di peso.

Ad esempio:

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

C'è una funzione di perdite standard di adesso che supporta i pesi per partita:

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

Dove pesi devono essere trasformati da pesi di classe ad un peso per esempio (con forma [dimensione del lotto]). Vedi documentation here.

31

Il codice che hai proposto mi sembra sbagliato. La perdita deve essere moltiplicata per il peso, sono d'accordo.

Ma se si moltiplica il logit dai pesi di classe, si finisce con:

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

Il secondo mandato non è uguale a:

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

Per dimostrare questo, possiamo essere riscrivi il secondo come:

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

Quindi ecco il codice I'm p roposing:

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 
+1

Sono di fronte allo stesso problema, ma nel tentativo di comprendere il codice precedente non capisco '\ sum_' - puoi spiegarlo per favore? Sembra essere il codice del lattice; funziona in Python? –

+0

Ma in realtà l'approccio migliore è quello di costruire mini-lotti bilanciati !! –

+1

@Ron: l'equazione dice semplicemente che è diverso da: moltiplicare il logit per il peso della classe e moltiplicare la distanza (cross entropy) per i pesi. Il codice in basso funziona in Python. Ma nel complesso, riesci a bilanciare ogni Minibatch e otterrai un modello migliore! –

8

Uso tf.nn.weighted_cross_entropy_with_logits() e impostare pos_weight a 1/(rapporto atteso positivi).

+0

Sono ancora un principiante nel deep learning quindi scusami se la mia domanda è ingenua. cosa intendi per rapporto atteso di positivi? e qual è la differenza tra questa funzione e 'sigmoid_cross_entropy'? – Maystro

1

Forse ops tf.nn.weighted_cross_entropy_with_logits() per due classi:

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

è possibile controllare le guide su tensorflow https://www.tensorflow.org/api_guides/python/contrib.losses

...

Mentre specificando una perdita scalare ridimensiona la perdita sull'intero lotto, a volte vogliamo ridimensionare la perdita per campione batch. Ad esempio, se abbiamo alcuni esempi che contano di più per ottenere correttamente, potremmo desiderare di avere una perdita maggiore rispetto ad altri campioni i cui errori sono meno importanti. In questo caso, possiamo fornire un vettore di peso di lunghezza batch_size che risulta nella perdita per ciascun campione nel batch che viene ridimensionato dall'elemento di peso corrispondente.Ad esempio, si consideri il caso di un problema di classificazione in cui vogliamo massimizzare la nostra precisione, ma siamo soprattutto interessati ad ottenere un'elevata precisione per una classe specifica:

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

ho dovuto lavorare con un simile insieme di dati sbilanciato di più classi e questo è come ho lavorato attraverso di essa, spero che aiutare qualcuno alla ricerca di una soluzione simile:

questo va dentro il modulo di formazione:

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) 

questo va all'interno del vostro modello di definizione della classe:

#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