我刚刚开始学习 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% 的情况下,会发生以下两种情况之一:
categorial_crossentropy
损失函数时都会发生这种情况)。在一次不规则的情况下,网络实际上确实开始正确猜测 Waldo 所在的位置(准确度约为 10%,并且无限期地保持不变),但该行为尚未重现。我对如何从这里继续进行有些不知所措。收敛到中心的事实是有一定道理的,因为它是 Waldo 在大量随机分布数据样本上的平均位置。但我在其他对象检测问题这篇文章中没有听说过这个问题,它在代码中还有其他问题,例如使用 softmax 进行输出。谁能提供一些关于如何解决此类问题的指导或建议?
我猜这与学习率的问题有关。而损失函数发散或收敛的泛化并不是一个简单的问题。但至于推荐:
不过,这些都是简单的建议。但显然它在任何深度学习情况下都很重要。