我在TensorFlow中编写了以下有问题的二元分类程序。无论输入是什么,成本始终返回零。我正在调试一个更大的程序,该程序无法从数据中学习。我已经将至少一个错误缩小到成本函数始终返回零。给定的程序使用了一些随机输入,并且存在相同的问题。self.X_train
和 self.y_train
原本应该从文件中读取,函数 self.predict()
包含更多层,形成一个前馈神经网络。
import numpy as npimport tensorflow as tfclass 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()
如果有人能帮我找出这里的问题,我可以尝试在我的原始程序中进行相同的更改。非常感谢!
回答:
唯一的问题是使用了无效的成本函数。如果您有超过两个类别,应该使用 softmax_cross_entropy_with_logits
,因为单一输出的softmax总是返回1,因为它被定义为:
softmax(x)_i = exp(x_i) / SUM_j exp(x_j)
因此,对于单个数字(一维输出)
softmax(x) = exp(x) / exp(x) = 1
此外,对于softmax输出,TensorFlow期望标签是一热编码,因此如果您只提供0或1,有两种可能性:
- 真实标签为0,因此成本为
-0*log(1) = 0
- 真实标签为1,因此成本为
-1*log(1) = 0
TensorFlow有一个单独的函数来处理二元分类,它应用sigmoid(请注意,对于多个输出,相同的函数将在每个维度上独立应用sigmoid,这是多标签分类所期望的):
tf.sigmoid_cross_entropy_with_logits
只需切换到这个成本函数,您就可以继续了,您也不需要再进行一热编码,因为这个函数是专门为您的用例设计的。
唯一缺少的部分是…您的代码没有实际的训练例程,您需要定义优化器,要求它最小化损失,然后在循环中运行训练操作。在您当前的设置中,您只是反复尝试预测,而网络永远不会改变。
特别是,请参考Stack Overflow上的Cross Entropy Jungle问题,它提供了对TF(和其他库)中所有这些不同辅助函数的更详细描述,这些函数有不同的要求/用例。