我正在遵循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中的training
和trainable
参数之间存在差异。
我正在从文件加载我的模型,因此:
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非常不同,因此我需要做相反的操作,将所有trainable
BN属性设置为True
。正如@zwang评论的那样,我从经验上发现了这一点。只需记住在训练后冻结它们,然后再部署模型进行推理。
顺便说一句,作为一个信息注释,例如,ResNet50V2总共有49个BN层,其中只有16个是预激活BN。这意味着剩下的33层正在更新它们的平均值和方差值。
在另一种情况下,人们必须进行几次经验测试;标准";这种方法对他/她的情况不起作用。我想这进一步强化了数据在深度学习中的重要性:)