CNN 在简单的目标检测问题中未按预期收敛

问题描述 投票:0回答:1

我刚刚开始学习 Tensorflow 是为了好玩,在简单的目标检测任务中训练 CNN 遇到了很大的困难。特别是,我正在尝试训练一个网络来播放“Waldo 在哪里?”在 Python 中使用 Tensorflow。我生成了与本文中类似的训练数据,其中我将 Waldo 的图像粘贴到随机位置的 500x500 像素图像的背景上,并具有随机大小(宽度在 23 到 43 像素之间)。目前,我正在使用纯灰色背景图像来测试网络和训练,尽管我尝试过使用其他图像,但它们以大致相同的方式失败了。这是示例图片,供参考。

对于训练,x_batch 包含表示上述形式图像的数组,但没有绿色框。 y_batch 包含 3 个浮点,分别代表 Waldo 周围框的行、列和大小。 x_batch 和 y_batch 均已标准化,因此所有值都在 0 和 1 之间。这是我正在使用的网络架构:

model = tf.keras.Sequential()
model.add(tf.keras.Input(shape=(500,500,3)))
model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(5,5), padding="same", kernel_initializer='he_uniform', activation='relu'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.MaxPool2D(pool_size=(2,2), padding="valid"))
model.add(tf.keras.layers.Dropout(0.2))

model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding="same", kernel_initializer='he_uniform', activation='relu'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2), padding="valid"))
model.add(tf.keras.layers.Dropout(0.2))

model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding="valid", kernel_initializer='he_uniform', activation='relu'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2), padding="valid"))
model.add(tf.keras.layers.Dropout(0.2))

model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=(2,2), padding="valid", kernel_initializer='he_uniform', activation='relu'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2), padding="valid"))
model.add(tf.keras.layers.Dropout(0.2))

model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(units=256, activation='relu'))
model.add(tf.keras.layers.Dense(units=3, activation='sigmoid'))

为了训练网络,我使用 Adam 优化器和自定义学习率调度程序,以及分类交叉熵损失函数(我也尝试过使用 mse):

def lr_schedule(epoch, lr):
    if (epoch + 1) % 5 == 0: 
        lr *= 0.4
    return max(lr, 3e-7)
            
optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001)
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit(gen.generate_data(), epochs=10, steps_per_epoch = 50, callbacks = [VisCallback(),
                                                                                    tf.keras.callbacks.LearningRateScheduler(lr_schedule)])

函数

gen.generate_data()
如上所述创建批次(我使用的批次大小为
16
,但也尝试过
32
),并且
VisCallback()
函数只是让网络创建带有红色的图像描述每个时期后的预测的框。

运行代码时,99% 的情况下,会发生以下两种情况之一:

  1. 网络快速收敛,并预测 Waldo 位于图像的中心,无论他实际在哪里。
  2. 网络很快就预测 Waldo 位于图像的一个角落,无论他实际在哪里(几乎每次使用
    categorial_crossentropy
    损失函数时都会发生这种情况)。

在一次不规则的情况下,网络实际上确实开始正确猜测 Waldo 所在的位置(准确度约为 10%,并且无限期地保持不变),但该行为尚未重现。我对如何从这里继续进行有些不知所措。收敛到中心的事实是有一定道理的,因为它是 Waldo 在大量随机分布数据样本上的平均位置。但我在其他对象检测问题这篇文章中没有听说过这个问题,它在代码中还有其他问题,例如使用 softmax 进行输出。谁能提供一些关于如何解决此类问题的指导或建议?

python tensorflow conv-neural-network object-detection
1个回答
0
投票

我猜这与学习率的问题有关。而损失函数发散或收敛的泛化并不是一个简单的问题。但至于推荐:

  1. 在大多数情况下,学习率和优化函数最重要。首先尝试简单的优化函数(如 SGD),然后尝试另一个函数,依此类推。 Adam 需要更多的理解,而不仅仅是 SGD 方法。
  2. 因此,根据给定的数字 1,假设您找到了所需的学习率和优化函数,然后检查模型层的组成。当然,首先必须考虑模型层是否有效,但在本建议中我指的是层的组成。如果层数太多或节点太少,整体精度就会下降。
  3. 通过1和2,如果你清楚了学习率和优化函数,那么你可以尝试其他损失函数。重要的是,简单回归和分类的损失函数之间存在差距。例如,如果你在分类中使用回归损失函数,无论损失是否发散或收敛,你都将得到不足够的准确度或结果。

不过,这些都是简单的建议。但显然它在任何深度学习情况下都很重要。

© www.soinside.com 2019 - 2024. All rights reserved.