Suite à la mise à niveau vers Keras 2.0.9, j’utilise l’utilitaire multi_gpu_model
mais je ne peux pas enregistrer mes modèles ni mes meilleurs poids à l’aide de
model.save('path')
L'erreur que je reçois est
TypeError: impossible de décaper les objets du module
Je soupçonne qu'il y a un problème d'accès à l'objet modèle. Y a-t-il un travail autour de ce problème?
Pour être honnête, la solution la plus simple consiste à examiner le modèle parallèle multi-gpu à l’aide de
parallel_model.summary()
(Le modèle parallèle est simplement le modèle après application de la fonction multi_gpu). Cela met clairement en évidence le modèle actuel (dans l’avant-dernière couche, je pense, je ne suis pas sur mon ordinateur pour le moment). Vous pouvez ensuite utiliser le nom de cette couche pour enregistrer le modèle.
model = parallel_model.get_layer('sequential_1)
Souvent, on l'appelle séquentielle_1, mais si vous utilisez une architecture publiée, il peut s'agir de «googlenet» ou de «alexnet». Vous verrez le nom de la couche à partir du résumé.
Ensuite, il est simple de simplement sauvegarder
model.save()
L’approche maximale fonctionne, mais je pense que c’est exagéré.
Rem: vous devrez compiler à la fois le modèle et le modèle parallèle.
Voici une version corrigée qui n'échoue pas lors de la sauvegarde:
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)
Vous pouvez utiliser cette fonction multi_gpu_model
jusqu'à ce que le bogue soit corrigé dans keras. De plus, lors du chargement du modèle, il est important de fournir l'objet module tensorflow:
model = load_model('multi_gpu_model.h5', {'tf': tf})
Le problème est avec la ligne import tensorflow
au milieu de multi_gpu_model
:
def multi_gpu_model(model, gpus):
...
import tensorflow as tf
...
Cela crée une fermeture pour la fonction get_slice
lambda, qui inclut le nombre de gpus (ce qui est ok) et le module tensorflow (non ok). Model save tente de sérialiser toutes les couches, y compris celles qui appellent get_slice
et échoue exactement car tf
se trouve dans la fermeture.
La solution consiste à déplacer l’importation hors de multi_gpu_model
, de sorte que tf
devienne un objet global, bien que toujours nécessaire pour que get_slice
fonctionne. Cela corrige le problème de la sauvegarde, mais lors du chargement, il faut fournir tf
explicitement.
C'est quelque chose qui nécessite un peu de travail en chargeant le poids multi_gpu_model dans le poids du modèle normal. .
#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)
`