神经网络在一个时代之后变得扁平化

时间:2017-06-26 22:34:07

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

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

使用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),如果这一点很重要的话。

3 个答案:

答案 0 :(得分:6)

症状是训练损失相对较早地停止改善。假设您的问题完全可以学习,这种行为有很多原因。这些都是我的首要任务:

  1. 输入的预处理不当:
  2. 神经网络优先选择零均值输入。例如,如果输入全部为正,则将限制权重在相同方向上更新,这可能是不可取的(https://youtu.be/gYpoJMlgyXA)。

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

    1. 网络的泛化能力:
    2. 网络对于任务而言并不复杂或不够深。

      这很容易检查。您可以在几张图片上训练网络(从3到10说)。网络应该能够过度拟合数据并将损失驱动到接近0.如果不是这样,您可能需要添加更多层,例如使用多于1个Dense层。

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

      1. 不正确的重量初始化。
      2. 不正确的权重初始化可能会阻止网络收敛(https://youtu.be/gYpoJMlgyXA,与之前的视频相同。)

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

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

答案 1 :(得分:2)

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

# ...
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

答案 2 :(得分:2)

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