如何在Keras的Sequential模型中更改输入形状

14

我有一个使用Keras构建的顺序模型。 我想知道如何更改输入的形状。以下是示例:

model = Sequential()
model.add(Dense(32, input_shape=(500,)))
model.add(Dense(10, activation='softmax'))
model.compile(optimizer='rmsprop',
      loss='categorical_crossentropy',
      metrics=['accuracy'])

假设我想使用不同的输入形状构建一个新模型,从概念上来说,它应该是这样的:

model1 = model
model1.layers[0] = Dense(32, input_shape=(250,))

有没有一种方法可以修改模型的输入形状?

3个回答

14

有点相关,希望对某人有所帮助:如果你有一个现有的模型,其中输入是一个占位符,看起来像(无,无,无,3),你可以加载模型,用具体形状的输入替换第一层。当你想在iOS CoreML中使用模型时,这种转换非常有用(在我的情况下,模型的输入是MLMultiArray而不是CVPixelBuffer,模型编译失败)。

from keras.models import load_model
from keras import backend as K
from keras.engine import InputLayer
import coremltools

model = load_model('your_model.h5')

# Create a new input layer to replace the (None,None,None,3) input layer :
input_layer = InputLayer(input_shape=(272, 480, 3), name="input_1")

# Save and convert :
model.layers[0] = input_layer
model.save("reshaped_model.h5")    
coreml_model = coremltools.converters.keras.convert('reshaped_model.h5')    
coreml_model.save('MyPredictor.mlmodel')

5

想一想在那种情况下改变输入形状会意味着什么。

你的第一个模型

model.add(Dense(32, input_shape=(500,)))

该层具有一个非常密集的矩阵,大小为500x32。

如果您将输入更改为250个元素,则该层的矩阵和输入维度将不匹配。

然而,如果您尝试从第一个500个元素输入模型重用上一层的训练参数,则可以通过get_weights获取这些权重。然后,您可以重新构建一个新模型,并使用set_weights在新模型中设置值。

model1 = Sequential()
model1.add(Dense(32, input_shape=(250,)))
model1.add(Dense(10, activation='softmax'))
model1.layers[1].set_weights(model1.layers[1].get_weights())

请记住,模型1的第一层(即model1.layers [0])仍未经过训练


1
有没有一种方法可以保留整个模型,只更改输入层?实际上,我有一个复杂的模型,我想用完整的输入集和部分输入集来训练它,并比较结果。我正在寻找一种方法,在保持模型1中的其余部分相同的情况下修改输入维度(当然除了输入维度和第一层)。 - itamar kanter
我认为不行。就像我说的,尺寸不匹配。如果你想知道你的模型如何处理部分输入,我建议训练一个专门针对部分输入的不同模型。不过,如果你真的想在两种尺寸不同的情况下使用相同的模型,那么你可以考虑使用RNN而不是MLP。 - maz

4

这里是另一种解决方案,无需从头开始定义模型的每一层。对我来说关键是使用“_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)

2
我正在使用TensorFlow 2.8.0版本,但在此版本中_layersbatch_input_shape不可用。只需要进行小的更改即可使其正常工作。我想要更新模型的第0层,即我的功能模型的“Input”节点(层)。 操作如下: model.layers[0]._batch_input_shape = new_input_shape其余代码保持不变。 - Vaibhav Singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接