为什么我在 Tensorflow 中的逻辑回归分类器不学习?

Why is my logistic regression classifier in Tensorflow not learning?

我正在通过实施逻辑回归 classifier 来 class 验证二进制 MNIst 数字数据集来学习 Tensorflow。我正在使用 tensorflow 1.13,如下面的代码所示

import tensorflow as tf
gpu_options = tf.GPUOptions(allow_growth=True, per_process_gpu_memory_fraction=0.1)
s = tf.InteractiveSession(config=tf.ConfigProto(gpu_options=gpu_options))
print("We're using TF", tf.__version__)

数据集如下:

from sklearn.datasets import load_digits
mnist = load_digits(2)

X,y = mnist.data, mnist.target

以下数据集具有以下形状

>> print("y [shape - %s]:" % (str(y.shape)), y[:10])
y [shape - (360,)]: [0 1 0 1 0 1 0 0 1 1]

>> print("X [shape - %s]:" % (str(X.shape)))
X [shape - (360, 64)]:

根据这些形状,我为输入定义了占位符,为权重定义了变量(我希望它们是正确的)

weights = tf.Variable(tf.zeros([X.shape[1],1]), name="weights")
input_x = tf.placeholder('float32', shape=[None, X.shape[1]], name="input_x")
input_y = tf.placeholder('float32', shape=[None, 1], name="input_y")

现在我定义损失、优化器并计算 class 概率如下

#predicted_y = <predicted probabilities for input_X>
logits = tf.matmul(input_x, weights)
predicted_y = tf.nn.softmax(logits)
probas=tf.argmax(predicted_y, axis=1)

#loss = <logistic loss (scalar, mean over sample)>
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=input_y))

#optimizer = <optimizer that minimizes loss>
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.0001).minimize(loss)

然后,我创建了一个函数来调用概率 class 的计算

predict_function=lambda vector1: probas.eval({input_x:vector1})

现在,我开始分离训练集和测试集

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y)

最后,我对每次迭代进行训练和测试

from sklearn.metrics import roc_auc_score

y_train_reshaped=np.reshape(y_train, (y_train.shape[0], 1))
s.run(tf.global_variables_initializer())

for i in range(5):

    #<run optimizer operation>
    s.run(optimizer, feed_dict={input_x:X_train,input_y:y_train_reshaped})

    #loss_i = <compute loss at iteration i>
    loss_i = loss.eval({input_x:X_train, input_y:y_train_reshaped})

    print("loss at iter %i:%.4f" % (i, loss_i))

    #My problem starts here
    print("train auc:",roc_auc_score(y_train, predict_function(X_train)))
    print("test auc:",roc_auc_score(y_test, predict_function(X_test)))

我对上述代码的问题是,虽然我可以看到损失在每次迭代中都在减少,但 ROC 指标保持不变。此循环的输出如下:

loss at iter 0:0.6820
train auc: 0.5
test auc: 0.5
loss at iter 1:0.6712
train auc: 0.5
test auc: 0.5
loss at iter 2:0.6606
train auc: 0.5
test auc: 0.5
loss at iter 3:0.6503
train auc: 0.5
test auc: 0.5
loss at iter 4:0.6403
train auc: 0.5
test auc: 0.5

通过打印 predict_function(X_train) 或 predict_function(X_test) 的输出,我看到预测总是 0。因此,有一些东西我可能不理解或做得不正确。我在这里错过了什么?

编辑: 我还尝试按照建议将学习率增加到 0.1 并将迭代次数增加到 50000,损失很快变为零,但是训练和测试 AUC是 0.5,这意味着 classifier 只预测一个 class。我确定我的代码有问题,具体是什么?

这里有两个不同的错误:

predicted_y = tf.nn.softmax(logits)
probas=tf.argmax(predicted_y, axis=1)

首先,由于您的 y 不是单热编码,因此您不应使用 softmax,而应使用 sigmoid(您在 [=18] 中正确执行的操作=] 定义);所以,第一行应该是

predicted_y = tf.nn.sigmoid(logits)

第二行,再次因为你的 y 不是单热编码,所以没有按照你的想法去做:因为你的预测是单元素数组,argmax 是定义 0,因此您无法获得从概率到硬预测的正确转换(在任何情况下,硬预测不用于计算 ROC - 您需要此概率)。

您应该完全放弃 probas,并将您的 prediction_function 更改为:

prediction_function=lambda vector1: predicted_y.eval({input_x:vector1})

这样,对于 learning_rate=0.1,AUC 从第一次迭代开始就达到 1.0:

loss at iter 0:0.0085
train auc: 0.9998902365402557
test auc: 1.0
loss at iter 1:0.0066
train auc: 1.0
test auc: 1.0
loss at iter 2:0.0052
train auc: 1.0
test auc: 1.0
loss at iter 3:0.0042
train auc: 1.0
test auc: 1.0
loss at iter 4:0.0035
train auc: 1.0
test auc: 1.0

你得到 X_train 的正确预测:

np.round(prediction_function(X_train)).reshape(1,-1)
# result:
array([[0., 1., 1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1., 1., 1.,
        1., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 0.,
        1., 1., 0., 1., 1., 0., 0., 0., 0., 1., 1., 0., 0., 1., 0., 0.,
        1., 1., 0., 0., 1., 1., 1., 0., 0., 1., 0., 1., 0., 0., 0., 1.,
        0., 1., 1., 1., 0., 1., 0., 1., 0., 0., 1., 0., 1., 1., 1., 1.,
        0., 0., 1., 1., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 1., 1.,
        0., 1., 1., 0., 1., 1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1.,
        1., 0., 0., 1., 0., 0., 1., 0., 1., 0., 0., 0., 1., 1., 0., 0.,
        0., 0., 0., 1., 0., 1., 1., 1., 1., 1., 0., 0., 0., 1., 1., 1.,
        0., 0., 0., 1., 1., 1., 1., 0., 0., 1., 1., 0., 1., 1., 1., 0.,
        1., 1., 0., 1., 1., 1., 0., 1., 0., 1., 1., 0., 0., 1., 1., 0.,
        1., 1., 1., 1., 0., 0., 1., 1., 0., 0., 0., 0., 1., 1., 0., 0.,
        0., 0., 1., 0., 0., 1., 1., 0., 1., 0., 0., 1., 1., 0., 0., 1.,
        1., 0., 0., 1., 0., 1., 0., 1., 0., 0., 0., 0., 0., 0., 0., 1.,
        1., 0., 1., 1., 1., 0., 0., 0., 0., 1., 0., 0., 1., 0., 0., 0.,
        1., 1., 1., 1., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 1., 1.,
        0., 1., 1., 0., 1., 0., 1., 0., 0., 0., 1., 0., 0., 1.]],
      dtype=float32)