如何从Keras模型中删除前N层?

2024-10-01 04:45:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我想从预训练的Keras模型中删除第一个N层。例如,一个EfficientNetB0,其第一个3层仅负责预处理:

import tensorflow as tf

efinet = tf.keras.applications.EfficientNetB0(weights=None, include_top=True)

print(efinet.layers[:3])
# [<tensorflow.python.keras.engine.input_layer.InputLayer at 0x7fa9a870e4d0>,
# <tensorflow.python.keras.layers.preprocessing.image_preprocessing.Rescaling at 0x7fa9a61343d0>,
# <tensorflow.python.keras.layers.preprocessing.normalization.Normalization at 0x7fa9a60d21d0>]

M.Innat所述,第一层是一个Input Layer,它应该被保留或重新连接。我想删除这些层,但这样的简单方法会引发错误:

cut_input_model = return tf.keras.Model(
    inputs=[efinet.layers[3].input], 
    outputs=efinet.outputs
)

这将导致:

ValueError: Graph disconnected: cannot obtain value for tensor KerasTensor(...)

推荐的方法是什么


Tags: 方法模型importinputlayerstftensorflowas
3条回答

我一直在尝试对keras tensorflow VGFace模型做同样的事情。经过大量的实验,我发现这种方法是有效的。在这种情况下,将使用除最后一层之外的所有模型,该层将替换为自定义嵌入层:

vgg_model = VGGFace(include_top=True, input_shape=(224, 224, 3)) # full VGG16 model
inputs = Input(shape=(224, 224, 3))
x = inputs
# Assemble all layers except for the last layer
for layer in vgg_model.layers[1:-2]:
  x = vgg_model.get_layer(layer.name)(x)
    
# Now add a new last layer that provides the 128 embeddings output
x = Dense(128, activation='softmax', use_bias=False, name='fc8x')(x)
# Create the custom model
custom_vgg_model = Model(inputs, x, name='custom_vggface')

与层[x]或pop()不同,get_layer获取实际层,允许将它们组装到新的输出层集中。然后可以从中创建新模型。“for”语句以1而不是0开头,因为输入层已由“inputs”定义

这种方法适用于序列模型。不清楚它是否适用于更复杂的模型

获取Graph disconnected错误的原因是您没有指定Input层。但这不是这里的主要问题。有时,使用SequentialFunctionalAPI从keras模型中删除中间层并不简单

对于顺序,它应该相对容易,而在函数模型中,您需要关注多输入块(例如multiplyadd等)。例如:如果要删除顺序模型中的某些中间层,可以轻松地调整this solution。但是对于函数模型(efficientnet),由于多输入内部块的原因,您不能这样做,您将遇到以下错误:ValueError: A merged layer should be called on a list of inputs。所以这需要更多的工作,这里有一个possible approach来克服它


这里我将为您的案例展示一个简单的解决方法,但它可能不是通用的,在某些情况下也不安全。以this approach为基础;使用pop方法Why it can be unsafe to use!。好的,让我们先加载模型

func_model = tf.keras.applications.EfficientNetB0()

for i, l in enumerate(func_model.layers):
    print(l.name, l.output_shape)
    if i == 8: break

input_19 [(None, 224, 224, 3)]
rescaling_13 (None, 224, 224, 3)
normalization_13 (None, 224, 224, 3)
stem_conv_pad (None, 225, 225, 3)
stem_conv (None, 112, 112, 32)
stem_bn (None, 112, 112, 32)
stem_activation (None, 112, 112, 32)
block1a_dwconv (None, 112, 112, 32)
block1a_bn (None, 112, 112, 32)

接下来,使用.pop方法:

func_model._layers.pop(1) # remove rescaling
func_model._layers.pop(1) # remove normalization

for i, l in enumerate(func_model.layers):
    print(l.name, l.output_shape)
    if i == 8: break

input_22 [(None, 224, 224, 3)]
stem_conv_pad (None, 225, 225, 3)
stem_conv (None, 112, 112, 32)
stem_bn (None, 112, 112, 32)
stem_activation (None, 112, 112, 32)
block1a_dwconv (None, 112, 112, 32)
block1a_bn (None, 112, 112, 32)
block1a_activation (None, 112, 112, 32)
block1a_se_squeeze (None, 32)

下面的代码加载一个模型,删除最后一层并添加一个新层作为最后一层

old_model = keras.models.load_model("old_model.h5")
new_model= keras.models.Sequential(old_model.layers[:-1])
new_model.add(keras.layers.Dense(5, activation="sigmoid"))

您可以使用类似的方法切掉第一层,只拾取最后一层

old_model.layers[N:]

有比这更好的方法。创建模型的克隆,复制其权重,然后添加新层并训练网络

clone_of_old_model = keras.models.clone_model(old_model)
clone_of_old_model.set_weights(old_model.get_weights())

我之所以说这种方法更好,是因为如果使用第一段代码,新模型的训练可能会影响旧模型

现在,您可以将这两部分组合起来创建一个新模型

只需记住编译模型,因为您将冻结和解冻层

相关问题 更多 >