简体   繁体   English

Keras 替换输入层

[英]Keras replacing input layer

The code that I have (that I can't change) uses the Resnet with my_input_tensor as the input_tensor.我拥有的代码(我无法更改)使用带有my_input_tensor作为 input_tensor 的my_input_tensor

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

Investigating the source code , ResNet50 function creates a new keras Input Layer with my_input_tensor and then create the rest of the model.调查源代码,ResNet50 函数使用my_input_tensor创建一个新的 keras 输入层,然后创建模型的其余部分。 This is the behavior that I want to copy with my own model.这是我想用我自己的模型复制的行为。 I load my model from h5 file.我从 h5 文件加载我的模型。

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

Since this model already has an Input Layer, I want to replace it with a new Input Layer defined with my_input_tensor .由于这个模型已经有一个输入层,我想用一个用my_input_tensor定义的新输入层替换它。

How can I replace an input layer?如何替换输入层?

When you saved your model using:当您使用以下方法保存模型时:

old_model.save('my_model.h5')

it will save following:它将保存以下内容:

  1. The architecture of the model, allowing to create the model.模型的架构,允许创建模型。
  2. The weights of the model.模型的权重。
  3. The training configuration of the model (loss, optimizer).模型的训练配置(损失、优化器)。
  4. The state of the optimizer, allowing training to resume from where you left before.优化器的状态,允许训练从你之前离开的地方恢复。

So then, when you load the model:那么,当你加载模型时:

res50_model = load_model('my_model.h5')

you should get the same model back, you can verify the same using:你应该得到相同的模型,你可以使用以下方法验证相同的模型:

res50_model.summary()
res50_model.get_weights()

Now you can, pop the input layer and add your own using:现在您可以弹出输入层并使用以下命令添加您自己的层:

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

add new input layer:添加新的输入层:

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()

The solution from @MilindDeore did not work for me, unfortunately.不幸的是,@MilindDeore 的解决方案对我不起作用。 While I can print the summary of the new model, I receive a "Matrix size incompatible" error upon prediction.虽然我可以打印新模型的摘要,但在预测时收到“矩阵大小不兼容”错误。 I guess this makes sense, since the new input shape of the dense layer does not match the shape of the old dense layer weights.我想这是有道理的,因为密集层的新输入形状与旧密集层权重的形状不匹配。

Thus, here is another solution.因此,这是另一种解决方案。 The key for me was to use "_layers" instead of "layers".我的关键是使用“_layers”而不是“layers”。 The latter only seems to return a copy.后者似乎只返回一个副本。

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)

Layers.pop(0) or anything like that doesn't work. Layers.pop(0) 或类似的东西不起作用。

You have two options that you can try:您有两个选项可以尝试:

1. 1.

You can create a new model with the required layers.您可以创建具有所需层的新模型。

A relatively easy way to do this is to i) extract the model json configuration, ii) change it appropriately, iii) create a new model from it, and then iv) copy over the weights.一个相对简单的方法是 i) 提取模型 json 配置,ii) 适当更改它,iii) 从中创建一个新模型,然后 iv) 复制权重。 I'll just show the basic idea.我只会展示基本的想法。

i) extract the configuration i) 提取配置

model_config = model.get_config()

ii) change the configuration 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]]

ii) create a new model ii) 创建一个新模型

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

ii) copy weights 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. 2.

You can try a library like kerassurgeon (I am linking to a fork that works with the tensorflow keras version).你可以尝试像kerassurgeon这样的库(我正在链接到一个适用于 tensorflow keras 版本的叉子)。 Note that insertion and deletion operations only work under certain conditions such as compatible dimensions.请注意,插入和删除操作仅在某些条件下有效,例如兼容维度。

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)

Unfortunately kerassurgeon did not support my model as I had frozen layers.不幸的是,kerassurgeon 不支持我的模型,因为我有冷冻层。 I had to make a small change to @MilindDeore's solution - replace model.layers.pop(0) to model.我不得不对@MilindDeore 的解决方案做一个小改动 - 将 model.layers.pop(0) 替换为模型。 _layers .pop(0) and it worked for me. _layers .pop(0) 对我有用 Note that I am using tf.keras in TF 2.0.请注意,我在 TF 2.0 中使用 tf.keras。

For tf.keras in Tensorflow 2, using tfsurgeon did not work as I had custom layers.对于 Tensorflow 2 中的 tf.keras,使用 tfsurgeon 不起作用,因为我有自定义层。

What did work was changing layer._batch_input_size (note the underscore)所做的工作是改变layer._batch_input_size (注意下划线)

Hacky, but got the job done. Hacky,但完成了工作。

This should be pretty easy with kerassurgeon .使用kerassurgeon这应该很容易。 First you need to install the library;首先你需要安装这个库; depending on if you are using Keras through TensorFlow (with tf 2.0 and up) or Keras as a separate library, it needs to be installed in different ways.取决于您是通过 TensorFlow(使用 tf 2.0 及更高版本)使用 Keras 还是将 Keras 作为单独的库使用,它需要以不同的方式安装。

For Keras in TF: pip install tfkerassurgeon ( https://github.com/Raukk/tf-keras-surgeon ).对于 TF 中的pip install tfkerassurgeonpip install tfkerassurgeon ( https://github.com/Raukk/tf-keras-surgeon )。 For standalone Keras: pip install kerassurgeon ( https://github.com/BenWhetton/keras-surgeon )对于独立的pip install kerassurgeonpip install kerassurgeon ( https://github.com/BenWhetton/keras-surgeon )

To replace the input (example with TF 2.0; currently untested code):替换输入(使用 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM