【问题标题】:Neural Network flatlines after one epoch一个时期后的神经网络扁平化
【发布时间】:2017-06-26 22:34:06
【问题描述】:

我正在使用 keras 创建一个卷积神经网络,以尝试将图像分类为两个不同的类别,并且由于某种原因,在第一个 epoch 之后,准确性永远不会改变。

使用 Keras 的 to_categorical() 后,我的标签看起来像:

[[0.  1.]
[1.  0.]
[1.  0.]
[0.  1.]]

我的模型的代码是:

model = Sequential()
model.add(Conv2D(filters=32, kernel_size=[5, 5], strides=1, padding='same', activation='relu', input_shape=(imageSize, imageSize, 3)))
model.add(MaxPooling2D())
model.add(Conv2D(filters=64, kernel_size=[5, 5], strides=1, padding='same', activation='relu'))
model.add(MaxPooling2D())
model.add(Flatten())
model.add(Dense(2))
sgd = SGD()  # Use stochastic gradient descent for now
model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])

model.summary()

counter = 0
# Train one cycle at a time so we can shuffle data inbetween
for x in range(trainingEpochs):

    counter += 1
    print()  # New line
    print('Epoch ' + str(counter))

    trainingImages, trainingLabels = shuffle(trainingImages, trainingLabels, random_state=0)  # Shuffle both sets in unison

    model.fit(x=trainingImages, y=trainingLabels, batch_size=32, epochs=1, verbose=2)

此代码导致输出:

Epoch 1
36s - loss: 5.0770 - acc: 0.3554

Epoch 2
36s - loss: 4.9421 - acc: 0.3066

Epoch 3
36s - loss: 4.9421 - acc: 0.3066

Epoch 4
36s - loss: 4.9421 - acc: 0.3066

到目前为止,我已经尝试过更改批量大小,使用 binary_crossentropy,更改洗牌方法,更改卷积参数,使用黑白照片而不是 RGB,使用不同尺寸的图片,使用 ADAM 而不是 SGD,以及使用SGD 的学习率较低,但这些都没有解决问题。我很茫然,有人有什么想法吗?

编辑:trainingImages 的形状为 (287, 256, 256, 3),如果这很重要的话。

【问题讨论】:

  • 我会说你的网络对于数据来说太简单了。您需要通过添加层和增加参数(权重)的数量来使其更复杂。
  • 你的班级分布是什么?网络比随机好吗?
  • 我猜这里报告的准确率是训练准确率?您是否尝试过使用更大的网络?

标签: python python-3.x machine-learning tensorflow keras


【解决方案1】:

症状是训练损失相对较早停止改善。假设您的问题完全可以学习,那么这种行为的原因有很多。这些在我的脑海中:

  1. 输入预处理不当:

神经网络更喜欢零均值的输入。例如,如果输入都是正数,它将限制权重在同一方向上更新,这可能是不可取的(https://youtu.be/gYpoJMlgyXA)。

因此,您可能希望从所有图像中减去平均值(例如,从 3 个通道中的每个通道中减去 127.5)。缩放以使每个通道中的单位标准偏差也可能会有所帮助。

  1. 网络的泛化能力:

网络对于任务来说不够复杂或深度不够。

这很容易检查。你可以只用几张图片(比如 3 到 10 张)训练网络。网络应该能够过拟合数据并将损失驱动到几乎为 0。如果不是这样,您可能需要添加更多层,例如使用超过 1 个 Dense 层。

另一个好主意是使用预训练的权重(在 Keras 文档的应用程序中)。您可以调整顶部的密集层以适应您的问题。

  1. 权重初始化不正确。

权重初始化不当会导致网络无法收敛(https://youtu.be/gYpoJMlgyXA,和之前的视频一样)。

对于 ReLU 激活,您可能希望使用 He 初始化而不是默认的 Glorot 初始化。我发现这有时可能是必要的,但并非总是如此。

最后,您可以使用 Keras 的调试工具,例如 keras-vis、keplr-io、deep-viz-keras。它们对于打开卷积网络的黑盒非常有用。

【讨论】:

    【解决方案2】:

    在浏览了@rafaelvalle 链接的博客文章后,我设法确定我的问题是由我的标签编码引起的。最初我将它们作为单一热编码,看起来像[[0, 1], [1, 0], [1, 0]],在博客文章中它们的格式为[0 1 0 0 1]。将我的标签更改为此并使用二元交叉熵使我的模型正常工作。感谢 Ngoc Anh Huynh 和 rafaelvalle!

    【讨论】:

      【解决方案3】:

      您需要在网络的最后一层添加 sigmoid 非线性并将输出的数量更改为 1。这种非线性将输入映射到 [0, 1]。

      # ...
      model.add(Flatten())
      model.add(Dense(1))
      # add nonlinearity
      model.add(Activation('sigmoid'))
      

      另外,将模型的损失更改为 binary_crossentropy

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

      最后,确保您的标签是布尔型(或 0 或 1 中的 int)和形状 (n_observations, 1)。也就是说,将它们从 [[0, 1], [1, 0], [1, 0]] 更改为 [0 1 0 0 1]。

      如果您仍然遇到问题,请查看 keras' blog 描述如何构建二进制图像分类器。

      【讨论】:

      • 为什么是 sigmoid? Softmax 更有意义。
      • 问题是二元分类,因此,没有必要使用归一化项来解释其他类..
      • 是的,但是这一层输出两个值,而不是一个。 Sigmoid 仅在您输出标量时适用。
      • 嗯,似乎添加 binary_crossentropy 并使用 sigmoid 或 softmax 并不能解决问题。还有其他想法吗?我是否需要在训练图像周围放置一个边界框以向 CNN 显示我要识别的内容,或者我可以只为它提供带有标签的普通 jpeg 数据吗?我在 LSTM 上大量使用 Keras,但在 CNN 上完全没有。
      • 另外,如果我尝试将 Dense 图层更改为大小 1,我会收到错误:ValueError: Error when checks target: expected dense_1 to have shape (None, 1) but got array with shape (287) , 2) 其中 287 是我的样本量。
      猜你喜欢
      • 2018-05-22
      • 2013-11-19
      • 2017-09-11
      • 2014-08-17
      • 1970-01-01
      • 2018-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多