2016-02-08 16 views
14

Sto cercando di adattare this MNIST example alla classificazione binaria.TensorFlow per la classificazione binaria

Ma quando si modifica il mio NLABELS da NLABELS=2 a NLABELS=1, la funzione di perdita restituisce sempre 0 (e precisione 1).

from __future__ import absolute_import 
from __future__ import division 
from __future__ import print_function 

from tensorflow.examples.tutorials.mnist import input_data 
import tensorflow as tf 

# Import data 
mnist = input_data.read_data_sets('data', one_hot=True) 
NLABELS = 2 

sess = tf.InteractiveSession() 

# Create the model 
x = tf.placeholder(tf.float32, [None, 784], name='x-input') 
W = tf.Variable(tf.zeros([784, NLABELS]), name='weights') 
b = tf.Variable(tf.zeros([NLABELS], name='bias')) 

y = tf.nn.softmax(tf.matmul(x, W) + b) 

# Add summary ops to collect data 
_ = tf.histogram_summary('weights', W) 
_ = tf.histogram_summary('biases', b) 
_ = tf.histogram_summary('y', y) 

# Define loss and optimizer 
y_ = tf.placeholder(tf.float32, [None, NLABELS], name='y-input') 

# More name scopes will clean up the graph representation 
with tf.name_scope('cross_entropy'): 
    cross_entropy = -tf.reduce_mean(y_ * tf.log(y)) 
    _ = tf.scalar_summary('cross entropy', cross_entropy) 
with tf.name_scope('train'): 
    train_step = tf.train.GradientDescentOptimizer(10.).minimize(cross_entropy) 

with tf.name_scope('test'): 
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 
    _ = tf.scalar_summary('accuracy', accuracy) 

# Merge all the summaries and write them out to /tmp/mnist_logs 
merged = tf.merge_all_summaries() 
writer = tf.train.SummaryWriter('logs', sess.graph_def) 
tf.initialize_all_variables().run() 

# Train the model, and feed in test data and record summaries every 10 steps 

for i in range(1000): 
    if i % 10 == 0: # Record summary data and the accuracy 
     labels = mnist.test.labels[:, 0:NLABELS] 
     feed = {x: mnist.test.images, y_: labels} 

     result = sess.run([merged, accuracy, cross_entropy], feed_dict=feed) 
     summary_str = result[0] 
     acc = result[1] 
     loss = result[2] 
     writer.add_summary(summary_str, i) 
     print('Accuracy at step %s: %s - loss: %f' % (i, acc, loss)) 
    else: 
     batch_xs, batch_ys = mnist.train.next_batch(100) 
     batch_ys = batch_ys[:, 0:NLABELS] 
     feed = {x: batch_xs, y_: batch_ys} 
    sess.run(train_step, feed_dict=feed) 

Ho controllato le dimensioni di entrambi batch_ys (alimentato in y) e _y e sono entrambe matrici 1XN quando NLABELS=1 quindi il problema sembra essere anteriore a quella. Forse qualcosa a che fare con la moltiplicazione della matrice?

In realtà ho avuto lo stesso problema in un progetto reale, quindi qualsiasi aiuto sarebbe apprezzato ... Grazie!

+0

Sto provando la tua rete e sembra che non funzioni, hai trovato una possibile soluzione? –

risposta

33

L'esempio MNIST originale utilizza un one-hot encoding per rappresentare le etichette nei dati: ciò significa che se ci sono NLABELS = 10 classi (come in MNIST), l'uscita di destinazione è [1 0 0 0 0 0 0 0 0 0] per classe 0, [0 1 0 0 0 0 0 0 0 0] per la classe 1, ecc L'operatore tf.nn.softmax() converte i logits calcolati da tf.matmul(x, W) + b in una distribuzione di probabilità tra le diverse classi di uscita, che viene quindi confrontata con il valore immesso per y_.

Se NLABELS = 1, questa si comporta come se ci fosse una sola classe e la tf.nn.softmax() op sarebbe calcolare una probabilità di 1.0 per quella classe, portando ad un cross-entropia di 0.0, dal momento che tf.log(1.0) è 0.0 per tutti gli esempi .

ci sono (almeno) due approcci si può provare per la classificazione binaria:

  1. La più semplice sarebbe quella di impostare NLABELS = 2 per le due classi possibili e codificare i dati di allenamento come [1 0] per l'etichetta 0 e [0 1] per l'etichetta 1. This answer ha un suggerimento su come farlo.

  2. Si potrebbe mantenere le etichette come interi 0 e 1 e utilizzare tf.nn.sparse_softmax_cross_entropy_with_logits(), come suggerito in this answer.

+0

Oh, vedo il problema ... Ma ora mi chiedo, dovrei usare l'entropia incrociata per un problema di classificazione binaria, allora? Questo tizio che ha implementato una rete neurale a mano non ha usato l'entropia incrociata per il suo problema di classificazione binaria: http://iamtrask.github.io/2015/07/12/basic-python- network/ –

+0

Questo è certamente possibile. Potresti avere una singola unità di output, alimentarla tramite 'tf.nn.sigmoid()' per ottenere un valore compreso tra 0 e 1 e quindi usare 'y - y_' come funzione di perdita. – mrry

+1

TensorFlow non tenta di minimizzare la funzione di perdita? Deve essere uno scalare, giusto? Dovrei fare qualcosa come 'sum (abs (y-y _))'? –