【问题标题】:tf.keras predictions are bad while evaluation is goodtf.keras 预测很差,而评估很好
【发布时间】:2019-08-22 01:56:27
【问题描述】:

我在 tf.keras 中编写模型,在训练集上运行 model.evaluate() 通常会产生约 96% 的准确率。我对测试集的评价通常很接近,大约 93%。但是,当我手动预测时,模型通常是不准确的。这是我的代码:

import tensorflow as tf
from tensorflow.keras import layers
import numpy as np
import pandas as pd

!git clone https://github.com/DanorRon/data
%cd data
!ls

batch_size = 100
epochs = 15
alpha = 0.001
lambda_ = 0.001
h1 = 50

train = pd.read_csv('/content/data/mnist_train.csv.zip')
test = pd.read_csv('/content/data/mnist_test.csv.zip')

train = train.loc['1':'5000', :]
test = test.loc['1':'2000', :]

train = train.sample(frac=1).reset_index(drop=True)
test = test.sample(frac=1).reset_index(drop=True)

x_train = train.loc[:, '1x1':'28x28']
y_train = train.loc[:, 'label']

x_test = test.loc[:, '1x1':'28x28']
y_test = test.loc[:, 'label']

x_train = x_train.values
y_train = y_train.values

x_test = x_test.values
y_test = y_test.values

nb_classes = 10
targets = y_train.reshape(-1)
y_train_onehot = np.eye(nb_classes)[targets]

nb_classes = 10
targets = y_test.reshape(-1)
y_test_onehot = np.eye(nb_classes)[targets]

model = tf.keras.Sequential()
model.add(layers.Dense(784, input_shape=(784,), kernel_initializer='random_uniform', bias_initializer='zeros'))
model.add(layers.Dense(h1, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(lambda_), kernel_initializer='random_uniform', bias_initializer='zeros'))
model.add(layers.Dense(10, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2(lambda_), kernel_initializer='random_uniform', bias_initializer='zeros'))

model.compile(optimizer='SGD',
             loss = 'mse',
             metrics = ['categorical_accuracy'])

model.fit(x_train, y_train_onehot, epochs=epochs, batch_size=batch_size)

model.evaluate(x_test, y_test_onehot, batch_size=batch_size)

prediction = model.predict_classes(x_test)
print(prediction)

print(y_test[1:])

我听说很多时候人们遇到这个问题,这只是数据输入的问题。但我在这里看不出有什么问题,因为它几乎总是错误地预测(如果它是随机的,就和你预期的一样多)。我该如何解决这个问题?

编辑:以下是具体结果:

最后的训练步骤:

Epoch 15/15
49999/49999 [==============================] - 3s 70us/sample - loss: 0.0309 - categorical_accuracy: 0.9615

评估输出:

2000/2000 [==============================] - 0s 54us/sample - loss: 0.0352 - categorical_accuracy: 0.9310
[0.03524150168523192, 0.931]

model.predict_classes 的输出:

[9 9 0 ... 5 0 5]

打印输出(y_test):

[9 0 0 7 6 8 5 1 3 2 4 1 4 5 8 4 9 2 4]

【问题讨论】:

  • 为什么在代码中使用print(y_test[1:]) 而不是print(y_test)?会不会是您的真实标签刚刚从第二个标签开始,所以您正在与错误的预测进行比较?

标签: python machine-learning neural-network mnist tf.keras


【解决方案1】:

首先,您的损失函数是错误的:您处于多类分类设置中,并且您使用的是适合回归而非分类 (MSE) 的损失函数。

将我们的模型编译改为:

model.compile(loss='categorical_crossentropy',
              optimizer='SGD',
              metrics=['accuracy'])

请参阅 Keras MNIST MLP example 以获取更多详细信息,并在 What function defines accuracy in Keras when the loss is mean squared error (MSE)? 中提供自己的答案以获取更多详细信息(尽管在这里您实际上遇到了逆问题,即分类设置中的回归损失)。

此外,尚不清楚您使用的 MNIST 变体是否已经标准化;如果没有,你应该自己规范化它们:

x_train = x_train.values/255
x_test = x_test.values/255

也不清楚你为什么要一个 784 单元的层,因为这实际上是你的 NN 的 第二 层(第一层由 input_shape 参数隐式设置 - 见 @ 987654323@),它当然不需要为您的 784 个输入特征中的每一个包含一个单元。

更新(在 cmets 之后):

但是为什么 MSE 对分类没有意义呢?

这是一个理论问题,并不完全适合 SO;粗略地说,这与我们不使用线性回归进行分类的原因相同 - 我们使用 logistic 回归,这两种方法之间的实际差异正是损失函数。 Andrew Ng 在 Coursera 的热门机器学习课程中很好地解释了这一点 - 请参阅他在 Youtube 上的 Lecture 6.1 - Logistic Regression | Classification(解释从 ~ 3:00 开始),以及 4.2 为什么不是线性回归 [用于分类] 部分? 来自 Hastie、Tibshirani 和同事的(强烈推荐且免费提供)教科书An Introduction to Statistical Learning

MSE 确实提供了很高的准确度,那为什么不重要呢?

如今,几乎任何你扔给 MNIST 的东西都会“工作”,当然这既不能使它正确,也不能成为要求更高的数据集的好方法......

更新 2

每当我使用交叉熵运行时,准确度都会在 ~10% 左右波动

抱歉,无法重现该行为...将Keras MNIST MLP example 与您的模型的简化版本一起使用,即:

model = Sequential()
model.add(Dense(784, activation='linear', input_shape=(784,)))
model.add(Dense(50, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer=SGD(),
              metrics=['accuracy'])

仅在 5 个 epoch 之后,我们很容易就获得了 ~ 92% 的 验证 准确度:

history = model.fit(x_train, y_train,
                    batch_size=128,
                    epochs=5,
                    verbose=1,
                    validation_data=(x_test, y_test))

Train on 60000 samples, validate on 10000 samples
Epoch 1/10
60000/60000 [==============================] - 4s - loss: 0.8974 - acc: 0.7801 - val_loss: 0.4650 - val_acc: 0.8823
Epoch 2/10
60000/60000 [==============================] - 4s - loss: 0.4236 - acc: 0.8868 - val_loss: 0.3582 - val_acc: 0.9034
Epoch 3/10
60000/60000 [==============================] - 4s - loss: 0.3572 - acc: 0.9009 - val_loss: 0.3228 - val_acc: 0.9099
Epoch 4/10
60000/60000 [==============================] - 4s - loss: 0.3263 - acc: 0.9082 - val_loss: 0.3024 - val_acc: 0.9156
Epoch 5/10
60000/60000 [==============================] - 4s - loss: 0.3061 - acc: 0.9132 - val_loss: 0.2845 - val_acc: 0.9196

注意第一个 Dense 层的 activation='linear',它相当于 not specifying anything,就像你的情况一样(正如我所说,你扔给 MNIST 的几乎所有东西都会“工作”)......

最终建议:尝试将模型修改为:

model = tf.keras.Sequential()
model.add(layers.Dense(784, activation = 'relu',input_shape=(784,)))
model.add(layers.Dense(h1, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

为了使用更好的(和default'glorot_uniform' 初始化器,并删除kernel_regularizer 参数(它们可能是任何问题的原因 - 总是从简单开始!)。 ..

【讨论】:

  • 我之所以将MSE作为我的损失函数是因为当我使用交叉熵时,发生了很多奇怪的事情。我有另一篇关于该信息的帖子,但我没有得到任何有效的答案。这是帖子的链接:stackoverflow.com/questions/55328966/tf-keras-loss-becomes-nan
  • @RonanVenkat MSE 对于此类分类问题毫无意义,这真的是不可协商的
  • @RonanVenkat 请先尝试使用内置的 MNIST 数据重现 Keras MNIST 示例!天知道你使用的晦涩的 MNIST 变体是否已经规范化(你没有规范化它们)......!
  • 我检查过,数据没有自动标准化,你知道的。
  • 我知道我无法比较损失,但我可以比较准确性,这就是我正在做的。问题是手动预测是关闭的,但评估具有很高的准确性。 MSE对测试集的评价非常好,但是crossentropy评价很差,不比随机猜测好。
猜你喜欢
  • 2013-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
  • 2019-10-05
  • 1970-01-01
  • 2019-05-31
  • 1970-01-01
相关资源
最近更新 更多