【问题标题】:Cost function always returning zero for a binary classification in tensorflow对于张量流中的二进制分类,成本函数总是返回零
【发布时间】:2018-01-20 23:57:33
【问题描述】:

我在 tensorflow 中编写了以下二进制分类程序,但有问题。无论输入是什么,成本都会一直归零。我正在尝试调试一个更大的程序,该程序没有从数据中学习任何东西。我已经将至少一个错误缩小到成本函数总是返回零。给定的程序正在使用一些随机输入并且存在相同的问题。 self.X_trainself.y_train 原本应该是从文件中读取的,而函数 self.predict() 有更多的层形成一个前馈神经网络。

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

如果有人能找出我在这方面做错了什么,我可以尝试在我的原始程序中进行相同的更改。非常感谢!

【问题讨论】:

    标签: python machine-learning tensorflow neural-network artificial-intelligence


    【解决方案1】:

    唯一的问题是使用了无效的成本。 softmax_cross_entropy_with_logits 如果您有更多两个类,则应使用softmax_cross_entropy_with_logits,因为单个输出的 softmax 始终返回 1,因为它被定义为:

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

    so 对于单个数字(一维输出)

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

    此外,对于 softmax 输出,TF 需要 one-hot 编码标签,因此如果您只提供 0 或 1,则有两种可能性:

    1. 真正的标签是0,所以成本是-0*log(1) = 0
    2. 真正的标签是1,所以成本是-1*log(1) = 0

    Tensorflow 有一个单独的函数来处理二进制分类,它改为应用 sigmoid(请注意,对于多个输出,相同的函数会在每个维度上独立应用 sigmoid,这是多标签分类所期望的):

    tf.sigmoid_cross_entropy_with_logits
    

    只需切换到这个成本,你就可以开始了,你也不必再将任何东西编码为 one-hot,因为这个函数是专门为你的用例设计的。

    唯一缺少的一点是......您的代码没有实际的训练例程,您需要定义优化器,要求它最小化损失,然后在循环中运行训练操作。在您当前的设置中,您只是尝试一遍又一遍地预测,而网络永远不会改变。

    特别是,请参阅Cross Entropy Jungle question on SO,它提供了 TF(和其他库)中所有这些不同帮助函数的更详细描述,它们有不同的要求/用例。

    【讨论】:

    • sigmoid loss 衡量离散分类任务中的概率误差,其中每个类都是独立的,而不是互斥的。这种损失不会对二元分类问题有效。
    • @Ishant,您似乎混淆了术语 - 对于 二元分类,只有两个选项,您是 1 类或 2 类的成员,这就是为什么您可以用 sigmoid 对 一个 概率建模。 P(y=1|x) = sigmoid(f(x)),正如概率 P(y=2|x) = 1 - P(y=1|x) 的定义。这里不存在互斥的问题。但是,如果你有超过 2 个类,那么你是对的,不能应用 sigmoid。这正是(在其他模型中)逻辑回归的推导方式。
    • 危害不大,但不是“无害”——你分配了更多的内存(如果最后一层很小,则无关紧要,否则可能很重要),你在浪费计算(因为没有任何东西可以使学习受益,但我们必须计算额外的梯度),最后对于神经网络来说,这种冗余是否不会影响学习动态还不清楚(因为我们对损失曲面的了解仍然很少)深度网络),因此这是避免不必要的复杂性的更好策略。
    • 谢谢。这不是我要调试的实际程序,我只是想弄清楚为什么成本返回零。在实际版本中,迭代的成本一直保持在零并且没有学到任何东西。我认为最好只发布找到常量的部分,以使其不那么混乱。
    【解决方案2】:

    softmax_cross_entropy_with_logits 基本上是两部分的稳定实现:

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

    现在在您的示例中,预测是单个值,因此当您对其应用 softmax 时,无论 (exp(prediction)/exp(prediction) = 1) 的值如何,它都将始终为 1,因此 tf.log(softmax) 项变为 0。这就是为什么你总是得到零成本。

    要么应用 sigmoid 以获取介于 0 或 1 之间的概率,或者如果你想使用 softmax 获取标签,例如 [1, 0] 用于 0 类,[0, 1] 用于 1 类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-04
      • 2017-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-28
      • 1970-01-01
      相关资源
      最近更新 更多