2

我正在使用 Keras 2.1.6 使用 2 种众所周知的标准方法进行迁移学习。两者都在 Chollet 书的第 5 章和https://github.com/fchollet/deep-learning-with-python-notebooks/blob/master/5.3-using-a-pretrained-convnet.ipynb中详细介绍

2种方式总结如下:

A) 从 conv_base 缓存表示,然后在你的 FC 上单独训练。这被认为很快,但不允许在 Keras 中进行数据扩充。

B) 用你的 FC 扩展 conv_base 模型并冻结 conv_base 权重,并端到端训练。这在 CPU 上训练成本很高,但会提供更大的灵活性,特别是添加数据增强。

对于我的特定数据集并使用 MobileNet(而不是 VGG),我尝试了两种方式。方法 (A) 在 10 个 epoch 后会给我大约 75% 的验证准确率,但方法 (B) 只会给我约 58%(没有数据增强)。但是,我希望它们大致相同。我试图调试并查看我做错了什么,但没有发现任何问题。

我读到的一件事是,据说在方法 B) 中被冻结的权重可能由于过去的错误而没有被冻结。但是当前的 Keras 版本 2.1.6 应该没有这个。这是我冻结 conv_base 中的权重的方法。

conv_base.trainable = False
for layer in conv_base.layers:
    layer.trainable = False

可能不需要循环,但我添加它以防万一。我通过在几个 epoch 后检查权重来验证权重实际上被冻结了。所以这可能不是导致问题的原因。

任何有关于如何调试或可能出错的提示的人,请告诉我。

我将两次运行都发布为 GitHub 要点。我在 google colab 上运行并导出了它们。相关部分应该从那些 Keras 导入开始。

方法A):https ://gist.github.com/kechan/38b4e6c85501246a2a49deadd26aefd7

方法B):https ://gist.github.com/kechan/f3fea62279ac847e9adc100351b7e9e8

更新

我进一步将这两种迁移学习方式结合到一个笔记本中,并尽可能地保持其他一切“恒定”。这是新的要点:

https://gist.github.com/kechan/9487fad4dfaeede212e3d9899fb21105

4

1 回答 1

0

这似乎是BatchNormalization层 (BN) 或任何其他层的影响,它们在训练与推理中的工作方式不同。BN 特别是在推理中使用保存的人口统计数据,但在训练中使用当前的小批量统计数据。当您冻结基础模型中 BN 层的权重然后进行训练时,会使用小批量统计信息。这可能会导致不好的结果,因为相邻的卷积层期望使用保存的人口统计数据对输入进行归一化。

如果您首先使用基础模型提取特征,您不会看到任何不良影响,因为基础模型处于推理模式并且使用人口统计数据。

一种解决方案是子类BatchNormalization化并覆盖将标志__call__设置为 False 的方法。training类似于以下内容:

class InferenceBatchNormalization(BatchNormalization):
    def __init__(self, **kwargs):
        super(BatchNormalization, self).__init__(**kwargs)

    def call(self, inputs, training=None):
        return super(BatchNormalization, self).__call__(inputs, training=False)

看看 keras 代码,它就会变得清晰:https ://github.com/keras-team/keras/blob/master/keras/layers/normalization.py#L132

于 2019-03-04T09:51:40.393 回答