web-dev-qa-db-ja.com

Kerasのシーケンシャルモデルで入力形状を変更する方法

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

モデルの入力形状を変更する方法はありますか?

9
itamar kanter

その状況で入力形状を変更するとどうなるかを考えてください。

あなたの最初のモデル

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

Model1の最初のレイヤー(別名model1.layers [0])はまだトレーニングされていないことに注意してください

1
maz

ある程度関連しているので、うまくいけば誰かがこれを役に立つでしょう:たとえば、入力が(None、None、None、3)のようなプレースホルダーである既存のモデルがある場合、モデルをロードして、最初のレイヤーを具体的な形状の入力。この種の変換は、たとえばiOS CoreMLでモデルを使用する場合に非常に役立ちます(私の場合、モデルの入力はCVPixelBufferではなくMLMultiArrayで、モデルのコンパイルは失敗しました)。

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')
11
ohad serfaty

これは、モデルの各レイヤーを最初から定義しない別のソリューションです。私にとっての鍵は、「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)
0
gebbissimo