如何微调Keras中的接收v3

如何微调Keras中的接收v3,keras,deep-learning,transfer-learning,batch-normalization,image-classification,Keras,Deep Learning,Transfer Learning,Batch Normalization,Image Classification,我试图在Keras中训练一个基于InceptionV3架构的分类器。 为此,我加载了预先训练好的InceptionV3模型,没有顶层,并为我的分类问题的类添加了最后一个完全连接的层。在第一次培训中,我冻结了InceptionV3基础模型,只培训了最后一个完全连接的层 在第二步中,我想通过解冻InceptionV3模型的一部分来“微调”网络。 现在我知道InceptionV3模型广泛使用了BatchNorm层。当BatchNorm层“解冻”以便在转移学习时进行微调时,建议()保持BatchNorm

我试图在Keras中训练一个基于InceptionV3架构的分类器。 为此,我加载了预先训练好的InceptionV3模型,没有顶层,并为我的分类问题的类添加了最后一个完全连接的层。在第一次培训中,我冻结了InceptionV3基础模型,只培训了最后一个完全连接的层

在第二步中,我想通过解冻InceptionV3模型的一部分来“微调”网络。 现在我知道InceptionV3模型广泛使用了BatchNorm层。当BatchNorm层“解冻”以便在转移学习时进行微调时,建议()保持BatchNorm层计算的平均值和方差固定。这应该通过将BatchNorm层设置为推断模式而不是训练模式来实现。 另请参阅:

现在我的主要问题是:如何仅将InceptionV3模型的BatchNorm层设置为推断模式?

目前,我通过在组装网络时设置“training”参数,将整个InceptionV3基本模型设置为推断模式:

inputs = keras.Input(shape=input_shape)
# Scale the 0-255 RGB values to 0.0-1.0 RGB values
x = layers.experimental.preprocessing.Rescaling(1./255)(inputs)
# Set include_top to False so that the final fully connected (with pre-loaded weights) layer is not included.
# We will add our own fully connected layer for our own set of classes to the network.
base_model = keras.applications.InceptionV3(input_shape=input_shape, weights='imagenet', include_top=False)
x = base_model(x, training=False)
# Classification block
x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
x = layers.Dense(num_classes, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=x)
我不喜欢的是,通过这种方式,我将整个模型设置为推理模式,这可能会将某些层设置为不应该设置的推理模式

下面是代码的一部分,用于加载我所做的初始训练中的权重,以及冻结InceptionV3部分的前150层并解冻其余层的代码:

model.load_weights(load_model_weight_file_name)
for layer in base_model.layers[: 150]:
    layer.trainable = False
for layer in base_model.layers[ 150:]:
    layer.trainable = True
我的其余代码(此处未显示)是通常的编译和拟合调用

运行此代码似乎会导致网络无法真正学习(损失和准确性保持大致相同)。我尝试了不同数量级的优化步长,但似乎没有帮助

另一件我观察到的事情是,当我使整个接收v3部分可训练时

base_model.trainable = True

训练开始时的准确度要比我第一轮训练结束时低几个数量级(当然损失要大得多)。有人能给我解释一下吗?如果在准确性和损失方面不进行培训,我至少希望培训能够继续进行。

您可以采取以下措施:

for layer in base_model.layers:
    if isinstance(layer ,tf.keras.layers.BatchNormalization):
        layer.trainable=False
这将迭代每个层并检查类型,如果层为BatchNorm,则设置为推断模式

至于转移学习期间的低启动精度,您只加载权重,而不是优化程序状态(如加载架构、权重、优化程序状态等的完整
model.load()


这并不意味着有错误,但如果你必须只加载重量,让它训练,优化者最终会配置,你应该看到进展。另外,由于您在第二次跑步时可能会过度书写预先训练的重量,请确保使用较低的学习率,以便更新相对较小,即微调重量,而不是将其炸成碎片。

谢谢您的提示,但我想这不是我想要的。因为我确实想让这些层学习(因为它们必须学习gamma和beta权重,对吧?),我只是不想让它们处于训练模式,以避免层计算一批的平均值和方差。我真的不理解你对准确性的解释。当我加载权重时,在训练开始时,网络将与之前大致相同,因此分类结果将大致相同。即使在第一个纪元的第一步中,我也看到了比以前低得多的精度(和更高的损失)。您的问题是“如何仅将InceptionV3模型的BatchNorm层设置为推断模式”,而这正是您要做的。我认为这里的术语可能有些混乱-如果您希望层学习(
layer.trainable=True
),那么根据定义,它们处于培训模式。设置trainable=false是推理模式的定义,是keras/tf在调用
base\u model.predict时自动执行的操作。您不能让层学习,也不能处于培训模式。只是为了澄清“建议在BatchNorm层“解冻”以便在转移学习时进行微调”,此处“解冻”意味着设置layer.trainable=True,假设您冻结/设置所有其他层的trainable=False。您可以冻结整个模型并在顶部添加一些附加层,或者解冻所有/部分层并选择较低的学习率来略微调整整个模型权重。在精度注释中-当您仅加载权重(而不是优化器等)时,则是,模型权重将相同,但是,当您训练模型时,优化器也会保留一个状态,因此,如果您没有从第一轮训练中加载优化器(即,优化器状态被重置),那么它将需要一些初始批次来重新计算其状态,这就是为什么您在开始时的精度比以前低得多的原因。您是否允许它运行以查看精度是否有所提高?