Keras - Transferlernen - Eingabe-Tensor-Form ändern


14

Dieser Beitrag scheint darauf hinzudeuten, dass das, was ich erreichen möchte, nicht möglich ist. Davon bin ich jedoch nicht überzeugt - angesichts dessen, was ich bereits getan habe, verstehe ich nicht, warum das, was ich tun möchte, nicht erreicht werden kann ...

Ich habe zwei Bilddatensätze, von denen einer Bilder mit Form (480, 720, 3) und der andere Bilder mit Form (540, 960, 3) enthält.

Ich habe ein Modell mit dem folgenden Code initialisiert:

input = Input(shape=(480, 720, 3), name='image_input')

initial_model = VGG16(weights='imagenet', include_top=False)

for layer in initial_model.layers:
    layer.trainable = False

x = Flatten()(initial_model(input))
x = Dense(1000, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(1000, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(14, activation='linear')(x)

model = Model(inputs=input, outputs=x)
model.compile(loss='mse', optimizer='adam', metrics=['mae'])

Nachdem ich dieses Modell für das vorherige Dataset trainiert habe, möchte ich die Eingabe-Tensor-Ebene entfernen und dem Modell einen neuen Eingabe-Tensor voranstellen, dessen Form mit den Bildabmessungen des letzten Datasets übereinstimmt.

model = load_model('path/to/my/trained/model.h5')
old_input = model.pop(0)
new_input = Input(shape=(540, 960, 3), name='image_input')
x = model(new_input)
m = Model(inputs=new_input, outputs=x)
m.save('transfer_model.h5')

was diesen Fehler ergibt:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2506, in save
    save_model(self, filepath, overwrite, include_optimizer)
  File "/home/aicg2/.local/lib/python2.7/site-packages/keras/models.py", line 106, in save_model
    'config': model.get_config()
  File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2322, in get_config
    layer_config = layer.get_config()
  File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2370, in get_config
    new_node_index = node_conversion_map[node_key]
KeyError: u'image_input_ib-0'

In dem von mir verknüpften Beitrag gibt maz an, dass es eine Dimensionsinkongruenz gibt, die verhindert, dass die Eingabeebene eines Modells geändert wird. Wenn dies der Fall ist, wie setze ich dann eine Eingabeebene (480, 720, 3) voran des VGG16-Modells, das (224, 224, 3) Bilder erwartet?

Ich denke, ein wahrscheinlicheres Problem ist, dass die Ausgabe meines früheren Modells etwas anderes erwartet als das, was ich basierend auf dem, was fchollet in diesem Beitrag sagt, gebe . Ich bin syntaktisch verwirrt, aber ich glaube, das gesamte x = Layer()(x)Segment baut die Ebene Stück für Stück aus Eingabe-> Ausgabe auf, und wenn Sie einfach eine andere Eingabe voranstellen, wird sie unterbrochen.

Ich habe aber wirklich keine Ahnung ...

Kann mir jemand bitte erklären, wie ich das erreichen kann, was ich versuche, oder, wenn es nicht möglich ist, mir erklären, warum nicht?


hast du es gelöst
tktktk0711

Antworten:


3

Sie können dies tun, indem Sie eine neue VGG16-Modellinstanz mit der neuen Eingabeform erstellen new_shapeund alle Ebenengewichte kopieren. Der Code ist ungefähr

new_model = VGG16(weights=None, input_shape=new_shape, include_top=False)
for new_layer, layer in zip(new_model.layers[1:], model.layers[1:]):
    new_layer.set_weights(layer.get_weights())

Versuchte dies mit
inceptionV3

@ r-zip Ich bekomme eine Fehlermeldung: Traceback (most recent call last): File "predict_video11.py", line 67, in <module> new_layer.set_weights(layer.get_weights()) File "/usr/local/lib/python2.7/dist-packages/keras/engine/base_layer.py", line 1057, in set_weights 'provided weight shape ' + str(w.shape)) ValueError: Layer weight shape (3, 3, 33, 64) not compatible with provided weight shape (3, 3, 9, 64) und das ist die Eingabeebene, die so verwendet wird [2:]?
mLstudent33

1

Die Ausgabebreite und -höhe der Ausgabedimensionen von VGGnet ist ein fester Teil der Eingabebreite und -höhe, da die einzigen Ebenen, die diese Dimensionen ändern, die Poolebenen sind. Die Anzahl der Kanäle in der Ausgabe ist auf die Anzahl der Filter in der letzten Faltungsschicht festgelegt. Die Abflachungsebene wird dies umformen, um eine Dimension mit der Form zu erhalten:

((input_width * x) * (input_height * x) * channels)

Dabei ist x eine Dezimalzahl <1.

Der Hauptpunkt ist, dass die Form der Eingabe für die dichten Ebenen von der Breite und Höhe der Eingabe für das gesamte Modell abhängt. Die in die dichte Schicht eingegebene Form kann sich nicht ändern, da dies das Hinzufügen oder Entfernen von Knoten zum neuronalen Netzwerk bedeuten würde.

Eine Möglichkeit, dies zu vermeiden, besteht darin, eine globale Poolebene anstelle einer flachen Ebene (normalerweise GlobalAveragePooling2D) zu verwenden. Auf diese Weise wird der Durchschnitt pro Kanal ermittelt, wodurch die Form der Eingabe in die dichten Ebenen nur so (channels,)ist, dass sie nicht von der Eingabeform abhängt das ganze Modell.

Sobald dies erledigt ist, hängt keine der Ebenen im Netzwerk von der Breite und Höhe der Eingabe ab, sodass die Eingabeebene mit so etwas wie geändert werden kann

input_layer = InputLayer(input_shape=(480, 720, 3), name="input_1")
model.layers[0] = input_layer

0

Hier ist eine andere Lösung, die nicht spezifisch für das VGG-Modell ist.

Beachten Sie, dass die Gewichte der dichten Ebene nicht kopiert werden können (und daher neu initialisiert werden). Dies ist sinnvoll, da die Form der Gewichte beim alten und beim neuen Modell unterschiedlich ist.

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

Dies sollte mit ziemlich einfach sein kerassurgeon. Zuerst müssen Sie die Bibliothek installieren. Je nachdem, ob Sie Keras über TensorFlow (mit tf 2.0 und höher) oder Keras als separate Bibliothek verwenden, muss Keras auf unterschiedliche Weise installiert werden.

Für Keras in TF: pip install tfkerassurgeon( https://github.com/Raukk/tf-keras-surgeon ). Für eigenständige Keras:pip install kerassurgeon ( https://github.com/BenWhetton/keras-surgeon )

So ersetzen Sie die Eingabe (Beispiel mit TF 2.0; derzeit nicht getesteter Code):

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

model = load_model('path/to/my/trained/model.h5')
new_input = Input(shape=(540, 960, 3), name='image_input')

# 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], new_input)

0

@gebbissimo answer hat bei mir in TF2 mit nur kleinen Anpassungen funktioniert, die ich unten in einer einzigen Funktion teile:

def change_input_size(model,h,w,ch=3):
   model._layers[0]._batch_input_shape = (None,h,w,ch)
   new_model = keras.models.model_from_json(model.to_json())
   new_model.summary()
   for layer,new_layer in zip(model.layers,new_model.layers):
      new_layer.set_weights(layer.get_weights())
   return new_model

0

So ändere ich die Eingabegröße im Keras-Modell. Ich habe zwei CNN-Modelle, eines mit der Eingabegröße [None, None, 3], während das andere die Eingabegröße [512,512,3] hat. Beide Modelle haben das gleiche Gewicht. Mit set_weights (model.get_weights ()) können Gewichte von Modell 1 auf Modell 2 übertragen werden

inputs = Input((None, None, 3))
.....
model = Model(inputs=[inputs], outputs=[outputs])
model.compile(optimizer='adam', loss='mean_squared_error')
model.load_weights('my_model_name.h5')

inputs2 = Input((512, 512, 3))
....
model2 = Model(inputs=[inputs2], outputs=[outputs])
model2.compile(optimizer='adam', loss='mean_squared_error')
model2.set_weights(model.get_weights())
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.