22

I dati di testo sono organizzati come vettore con 20.000 elementi, come [2, 1, 0, 0, 5, ...., 0]. l'elemento i-esimo indica la frequenza dell'i-esima parola in un testo.Classificazione testo multilabel utilizzando TensorFlow

I dati dell'etichetta di verità del terreno sono rappresentati anche come vettore con 4.000 elementi, come [0, 0, 1, 0, 1, ...., 0]. l'elemento i-esimo indica se l'etichetta i-esima è un'etichetta positiva per un testo. Il numero di etichette per un testo varia a seconda del testo.

Ho un codice per la classificazione del testo con etichetta singola.

Come posso modificare il seguente codice per la classificazione del testo multilabel?

Soprattutto, vorrei sapere i seguenti punti.

  • Come calcolare la precisione utilizzando TensorFlow.
  • Come impostare una soglia che giudica se un'etichetta è positiva o negativa. Ad esempio, se l'output è [0,80, 0,43, 0,21, 0,01, 0,32] e la verità di fondo è [1, 1, 0, 0, 1], le etichette con punteggi superiori a 0,25 dovrebbero essere giudicate positive.

Grazie.

import tensorflow as tf 

# hidden Layer 
class HiddenLayer(object): 
    def __init__(self, input, n_in, n_out): 
     self.input = input 

     w_h = tf.Variable(tf.random_normal([n_in, n_out],mean = 0.0,stddev = 0.05)) 
     b_h = tf.Variable(tf.zeros([n_out])) 

     self.w = w_h 
     self.b = b_h 
     self.params = [self.w, self.b] 

    def output(self): 
     linarg = tf.matmul(self.input, self.w) + self.b 
     self.output = tf.nn.relu(linarg) 

     return self.output 

# output Layer 
class OutputLayer(object): 
    def __init__(self, input, n_in, n_out): 
     self.input = input 

     w_o = tf.Variable(tf.random_normal([n_in, n_out], mean = 0.0, stddev = 0.05)) 
     b_o = tf.Variable(tf.zeros([n_out])) 

     self.w = w_o 
     self.b = b_o 
     self.params = [self.w, self.b] 

    def output(self): 
     linarg = tf.matmul(self.input, self.w) + self.b 
     self.output = tf.nn.relu(linarg) 

     return self.output 

# model 
def model(): 
    h_layer = HiddenLayer(input = x, n_in = 20000, n_out = 1000) 
    o_layer = OutputLayer(input = h_layer.output(), n_in = 1000, n_out = 4000) 

    # loss function 
    out = o_layer.output() 
    cross_entropy = -tf.reduce_sum(y_*tf.log(out + 1e-9), name='xentropy')  

    # regularization 
    l2 = (tf.nn.l2_loss(h_layer.w) + tf.nn.l2_loss(o_layer.w)) 
    lambda_2 = 0.01 

    # compute loss 
    loss = cross_entropy + lambda_2 * l2 

    # compute accuracy for single label classification task 
    correct_pred = tf.equal(tf.argmax(out, 1), tf.argmax(y, 1)) 
    accuracy = tf.reduce_mean(tf.cast(correct_pred, "float")) 

    return loss, accuracy 
+0

Penso che ci potrebbe essere una funzione di perdita meglio usare oltre cross-entropia. – Aaron

+0

Esistono diverse misure di accuratezza per un problema di classificazione multilabel: precisione di un errore, perdita di posizione, precisione media media, ecc.Sto ancora imparando TensorFlow e non sono ancora riuscito a implementare correttamente nessuno di essi. Ma forse questo articolo ti aiuterà: http://arxiv.org/pdf/1312.5419v3.pdf Fammi sapere se fai progressi! –

+0

Per una migliore idea di precisione, considerare il calcolo della precisione e del richiamo. –

risposta

8

Cambia relu to sigmoid of output layer. Modificare la perdita di entropia croce per esplicita formula matematica di sigma perdita di entropia incrociata (perdita esplicito stava lavorando nel mio caso/versione di tensorflow)

import tensorflow as tf 

# hidden Layer 
class HiddenLayer(object): 
    def __init__(self, input, n_in, n_out): 
     self.input = input 

     w_h = tf.Variable(tf.random_normal([n_in, n_out],mean = 0.0,stddev = 0.05)) 
     b_h = tf.Variable(tf.zeros([n_out])) 

     self.w = w_h 
     self.b = b_h 
     self.params = [self.w, self.b] 

    def output(self): 
     linarg = tf.matmul(self.input, self.w) + self.b 
     self.output = tf.nn.relu(linarg) 

     return self.output 

# output Layer 
class OutputLayer(object): 
    def __init__(self, input, n_in, n_out): 
     self.input = input 

     w_o = tf.Variable(tf.random_normal([n_in, n_out], mean = 0.0, stddev = 0.05)) 
     b_o = tf.Variable(tf.zeros([n_out])) 

     self.w = w_o 
     self.b = b_o 
     self.params = [self.w, self.b] 

    def output(self): 
     linarg = tf.matmul(self.input, self.w) + self.b 
     #changed relu to sigmoid 
     self.output = tf.nn.sigmoid(linarg) 

     return self.output 

# model 
def model(): 
    h_layer = HiddenLayer(input = x, n_in = 20000, n_out = 1000) 
    o_layer = OutputLayer(input = h_layer.output(), n_in = 1000, n_out = 4000) 

    # loss function 
    out = o_layer.output() 
    # modified cross entropy to explicit mathematical formula of sigmoid cross entropy loss 
    cross_entropy = -tf.reduce_sum(( (y_*tf.log(out + 1e-9)) + ((1-y_) * tf.log(1 - out + 1e-9))) , name='xentropy')  

    # regularization 
    l2 = (tf.nn.l2_loss(h_layer.w) + tf.nn.l2_loss(o_layer.w)) 
    lambda_2 = 0.01 

    # compute loss 
    loss = cross_entropy + lambda_2 * l2 

    # compute accuracy for single label classification task 
    correct_pred = tf.equal(tf.argmax(out, 1), tf.argmax(y, 1)) 
    accuracy = tf.reduce_mean(tf.cast(correct_pred, "float")) 

    return loss, accuracy 
11

È necessario utilizzare le variazioni della funzione di entropia incrociata in altri per supportare la classificazione multilabel. Nel caso in cui si disponga di meno di un migliaio di output, è necessario utilizzare sigmoid_cross_entropy_with_logits, nel caso in cui si abbiano 4000 output, è possibile considerare candidate sampling in quanto è più veloce del precedente.

Come calcolare la precisione utilizzando TensorFlow.

Questo dipende dal problema e da ciò che si desidera ottenere. Se non vuoi perdere nessun oggetto in un'immagine, se il classificatore va bene tranne uno, dovresti considerare l'intera immagine come un errore. Puoi anche considerare che un oggetto mancato o missclassiffied è un errore. Quest'ultimo penso che sia supportato da sigmoid_cross_entropy_with_logits.

Come impostare una soglia che giudica se un'etichetta è positiva o negativa. Ad esempio, se l'output è [0,80, 0,43, 0,21, 0,01, 0,32] e la verità di base è [1, 1, 0, 0, 1], le etichette con punteggi superiori a 0,25 devono essere giudicate positive.

La soglia è un modo per andare, devi decidere quale. Ma questa è una specie di hack, non una reale classificazione multilivello. Per questo è necessario le funzioni precedenti che ho detto prima.

+1

Non so perché la gente suggerisca 'sigmoid_cross_entropy_with_logits'. Se è quello che suggerisce il nome, io-e * ln (sigmoid (logits)). Quindi ridurrà al minimo la perdita dando alta probabilità ad ogni classe e infatti lo stava dando nel mio caso. –

+0

questa funzione non restituisce una probabilità. E non vedo come minimizzerà la perdita dando un alto valore. Se si imposta 1 sulle classi e 0 quando la classe non è presente, la rete fornisce valori vicini a 0 quando l'oggetto non è nell'immagine e valori vicini a 1 o più grandi (anche 2 o 3) se l'oggetto è in l'immagine. Lo sto usando e funziona piuttosto bene. – jorgemf

+0

Minimizzerà la perdita dando un valore elevato a ogni classe perché non c'è penalità (o perdita 0) per dare un valore elevato alle classi che sono etichettate 0. Quindi è necessario modificare la perdita di entropia incrociata con l'entropia incrociata binaria (y * ln (sigmoid (logits)) + 1-y * ln (sigmoid (1-logits))). sigmoid_cross_entropy_with_logits non implementa internamente l'entropia incrociata binaria. Sono sorpreso perché sta lavorando nel tuo caso, stai usando theano ecc. –