与“培训”相比,通过冻结conv_base进行的Keras迁移学习的准确性较差;“预缓存”;特征

与“培训”相比,通过冻结conv_base进行的Keras迁移学习的准确性较差;“预缓存”;特征,keras,transfer-learning,Keras,Transfer Learning,我正在使用Keras 2.1.6和2种非常著名的标准方法进行迁移学习。这两个都在Chollet的书的第5章和 这两种方式概括如下: A) 缓存conv_base中的表示,然后分别在FC上进行训练。 这被认为是快速的,但不允许在KERA中增加数据 B) 使用FC扩展conv_基本模型,冻结conv_基本重量,并进行端到端训练。这在CPU上进行培训成本很高,但将允许更大的灵活性,特别是添加数据扩充 对于我的特定数据集,使用MobileNet(而不是VGG),我尝试了两种方法。方法(A)将在10个阶段

我正在使用Keras 2.1.6和2种非常著名的标准方法进行迁移学习。这两个都在Chollet的书的第5章和

这两种方式概括如下:

A) 缓存conv_base中的表示,然后分别在FC上进行训练。 这被认为是快速的,但不允许在KERA中增加数据

B) 使用FC扩展conv_基本模型,冻结conv_基本重量,并进行端到端训练。这在CPU上进行培训成本很高,但将允许更大的灵活性,特别是添加数据扩充

对于我的特定数据集,使用MobileNet(而不是VGG),我尝试了两种方法。方法(A)将在10个阶段后为我提供约75%的验证准确率,但方法(B)仅为我提供约58%(无数据增加)。然而,我希望它们大致相同。我试着调试,看看我做错了什么,但没有发现任何错误

我读到的一件事是,在方法B)中被假定为冻结的重量可能不会因为过去的错误而冻结。但是当前的Keras版本2.1.6应该没有这个问题。下面是我在conv_base中冻结砝码的方法

conv_base.trainable = False
for layer in conv_base.layers:
    layer.trainable = False
循环可能不需要,但我添加了它以防万一。我在几个时代后通过检查重量来证实重量实际上是冻结的。所以这可能不是导致问题的原因

任何人谁有关于如何调试的提示,或什么可能会出错,请让我知道

我以GitHub gists的身份发布了两次跑步记录。我在GoogleColab上运行了这个并将其导出。相关部分应以Keras进口开始

方法A):

方法B):

更新 我进一步将转移学习的两种方式组合到一个笔记本中,并尽可能地保持其他一切“不变”。以下是新的要点:


这似乎是
批量标准化(BN)或任何其他层的效果,这些层在训练和推理中的工作方式不同。BN特别在推理中使用保存的人口统计数据,但在训练中使用当前的小批量统计数据。当您在基本模型中冻结一个BN层的权重,然后进行训练时,将使用小批量统计信息。这可能会导致糟糕的结果,因为相邻的conv层期望使用保存的总体统计数据对输入进行规范化

如果首先使用基本模型提取特征,则不会看到任何不良影响,因为基本模型处于推理模式,并且使用了总体统计信息

解决方案是将
BatchNormalization
子类化,并覆盖
\uuuuuu调用
方法,将
training
标志设置为False。如下所示:

类推断BatchNormalization(BatchNormalization):
定义初始(自我,**kwargs):
超级(批处理规范化,自).\uuuu初始化(**kwargs)
def呼叫(自我、输入、培训=无):
返回super(BatchNormalization,self)。\调用(输入,训练=False)

看一看keras代码,就会很清楚:

我实际上已经将这两个代码合并到一个笔记本中,以突出我看到的内容:更新:我测试了VGG16、MobileNet和Exception作为我的conv_基础(include_top=False)。我认为VGG16的差异最小,而MobileNet和Exception的差异更大。因此,架构可能很重要。VGG16没有的一件事是批处理规范。我开始怀疑可能存在一个“问题”,关于如何冻结、训练等涉及批处理规范层的问题。你知道这一点吗?事实上,我对书中的陈述表示怀疑。我无法使用与VGG16完全相同的代码(+冻结)重现结果。事实上,当我关闭冻结时,训练结果更接近书中的曲线(val acc达到96%-97%)。