La función de costo siempre devuelve cero para una clasificación binaria en tensorflow

He escrito el siguiente progtwig de clasificación binaria en tensorflow que tiene errores. El costo vuelve a ser cero todo el tiempo, sin importar cuál sea la entrada. Estoy tratando de depurar un progtwig más grande que no está aprendiendo nada de los datos. He reducido al menos un error a la función de costo que siempre devuelve cero. El progtwig dado está usando algunas entradas aleatorias y tiene el mismo problema. self.X_train y self.y_train originalmente se supone que lee de los archivos y la función self.predict() tiene más capas que forman una neural network de avance.

 import numpy as np import tensorflow as tf class annClassifier(): def __init__(self): with tf.variable_scope("Input"): self.X = tf.placeholder(tf.float32, shape=(100, 11)) with tf.variable_scope("Output"): self.y = tf.placeholder(tf.float32, shape=(100, 1)) self.X_train = np.random.rand(100, 11) self.y_train = np.random.randint(0,2, size=(100, 1)) def predict(self): with tf.variable_scope('OutputLayer'): weights = tf.get_variable(name='weights', shape=[11, 1], initializer=tf.contrib.layers.xavier_initializer()) bases = tf.get_variable(name='bases', shape=[1], initializer=tf.zeros_initializer()) final_output = tf.matmul(self.X, weights) + bases return final_output def train(self): prediction = self.predict() cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=prediction, labels=self.y)) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run(cost, feed_dict={self.X:self.X_train, self.y:self.y_train})) with tf.Graph().as_default(): classifier = annClassifier() classifier.train() 

Si alguien pudiera averiguar qué estoy haciendo mal en esto, puedo intentar hacer el mismo cambio en mi progtwig original. ¡Muchas gracias!

El único problema es el costo inválido utilizado. softmax_cross_entropy_with_logits debe usarse si tiene más de dos clases, ya que softmax de una sola salida siempre devuelve 1, ya que se define como:

 softmax(x)_i = exp(x_i) / SUM_j exp(x_j) 

así que para un solo número (salida unidimensional)

 softmax(x) = exp(x) / exp(x) = 1 

Además, para la salida de softmax, TF espera tags codificadas de una sola vez, por lo que si proporciona solo 0 o 1, hay dos posibilidades:

  1. La etiqueta verdadera es 0, por lo que el costo es -0*log(1) = 0
  2. La etiqueta verdadera es 1, por lo que el costo es -1*log(1) = 0

Tensorflow tiene una función separada para manejar la clasificación binaria que aplica sigmoid en su lugar (tenga en cuenta que la misma función para más de una salida aplicaría sigmoid independientemente en cada dimensión, que es lo que esperaría la clasificación de tags múltiples):

 tf.sigmoid_cross_entropy_with_logits 

simplemente cambie a este costo y ya está listo para ir, ya no tiene que codificar nada como uno solo, ya que esta función está diseñada únicamente para su uso.

Lo único que falta es que … su código no tiene una rutina de entrenamiento real, necesita definir optimizador, pedirle que minimice una pérdida y luego ejecutar una operación de tren en el circuito. En su configuración actual, solo intente predecir una y otra vez, con la red que nunca cambia.

En particular, consulte la pregunta de Cross Entropy Jungle en SO que proporciona una descripción más detallada de todas estas diferentes funciones de ayuda en TF (y otras bibliotecas), que tienen diferentes requisitos / casos de uso.

El softmax_cross_entropy_with_logits es básicamente una implementación estable de las 2 partes:

 softmax = tf.nn.softmax(prediction) cost = -tf.reduce_mean(labels * tf.log(softmax), 1) 

Ahora, en su ejemplo, la predicción es un valor único, por lo que cuando aplica softmax en ella, siempre será 1 independientemente del valor (exp(prediction)/exp(prediction) = 1) , y por lo tanto el tf.log(softmax) término se convierte en 0. Es por eso que siempre obtiene su costo cero.

Aplique sigmoid para obtener sus probabilidades entre 0 o 1 o si utiliza usar softmax obtenga las tags como [1, 0] para la clase 0 y [0, 1] para la clase 1.