用于图像回归任务的神经网络仅学习训练数据的平均值

数据挖掘 神经网络 回归 图像识别
2022-03-10 20:36:33

我正在尝试训练神经网络从输入数据中提取参数。特别是确定砖块的宽度、高度和颜色(参见附图作为示例输入)。

我已经尝试过在原始图像上运行的 CNN 和在提取的特征上运行的 NN(2 个描述边缘和一个颜色直方图)。

这两种方法似乎都学习了训练数据的平均值。颜色多为灰色,宽度和高度介于两个极端之间。输出不依赖于输入,因为 NN 总是输出“相同”的值(只有非常小的波动)。

当我对生成的数据进行操作时,我在输入和期望的输出以及无限的训练数据之间有着完美的相关性。使用的损失函数是均方误差(也尝试了绝对误差)。

有人可以解释为什么会发生这种情况或如何避免这种训练行为吗?

我正在使用库tiny-cnn我目前的方法(使用特征)使用 5 个全连接层,将层大小从 1200 减小到 17(参数数量)。

    net << fully_connected_layer<sigmoid>(1200, 600)
    << fully_connected_layer<sigmoid>(600, 300)
    << fully_connected_layer<sigmoid>(300, 150)
    << fully_connected_layer<sigmoid>(150, 60)
    << fully_connected_layer<identity>(60, 17);

我测试了几个 CNN 结构,总是以 2 个全连接层结束。我尝试了从 3 到 11 的不同内核大小。

这是我尝试的最后一个:

net << convolutional_layer<tan_h>(100, 100, 5, 3, 4)
    << average_pooling_layer<tan_h>(96, 96, 4, 2)
    << convolutional_layer<tan_h>(48, 48, 7, 4, 8)
    << average_pooling_layer<tan_h>(42, 42, 8, 2)
    << convolutional_layer<tan_h>(21, 21, 7, 8, 16)
    << average_pooling_layer<tan_h>(15, 15, 16, 3)
    << convolutional_layer<tan_h>(5, 5, 5, 16, 32)
    << fully_connected_layer<relu>(32, 64)
    << fully_connected_layer<identity>(64, size);

5-conv,平均,7-conv,平均,7-conv,平均(3x3),5-conv,完整,完整

我主要使用具有标准学习率的 RMSProp 和 adagrad,但也尝试了更高和更低的学习率。

示例输入:

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述

1个回答

我通过一些示例数据(OP 提供的)和一些简化更深入地研究了这个问题。我只是预测了砖高度参数,而不是问题中的 17 个示例参数。我使用 Python 中的 Keras 库来探索几种不同的架构。

最初我复制了这个问题,简单的 CNN 预测所有高度的相同值,而最好的损失(样本数据约为 0.0053)是当它非常精确地预测所有输入的平均值时。由于某种原因,网络无法找到数据中明显存在的视觉结构。

经过一些实验,我有了一个按预期运行的网络。对于这样一个简单的问题,它的深度令人惊讶。我对原因的最佳猜测是所有卷积的组合重叠需要与被检测到的特征具有相同的大小顺序。

一些重要的细节:

  • 检查使用您使用的图像库读取图像尺寸的顺序是否与 CNN 正在处理的预期结构相匹配。如果维度的顺序不同,这不会导致任何错误,但它会扰乱 CNN 使用的解释,并阻止它学习除均值之外的任何内容。

  • 避免使用池化层,因为它们会模糊其他层的特征像素位置。

  • 检查您的参数是否不明确。例如,这两个“砖宽”参数似乎可以互换。这使得网络更难预测它们,即使你避免了架构问题,它也可能会为示例输出一个粗略的平均值。

  • 这个问题比我最初想象的更难找到一个可行的架构。我不完全确定为什么会这样,但我猜测这与需要隔离以便网络“测量”它们的特征的大小有关。尽管像素级结构在训练数据中非常明显和清晰,但最终的工作架构非常深,例如 10 个卷积层。

这是我在 Python/Keras 中的解决方案的要点。要点架构总结:4 次 Conv2d 层,8 个特征图和 5x5 内核。辍学率 25%。4 次以上的 Conv2d 层,具有 16 个特征图和 5x5 内核。辍学 50%。具有 256 个输出的全连接层。辍学 50%。稍后完全连接,具有 128 个输出。辍学 50%。单输出神经元。所有层都使用 ReLU 激活,除了输出是线性的。

该示例将图像大小重新调整为 50x50 以提高速度。但是,使用 100x100 图像效果很好。为此,我添加了几个卷积层(8 个特征和 16 个特征部分各一个),并在验证集上获得了约 0.00025 的合理损失。看起来仍然可以通过更多的训练示例、更多的 epoch 甚至更多的特征图来获得更低的损失。许多预测非常好,接近实际值。

有趣的是,最严重的错误是预测接近于 2:1 或 3:2 与地面实况的比例的短砖,这意味着网络找到了正确的结构,但被砖的周期性性质所迷惑。我认为这可以通过更多的训练示例(也许更高层中的更多特征)来解决,并且应该有可能在砖高度上获得更低的损失度量。

我认为对应的 tiny-cnn 结构是这样的:

net << convolutional_layer<relu>(100, 100, 5, 3, 8)
    << convolutional_layer<relu>(96, 96, 5, 8, 8)
    << convolutional_layer<relu>(92, 92, 5, 8, 8)
    << convolutional_layer<relu>(88, 88, 5, 8, 8)
    << convolutional_layer<relu>(84, 84, 5, 8, 8)
    << dropout(80 * 80 * 8, 0.25)
    << convolutional_layer<relu>(80, 80, 5, 8, 16)
    << convolutional_layer<relu>(76, 76, 5, 16, 16)
    << convolutional_layer<relu>(72, 72, 5, 16, 16)
    << convolutional_layer<relu>(68, 68, 5, 16, 16)
    << convolutional_layer<relu>(64, 64, 5, 16, 16)
    << dropout(60 * 60 * 16, 0.5)
    << fully_connected_layer<relu>(57600, 256)
    << dropout(256, 0.5)
    << fully_connected_layer<relu>(256, 128)
    << dropout(128, 0.5)
    << fully_connected_layer<identity>(128, 1)