使用神经网络的 MNIST 数据集精度太低

数据挖掘 神经网络 喀拉斯 极简主义
2021-10-13 00:21:47

我从深度学习开始。这是一个简单的神经网络的实现,在 MNIST 数据集上只有一个隐藏层。为什么损失在任何时期都没有改变?这显然意味着它根本没有学习。准确度约为。11% 这就像随机猜测。但是应该这么少吗?
我使用了 Adam 优化器和 cross_entropy 损失。

input_nodes = 784
hl1_nodes = 64
output_nodes = 1

from keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()

X_train_reshaped = X_train.reshape(X_train.shape[0],784)

model = Sequential()
model.add(Dense(hl1_nodes, activation='relu', input_shape=(input_nodes,)))
model.add(Dense(output_nodes, activation = 'sigmoid'))

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

history = model.fit(x=X_train_reshaped, y=y_train, validation_split=0.33, verbose=1,epochs=10)

#output
Train on 40199 samples, validate on 19801 samples
Epoch 1/10
40199/40199 [==============================] - 4s 87us/step - loss: -55.0254 - acc: 0.1142 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 2/10
40199/40199 [==============================] - 3s 76us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 3/10
40199/40199 [==============================] - 3s 74us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 4/10
40199/40199 [==============================] - 3s 75us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 5/10
40199/40199 [==============================] - 3s 75us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 6/10
40199/40199 [==============================] - 3s 75us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 7/10
40199/40199 [==============================] - 3s 75us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 8/10
40199/40199 [==============================] - 3s 75us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 9/10
40199/40199 [==============================] - 3s 75us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088
Epoch 10/10
40199/40199 [==============================] - 3s 75us/step - loss: -55.0284 - acc: 0.1141 - val_loss: -55.1361 - val_acc: 0.1088

我错过了什么?编辑:即使在第 90 个纪元之后,第 4 位也是相同的。

4个回答

我错过了什么?

  • 分类任务的架构不正确。您有一个使用 训练的二进制输出,binary_crossentropy因此 NN 只能将某物分类为一类(标签 1)或非类(标签 0)。相反,您很可能希望使用softmax激活而不是sigmoidcategorical_crossentropy作为损失的 10 个输出,以便您可以分类最有可能给定输入的数字

  • MNIST 原始数据处理不完整。输入像素值X_train范围从 0 到 255,这将导致 NN 出现数值问题。中的目标标签y_train是数字值(0,1,2,3,4,5,6,7,8,9),而对于分类,您需要将其转换为二进制类 - 通常是一次性编码,例如标签 3 变成了一个向量[0,0,0,1,0,0,0,0,0,0]

    • 扩展输入 - 一个快速修复可能是X_train = X_train/ 255并且X_test = X_test/ 255
    • 一键对标签进行编码。快速修复可能是y_train = keras.utils.to_categorical(y_train)

我对您的代码进行了这些更改,并在 10 个时期后得到了这个:

val_loss: 0.1194 - val_acc: 0.9678

您可以使用一千种技巧来提高 MNIST 的准确性。我感谢 Yassine Ghouzam Kaggle Kernel 的大部分想法:

  1. 规范化数据。这允许优化运行得更快一些。
  2. 在 keras 中使用 Conv2D 层,每隔一段时间使用 MaxPool2D。Ghouzam 内核使用了 Conv2D、Conv2D、MaxPool、Dropout、Conv2D、Conv2D、MaxPool2D、Dropout、Flatten、Dense、Dropout,最后是 Dense。所有激活函数(如果适用)都是 relu,除了输出层是 softmax。
  3. 获得高精度的另一个关键是数据生成。这在 MNIST 上特别有效,因为它很容易稍微调整图像而不会无意中更改标签。您可以使用 keras 的 ImageDataGenerator 来执行此操作。

我将 Ghouzam 内核运行了 60 个 epoch,这在我功率不足的硬件上花了很长时间,但我得到了 99.6% 我提交给 Kaggle 比赛时的准确性。

您使用了一种非常简单的方法来预测MNIST数据集。

问题似乎出在使用“sigmoid”激活函数的最终输出节点上。

Sigmoid激活函数预测 0 到 1 之间的值,并且是用于预测 0 到 9 范围内数字的激活函数的错误选择(要验证这一点,请尝试将正确的预测附加到列表中并打印出来。)。

您可以使用的一种方法是对标签进行一次热编码,然后将标签提供给网络。这肯定会解决你的问题。

完成此操作后,您可以尝试多种方法来提高模型的准确性。

  • 使用简单的特征提取算法,例如HOG
  • 使用卷积网络。你可以在这里了解它
  • 应用数据增强。参考这里
  • 建立更深层次的模型。
  • 使用各种网络架构。
  • 使用迁移学习。...

可能有大量已经尝试和测试过的解决方案。只需自己尝试不同的方法,阅读不同的博客并了解其他人的相同方法,您的模型肯定会有所改进。

我觉得你这里的架构太天真了。但是,我能够使用良好的 CNN 架构重现同样的低准确度,即我的模型使用softmax而不是sigmoid用于 MNIST 数据集。

model = models.Sequential()
model.add(layers.Conv2D(32, (3,3), activation='relu', input_shape= (28,28,1)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64, (3,3), activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64, (3,3), activation='relu'))

#Flaten the 3D conv-net to 1D for the Dense layers
model.add(layers.Flatten())

model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))`

即便如此,我的准确率也很低。但是,我的低准确率区域不是 CNN 的架构。而是 X 的形状,即输入数组。在您的情况下,X_train 和 X_test 的形状。

X_train = X_train.reshape(-1,28,28,1)
X_train = X_train.reshape(-1,28,28,1)

之后,重塑火车和测试阵列。我的准确率达到了 99+。请尝试重塑您的输入数组以及更好的架构。