wake-up-neo.com

Das Modell kann nicht mit model.save im Anschluss an multi_gpu_model in Keras gespeichert werden

Nach dem Upgrade auf Keras 2.0.9 habe ich das Dienstprogramm multi_gpu_model verwendet, aber ich kann meine Modelle oder die besten Gewichte nicht mit speichern 

model.save('path')

Den Fehler bekomme ich

TypeError: Modulobjekte können nicht ausgewählt werden

Ich vermute, dass es Probleme gibt, Zugriff auf das Modellobjekt zu erhalten. Gibt es eine Arbeit um dieses Problem herum?

5
GhostRider

Um ehrlich zu sein, besteht der einfachste Ansatz darin, das parallele Multi-gpu-Modell mithilfe von zu untersuchen

 parallel_model.summary()

(Das Parallelmodell ist einfach das Modell, nachdem die multi_gpu-Funktion angewendet wurde). Dies zeigt deutlich das tatsächliche Modell (in der vorletzten Schicht - ich bin momentan nicht an meinem Computer). Dann können Sie den Namen dieser Ebene verwenden, um das Modell zu speichern.

 model = parallel_model.get_layer('sequential_1)

Häufig heißt es sequential_1, aber wenn Sie eine veröffentlichte Architektur verwenden, kann es sich um "googlenet" oder "alexnet" handeln. Der Name der Ebene wird in der Zusammenfassung angezeigt. 

Dann ist es einfach zu speichern

 model.save()

Maxims Ansatz funktioniert, aber ich denke der Overkill. 

Rem: Sie müssen sowohl das Modell als auch das parallele Modell kompilieren. 

6
GhostRider

Workaround

Hier ist eine gepatchte Version, die beim Speichern nicht fehlschlägt:

from keras.layers import Lambda, concatenate
from keras import Model
import tensorflow as tf

def multi_gpu_model(model, gpus):
  if isinstance(gpus, (list, Tuple)):
    num_gpus = len(gpus)
    target_gpu_ids = gpus
  else:
    num_gpus = gpus
    target_gpu_ids = range(num_gpus)

  def get_slice(data, i, parts):
    shape = tf.shape(data)
    batch_size = shape[:1]
    input_shape = shape[1:]
    step = batch_size // parts
    if i == num_gpus - 1:
      size = batch_size - step * i
    else:
      size = step
    size = tf.concat([size, input_shape], axis=0)
    stride = tf.concat([step, input_shape * 0], axis=0)
    start = stride * i
    return tf.slice(data, start, size)

  all_outputs = []
  for i in range(len(model.outputs)):
    all_outputs.append([])

  # Place a copy of the model on each GPU,
  # each getting a slice of the inputs.
  for i, gpu_id in enumerate(target_gpu_ids):
    with tf.device('/gpu:%d' % gpu_id):
      with tf.name_scope('replica_%d' % gpu_id):
        inputs = []
        # Retrieve a slice of the input.
        for x in model.inputs:
          input_shape = Tuple(x.get_shape().as_list())[1:]
          slice_i = Lambda(get_slice,
                           output_shape=input_shape,
                           arguments={'i': i,
                                      'parts': num_gpus})(x)
          inputs.append(slice_i)

        # Apply model on slice
        # (creating a model replica on the target device).
        outputs = model(inputs)
        if not isinstance(outputs, list):
          outputs = [outputs]

        # Save the outputs for merging back together later.
        for o in range(len(outputs)):
          all_outputs[o].append(outputs[o])

  # Merge outputs on CPU.
  with tf.device('/cpu:0'):
    merged = []
    for name, outputs in Zip(model.output_names, all_outputs):
      merged.append(concatenate(outputs,
                                axis=0, name=name))
    return Model(model.inputs, merged)

Sie können diese multi_gpu_model-Funktion verwenden, bis der Fehler in Keras behoben ist. Beim Laden des Modells ist es außerdem wichtig, das Tensorflow-Modulobjekt bereitzustellen:

model = load_model('multi_gpu_model.h5', {'tf': tf})

Wie es funktioniert

Das Problem liegt in der import tensorflow-Zeile in der Mitte von multi_gpu_model:

def multi_gpu_model(model, gpus):
  ...
  import tensorflow as tf
  ...

Dadurch wird eine Schließung für die get_slice-Lambda-Funktion erstellt, die die Anzahl der gpus (das ist in Ordnung) und das Tensorflow-Modul (nicht in Ordnung) enthält. Beim Speichern von Modellen wird versucht, alle Layer zu serialisieren, einschließlich derjenigen, die get_slice aufrufen, und schlägt fehl, da tf in der Schließung ist.

Die Lösung besteht darin, den Import aus multi_gpu_model zu verschieben, sodass tf ein globales Objekt wird, obwohl get_slice noch benötigt wird. Dies behebt das Problem des Speicherns, aber beim Laden muss tf explizit angegeben werden.

8
Maxim

Es ist etwas, das etwas umgangen werden muss, indem das multi_gpu_model-Gewicht auf das reguläre Modellgewicht geladen wird. Z.

#1, instantiate your base model on a cpu
with tf.device("/cpu:0"):
    model = create_model()

#2, put your model to multiple gpus, say 2
multi_model = multi_gpu_model(model, 2)

#3, compile both models
model.compile(loss=your_loss, optimizer=your_optimizer(lr))
multi_model.compile(loss=your_loss, optimizer=your_optimizer(lr))

#4, train the multi gpu model
# multi_model.fit() or multi_model.fit_generator()

#5, save weights
model.set_weights(multi_model.get_weights())
model.save(filepath=filepath)

`

auffrischung: https://github.com/fchollet/keras/issues/8123

0
Badger Titan