python Keras替换输入层

wydwbb8l  于 2023-04-19  发布在  Python
关注(0)|答案(7)|浏览(148)

我的代码(我不能更改)使用Resnet,my_input_tensor作为input_tensor。

model1 = keras.applications.resnet50.ResNet50(input_tensor=my_input_tensor, weights='imagenet')

研究source code,ResNet50函数用my_input_tensor创建一个新的keras输入层,然后创建模型的其余部分。这是我想用我自己的模型复制的行为。我从h5文件加载我的模型。

model2 = keras.models.load_model('my_model.h5')

因为这个模型已经有了一个输入层,所以我想用一个新的输入层来替换它,这个新的输入层是用my_input_tensor定义的。
如何替换输入层?

vawmfj5a

vawmfj5a1#

使用以下命令保存模型时:

old_model.save('my_model.h5')

它将保存以下内容:
1.模型的体系结构,允许创建模型。
1.模型的权重。
1.模型的训练配置(损失、优化器)。
1.优化器的状态,允许从之前离开的位置继续训练。
然后,当你加载模型时:

res50_model = load_model('my_model.h5')

你应该得到相同的模型回来,你可以验证相同的使用:

res50_model.summary()
res50_model.get_weights()

现在,您可以弹出输入层并使用以下命令添加您自己的输入层:

res50_model.layers.pop(0)
res50_model.summary()

添加新的输入层:

newInput = Input(batch_shape=(0,299,299,3))    # let us say this new InputLayer
newOutputs = res50_model(newInput)
newModel = Model(newInput, newOutputs)

newModel.summary()
res50_model.summary()
svdrlsy4

svdrlsy42#

Layers.pop(0)或类似的东西不起作用。
您有两个选项可以尝试:

1.

可以使用所需的图层创建新模型。
一个相对简单的方法是i)提取模型的json配置,ii)适当地更改它,iii)从中创建一个新模型,然后iv)复制权重。我只展示基本的想法。

i)提取配置

model_config = model.get_config()

ii)更改配置

input_layer_name = model_config['layers'][0]['name']
model_config['layers'][0] = {
                      'name': 'new_input',
                      'class_name': 'InputLayer',
                      'config': {
                          'batch_input_shape': (None, 300, 300),
                          'dtype': 'float32',
                          'sparse': False,
                          'name': 'new_input'
                      },
                      'inbound_nodes': []
                  }
model_config['layers'][1]['inbound_nodes'] = [[['new_input', 0, 0, {}]]]
model_config['input_layers'] = [['new_input', 0, 0]]

创建新模型

new_model = model.__class__.from_config(model_config, custom_objects={})  # change custom objects if necessary

ii)复制权重

# iterate over all the layers that we want to get weights from
weights = [layer.get_weights() for layer in model.layers[1:]]
for layer, weight in zip(new_model.layers[1:], weights):
    layer.set_weights(weight)

2.

你可以尝试像kerassurgeon这样的库(我正在链接一个与tensorflow keras版本一起工作的fork)。请注意,插入和删除操作仅在某些条件下有效,例如兼容的维度。

from kerassurgeon.operations import delete_layer, insert_layer

model = delete_layer(model, layer_1)
# insert new_layer_1 before layer_2 in a model
model = insert_layer(model, layer_2, new_layer_3)
ippsafx7

ippsafx73#

不幸的是,来自@MilindDeore的解决方案对我不起作用。虽然我可以打印新模型的摘要,但我在预测时收到一个“矩阵大小不兼容”错误。我想这是有道理的,因为密集层的新输入形状与旧密集层权重的形状不匹配。
因此,这里有另一个解决方案。对我来说,关键是使用“_layers”而不是“layers”。后者似乎只返回一个副本。

import keras
import numpy as np

def get_model():
    old_input_shape = (20, 20, 3)
    model = keras.models.Sequential()
    model.add(keras.layers.Conv2D(9, (3, 3), padding="same", input_shape=old_input_shape))
    model.add(keras.layers.MaxPooling2D((2, 2)))
    model.add(keras.layers.Flatten())
    model.add(keras.layers.Dense(1, activation="sigmoid"))
    model.compile(loss='binary_crossentropy', optimizer=keras.optimizers.Adam(lr=0.0001), metrics=['acc'], )
    model.summary()
    return model

def change_model(model, new_input_shape=(None, 40, 40, 3)):
    # replace input shape of first layer
    model._layers[1].batch_input_shape = new_input_shape

    # feel free to modify additional parameters of other layers, for example...
    model._layers[2].pool_size = (8, 8)
    model._layers[2].strides = (8, 8)

    # rebuild model architecture by exporting and importing via json
    new_model = keras.models.model_from_json(model.to_json())
    new_model.summary()

    # copy weights from old model to new one
    for layer in new_model.layers:
        try:
            layer.set_weights(model.get_layer(name=layer.name).get_weights())
        except:
            print("Could not transfer weights for layer {}".format(layer.name))

    # test new model on a random input image
    X = np.random.rand(10, 40, 40, 3)
    y_pred = new_model.predict(X)
    print(y_pred)

    return new_model

if __name__ == '__main__':
    model = get_model()
    new_model = change_model(model)
dsf9zpds

dsf9zpds4#

不幸的是,kerassurgeon不支持我的模型,因为我冻结了图层。我不得不对@MilindDeore的解决方案做一个小的修改-将model.layers.pop(0)替换为model._layers.pop(0),它对我有效。请注意,我在TF 2.0中使用tf.keras。

ujv3wf0j

ujv3wf0j5#

对于Tensorflow 2中的tf.keras,使用tfsurgeon不起作用,因为我有自定义层。
做了什么工作是改变layer._batch_input_size(注意下划线)
有点古怪,但还是完成了任务。

laik7k3q

laik7k3q6#

使用kerassurgeon应该很容易。根据您是通过TensorFlow(tf 2.0及以上版本)使用Keras还是将Keras作为单独的库使用,它需要以不同的方式安装。
对于TF中的Keras:pip install tfkerassurgeonhttps://github.com/Raukk/tf-keras-surgeon)。对于独立Keras:pip install kerassurgeonhttps://github.com/BenWhetton/keras-surgeon
要替换输入(以TF 2.0为例;当前未测试的代码):

from tensorflow import keras  # or import keras for standalone version
from tensorflow.keras.layers import Input

model = keras.models.load_model('my_model.h5')
my_input_tensor = Input(input_shape=(260, 260, 3))

# or kerassurgeon for standalone Keras
from tfkerassurgeon import delete_layer, insert_layer

model = delete_layer(model.layers[0])
# inserts before layer 0
model = insert_layer(model.layers[0], my_input_tensor)
m528fe3b

m528fe3b7#

对于TensorFlow 2,我们可以修改batch_input_shape

model.summary()
model_config = model.get_config()
model_config["layers"][0]["config"]["batch_input_shape"] = (None, 10, 1)
modified_model = tf.keras.Model.from_config(model_config)
modified_model.summary()

相关问题