如何在迁移学习过程中冻结批处理规范层



我正在遵循TensorFlow官方网站上的迁移学习和微调指南。指出在微调过程中,批量归一化层应处于推理模式:

关于BatchNormalization层的重要注意事项

许多图像模型包含CCD_ 2层。那层是每一个可以想象的特殊情况。这里有一些东西需要保存记住。

  • BatchNormalization包含2个不可训练的权重,这些权重在训练过程中更新。这些是跟踪输入的平均值和方差的变量
  • 当您设置bn_layer.trainable = False时,BatchNormalization层将以推理模式运行,并且不会更新其均值&方差统计。一般来说,其他层的情况并非如此,因为重量可训练性&推理/训练模式是两个正交的概念。但在BatchNormalization层的情况下,两者是联系在一起的
  • 当您为了进行微调而解冻包含BatchNormalization层的模型时,您应该在调用基本模型时通过传递training=False来保持BatchNormalization层处于推理模式。否则,应用于不可训练权重的更新将突然破坏模型所学习的内容

您将在末尾的端到端示例中看到这种模式本指南。

即使是其他一些来源,例如这篇文章(标题为ResNet的迁移学习),也说了一些完全不同的东西:

for layer in resnet_model.layers:
if isinstance(layer, BatchNormalization):
layer.trainable = True
else:
layer.trainable = False

无论如何,我知道TensorFlow中的trainingtrainable参数之间存在差异。

我正在从文件加载我的模型,因此:

model = tf.keras.models.load_model(path)

我正在以这种方式解冻(或者实际上冻结其余的)一些顶层:

model.trainable = True
for layer in model.layers:
if layer not in model.layers[idx:]:
layer.trainable = False

现在关于批处理规范化层:我可以做:

for layer in model.layers:
if isinstance(layer, keras.layers.BatchNormalization):
layer.trainable = False

for layer in model.layers:
if layer.name.startswith('bn'):
layer.call(layer.input, training=False)

我应该做哪一个?最后冻结批量规范层是否更好

不确定训练与可训练的区别,但就我个人而言,我在设置可训练=错误时取得了很好的结果。

现在,关于是否首先冷冻它们:我没有冷冻它们,效果很好。推理很简单,批量范数层学习初始训练数据的移动平均值。这可能是猫、狗、人、汽车等。但当你进行迁移学习时,你可能会进入一个完全不同的领域。这个新的图像域的移动平均值与之前的数据集大不相同。

通过解冻这些层并冻结CNN层,我的模型的准确率提高了6-7%(82>89%)。我的数据集与efficientnet训练的初始Imagenet数据集大不相同。

第页。S.根据你计划如何在训练后运行模式,我建议你在训练模型后冻结批处理规范层。出于某种原因,如果你在线运行模型(一次运行一张图像),批量规范会变得很奇怪,并给出不规则的结果。在训练后冻结他们为我解决了这个问题。

使用下面的代码查看批处理规范层是否被冻结。它不仅会打印图层名称,还会打印它们是否可训练。

def print_layer_trainable(conv_model):
for layer in conv_model.layers:
print("{0}:t{1}".format(layer.trainable, layer.name))

在这种情况下,我已经测试了你的方法,但没有冻结我的模型的批量规范层。

for layer in model.layers:
if isinstance(layer, keras.layers.BatchNormalization):
layer.trainable = False

下面的代码对我来说很好。在我的例子中,模型是ResNetV2,批处理规范层以后缀"命名;preact_bn";。通过使用上面的代码打印图层,您可以看到批处理规范图层是如何命名和配置的。

for layer in new_model.layers[:]:          
if ('preact_bn' in layer.name):
trainable = False
else:
trainable = True
layer.trainable = trainable

只是添加到@luciano dourado答案;

在我的案例中,我从按照迁移学习指南开始,也就是说,在整个训练过程中冻结BN层(分类器+微调)。我看到的是,训练分类器没有问题,但我一开始微调,几批后损失就归NaN所有。

在运行了通常的检查之后:没有NaN的输入数据、产生正确值的损失函数等。我检查了BN层是否在推理模式下运行(trainable = False)。

但在我的情况下,数据集与ImageNet非常不同,因此我需要做相反的操作,将所有trainableBN属性设置为True。正如@zwang评论的那样,我从经验上发现了这一点。只需记住在训练后冻结它们,然后再部署模型进行推理。

顺便说一句,作为一个信息注释,例如,ResNet50V2总共有49个BN层,其中只有16个是预激活BN。这意味着剩下的33层正在更新它们的平均值和方差值。

在另一种情况下,人们必须进行几次经验测试;标准";这种方法对他/她的情况不起作用。我想这进一步强化了数据在深度学习中的重要性:)

最新更新