【问题标题】:Training CNN with transfer learning in Keras - image input doesn't work but vector input does在 Keras 中使用迁移学习训练 CNN - 图像输入不起作用,但矢量输入起作用
【发布时间】:2019-04-06 05:43:03
【问题描述】:

我正在尝试在 Keras 中进行迁移学习。我设置了一个 ResNet50 网络设置为不可训练一些额外的层:

# Image input
model = Sequential()
model.add(ResNet50(include_top=False, pooling='avg')) # output is 2048
model.add(Dropout(0.05))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.15))
model.add(Dense(512, activation='relu'))
model.add(Dense(7, activation='softmax'))
model.layers[0].trainable = False
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()

然后我使用 ResNet50 preprocess_input 函数创建输入数据:x_batch,以及一个热编码标签 y_batch,然后进行拟合:

model.fit(x_batch,
          y_batch,
          epochs=nb_epochs,
          batch_size=64,
          shuffle=True,
          validation_split=0.2,
          callbacks=[lrate])

经过十个左右的 epoch,训练准确率接近 100%,但验证准确率实际上从 50% 左右下降到 30%,而验证损失稳步增加。

但是,如果我改为创建仅包含最后几层的网络:

# Vector input
model2 = Sequential()
model2.add(Dropout(0.05, input_shape=(2048,)))
model2.add(Dense(512, activation='relu'))
model2.add(Dropout(0.15))
model2.add(Dense(512, activation='relu'))
model2.add(Dense(7, activation='softmax'))
model2.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model2.summary()

并输入 ResNet50 预测的输出:

resnet = ResNet50(include_top=False, pooling='avg')
x_batch = resnet.predict(x_batch)

然后验证准确率达到 85% 左右......这是怎么回事?为什么图片输入法不起作用?

更新:

这个问题真的很奇怪。如果我将 ResNet50 更改为 VGG19,它似乎可以正常工作。

【问题讨论】:

  • 检查第一种情况和第二种情况下的可训练层数。它们是一样的吗?
  • @dgumo 是的,它们是一样的
  • 是的,可训练参数的数量匹配(大约 2400 万个参数,2300 万个不可训练,130 万个可训练)

标签: python tensorflow keras


【解决方案1】:

经过大量谷歌搜索后,我发现问题与 ResNet 中的批量标准化层有关。 VGGNet 中没有批量归一化层,这就是它适用于该拓扑的原因。

在 Keras here 中有一个拉取请求来解决这个问题,其中有更详细的解释:

假设我们使用 Keras 的预训练 CNN 之一,并且我们想要对其进行微调。不幸的是,我们无法保证 BN 层内的新数据集的均值和方差与原始数据集的均值和方差相似。因此,如果我们微调顶层,它们的权重将被调整为新数据集的均值/方差。然而,在推理过程中,顶层将接收使用原始数据集的均值/方差进行缩放的数据。这种差异会导致准确性降低。

这意味着 BN 层正在根据训练数据进行调整,但是在执行验证时,将使用 BN 层的原始参数。据我所知,解决方法是允许冻结的 BN 层使用训练中更新的均值和方差。

一种解决方法是预先计算 ResNet 输出。事实上,这大大减少了训练时间,因为我们没有重复这部分计算。

【讨论】:

  • 可以多解释一下,Batch normalisation是一个层,是第一种还是第二种情况自动出现?你能给出固定叉的链接吗
【解决方案2】:

你可以试试:

Res = keras.applications.resnet.ResNet50(include_top=False, 
              weights='imagenet',  input_shape=(IMG_SIZE , IMG_SIZE , 3 ) )


    # Freeze the layers except the last 4 layers
for layer in vgg_conv.layers  :
   layer.trainable = False

# Check the trainable status of the individual layers
for layer in vgg_conv.layers:
    print(layer, layer.trainable)

# Vector input
model2 = Sequential()
model2.add(Res)
model2.add(Flatten())
model2.add(Dropout(0.05 ))
model2.add(Dense(512, activation='relu'))
model2.add(Dropout(0.15))
model2.add(Dense(512, activation='relu'))
model2.add(Dense(7, activation='softmax'))
model2.compile(optimizer='adam', loss='categorical_crossentropy', metrics =(['accuracy'])
model2.summary()

【讨论】:

  • 我可以理解为什么 vgg_conv.layers 是为 ResNet50 来的。
猜你喜欢
  • 2018-02-10
  • 2019-02-12
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
  • 2018-01-14
  • 2019-12-25
  • 1970-01-01
相关资源
最近更新 更多