CNN 训练准确率在训练期间变得更好,但测试准确率保持在 40% 左右

Posted

技术标签:

【中文标题】CNN 训练准确率在训练期间变得更好,但测试准确率保持在 40% 左右【英文标题】:CNN train accuracy gets better during training, but test accuracy stays around 40% 【发布时间】:2018-07-13 16:12:17 【问题描述】:

所以在过去的几个月里,我通过 Tensorflow 和 Keras 学习了很多关于神经网络的知识,所以我想尝试为 CIFAR10 数据集制作模型(代码如下)。

但是,在训练过程中,准确率变得更好(从 1 个 epoch 后的约 35% 到 5 个 epoch 后的约 60-65%),但 val_acc 保持不变或仅增加一点。以下是打印结果:

Epoch 1/5
50000/50000 [==============================] - 454s 9ms/step - loss: 1.7761 - acc: 0.3584 - val_loss: 8.6776 - val_acc: 0.4489
Epoch 2/5
50000/50000 [==============================] - 452s 9ms/step - loss: 1.3670 - acc: 0.5131 - val_loss: 8.9749 - val_acc: 0.4365
Epoch 3/5
50000/50000 [==============================] - 451s 9ms/step - loss: 1.2089 - acc: 0.5721 - val_loss: 7.7254 - val_acc: 0.5118
Epoch 4/5
50000/50000 [==============================] - 452s 9ms/step - loss: 1.1140 - acc: 0.6080 - val_loss: 7.9587 - val_acc: 0.4997
Epoch 5/5
50000/50000 [==============================] - 452s 9ms/step - loss: 1.0306 - acc: 0.6385 - val_loss: 7.4351 - val_acc: 0.5321
10000/10000 [==============================] - 27s 3ms/step
loss:  7.435152648162842 
accuracy:  0.5321

我在互联网上四处查看,我最好的猜测是我的模型过度拟合,所以我尝试删除一些层,添加更多的 dropout 层并减少过滤器的数量,但没有一个显示出任何增强。

最奇怪的是,前段时间我根据一些教程做了一个非常相似的模型,经过 8 个 epoch 后,最终准确率达到了 80%。 (虽然我丢失了那个文件)

这是我的模型的代码:

model = Sequential()
model.add(Conv2D(filters=256,
                 kernel_size=(3, 3),
                 activation='relu',
                 data_format='channels_last',
                 input_shape=(32, 32, 3)))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(filters=128,
                 kernel_size=(2, 2),
                 activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))


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

model.fit(train_images, train_labels,
          batch_size=1000,
          epochs=5,
          verbose=1,
          validation_data=(test_images, test_labels))

loss, accuracy = model.evaluate(test_images, test_labels)
print('loss: ', loss, '\naccuracy: ', accuracy)

train_imagestest_images 是大小为 (50000,32,32,3)(10000,32,32,3)numpy arraystrain_labelstest_labels 是大小为 (50000,10)(10000,10)numpy arrays

我的问题:是什么原因造成的,我能做些什么?

Maxim 回答后编辑:

我把模型改成这样了:

model = Sequential()
model.add(Conv2D(filters=64,
                 kernel_size=(3, 3),
                 activation='relu',
                 kernel_initializer='he_normal',    # better for relu based networks
                 input_shape=(32, 32, 3)))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(filters=256,
                 kernel_size=(3, 3),
                 activation='relu',
                 kernel_initializer='he_normal'))
model.add(MaxPooling2D((2, 2)))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(10, activation='softmax'))

现在的输出是这样的:

Epoch 1/10
50000/50000 [==============================] - 326s 7ms/step - loss: 1.4916 - acc: 0.4809 - val_loss: 7.7175 - val_acc: 0.5134
Epoch 2/10
50000/50000 [==============================] - 338s 7ms/step - loss: 1.0622 - acc: 0.6265 - val_loss: 6.9945 - val_acc: 0.5588
Epoch 3/10
50000/50000 [==============================] - 326s 7ms/step - loss: 0.8957 - acc: 0.6892 - val_loss: 6.6270 - val_acc: 0.5833
Epoch 4/10
50000/50000 [==============================] - 324s 6ms/step - loss: 0.7813 - acc: 0.7271 - val_loss: 5.5790 - val_acc: 0.6474
Epoch 5/10
50000/50000 [==============================] - 327s 7ms/step - loss: 0.6690 - acc: 0.7668 - val_loss: 5.7479 - val_acc: 0.6358
Epoch 6/10
50000/50000 [==============================] - 320s 6ms/step - loss: 0.5671 - acc: 0.8031 - val_loss: 5.8720 - val_acc: 0.6302
Epoch 7/10
50000/50000 [==============================] - 328s 7ms/step - loss: 0.4865 - acc: 0.8319 - val_loss: 5.6320 - val_acc: 0.6451
Epoch 8/10
50000/50000 [==============================] - 320s 6ms/step - loss: 0.3995 - acc: 0.8611 - val_loss: 5.3879 - val_acc: 0.6615
Epoch 9/10
50000/50000 [==============================] - 320s 6ms/step - loss: 0.3337 - acc: 0.8837 - val_loss: 5.6874 - val_acc: 0.6432
Epoch 10/10
50000/50000 [==============================] - 320s 6ms/step - loss: 0.2806 - acc: 0.9033 - val_loss: 5.7424 - val_acc: 0.6399
10000/10000 [==============================] - 19s 2ms/step
loss:  5.74234927444458 
accuracy:  0.6399

看来我又过拟合了,尽管我在目前得到的帮助下改变了模型……有什么解释或提示吗?

输入图像是(32,32,3) numpy 数组,归一化为(0,1)

【问题讨论】:

将batchsize减少到大约128或64。减少dense layer的大小可能是512或384 谢谢你的回答,我以为batch size只对内存有影响,但它对训练的影响似乎比我想象的要大。我现在正在使用较小的批量重新训练模型,但这可能需要很长时间。我会及时通知您! 【参考方案1】:

您还没有说明您是如何准备数据的,这里有一个让这个网络学习得更好的补充:

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

如果您像这样进行数据归一化,那么您的网络就很好:它在 5 个 epoch 后达到了约 65-70% 的测试准确度,这是一个很好的结果。请注意,5 个 epoch 只是一个开始,大约需要 30-50 个 epoch 才能真正很好地学习数据并显示接近最新技术的结果。

以下是我注意到的一些小改进,可以为您带来额外的性能点:

由于您使用的是基于 ReLu 的网络,he_normal 初始化器 is better 比 glorot_uniform(这是 Conv2D 中的默认值)。 随着网络的深入而减少过滤器的数量是很奇怪的。你应该做相反的事情。我更改了256 -> 64128 -> 256,准确度提高了。 我略微减少了 dropout 0.5 -> 0.4。 内核大小3x32x2 更常见。我认为您也应该在第二个 conv 层上尝试一下。其实你可以和all hyper-parameters一起玩,找到最佳组合。

这是最终代码:

(x_train, y_train), (x_test, y_test) = cifar10.load_data()
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

model = Sequential()
model.add(Conv2D(filters=64,
                 kernel_size=(3, 3),
                 activation='relu',
                 kernel_initializer='he_normal',
                 input_shape=(32, 32, 3)))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(filters=256,
                 kernel_size=(2, 2),
                 kernel_initializer='he_normal',
                 activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(10, activation='softmax'))

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

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

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

loss, accuracy = model.evaluate(x_test, y_test)
print('loss: ', loss, '\naccuracy: ', accuracy)

5个epoch后的结果:

loss:  0.822134458447 
accuracy:  0.7126

顺便说一句,您可能有兴趣将您的方法与 keras example CIFAR-10 conv net 进行比较。

【讨论】:

感谢您的回答,我的数据已经归一化了,但是我会在当前的培训过程完成后尽快尝试您的其他评论 我已经用我的新模型和输出编辑了我的问题,你能看看吗? @wohe1 你试过我的代码了吗?因为我的结果不一样。不知道是不是你没有包含的代码 我已经把我所有的代码都放在这里了:github.com/wohe157/cifar10(也是预处理)

以上是关于CNN 训练准确率在训练期间变得更好,但测试准确率保持在 40% 左右的主要内容,如果未能解决你的问题,请参考以下文章

cnn训练准确率很高,测试准确率很低(loss有一直下降)是为啥?

训练准确性提高但验证准确性保持不变

Pytorch CNN 不学习

关于机器学习的基本查询

测试准确性差,但具有非常好的训练和验证准确性

Tensorflow:损失减少,但准确度稳定