web-dev-qa-db-fra.com

Modèle de points de contrôle: TypeError: impossible de décaper des objets _thread.lock

Il semble que l'erreur s'est produite dans le passé dans différents contextes ici , mais je ne vide pas le modèle directement - j'utilise le rappel ModelCheckpoint. Une idée de ce qui pourrait mal tourner?

Information:

  • Keras version 2.0.8
  • Tensorflow version 1.3.0
  • Python 3.6

Exemple minimal pour reproduire l'erreur:

from keras.layers import Input, Lambda, Dense
from keras.models import Model
from keras.callbacks import ModelCheckpoint
from keras.optimizers import Adam
import tensorflow as tf
import numpy as np

x = Input(shape=(30,3))
low = tf.constant(np.random.Rand(30, 3).astype('float32'))
high = tf.constant(1 + np.random.Rand(30, 3).astype('float32'))
clipped_out_position = Lambda(lambda x, low, high: tf.clip_by_value(x, low, high),
                                      arguments={'low': low, 'high': high})(x)

model = Model(inputs=x, outputs=[clipped_out_position])
optimizer = Adam(lr=.1)
model.compile(optimizer=optimizer, loss="mean_squared_error")
checkpoint = ModelCheckpoint("debug.hdf", monitor="val_loss", verbose=1, save_best_only=True, mode="min")
training_callbacks = [checkpoint]
model.fit(np.random.Rand(100, 30, 3), [np.random.Rand(100, 30, 3)], callbacks=training_callbacks, epochs=50, batch_size=10, validation_split=0.33)

Sortie d'erreur:

Train on 67 samples, validate on 33 samples
Epoch 1/50
10/67 [===>..........................] - ETA: 0s - loss: 0.1627Epoch 00001: val_loss improved from inf to 0.17002, saving model to debug.hdf
Traceback (most recent call last):
  File "debug_multitask_inverter.py", line 19, in <module>
    model.fit(np.random.Rand(100, 30, 3), [np.random.Rand(100, 30, 3)], callbacks=training_callbacks, epochs=50, batch_size=10, validation_split=0.33)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/site-packages/keras/engine/training.py", line 1631, in fit

▽
    validation_steps=validation_steps)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/site-packages/keras/engine/training.py", line 1233, in _fit_loop
    callbacks.on_Epoch_end(Epoch, Epoch_logs)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/site-packages/keras/callbacks.py", line 73, in on_Epoch_end
    callback.on_Epoch_end(Epoch, logs)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/site-packages/keras/callbacks.py", line 414, in on_Epoch_end
    self.model.save(filepath, overwrite=True)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/site-packages/keras/engine/topology.py", line 2556, in save
    save_model(self, filepath, overwrite, include_optimizer)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/site-packages/keras/models.py", line 107, in save_model
    'config': model.get_config()
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/site-packages/keras/engine/topology.py", line 2397, in get_config
    return copy.deepcopy(config)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 215, in _deepcopy_list
    append(deepcopy(a, memo))
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/om/user/lnj/openmind_env/tensorflow-gpu/lib/python3.6/copy.py", line 169, in deepcopy
    rv = reductor(4)
TypeError: can't pickle _thread.lock objects
7
Jess

Lors de l'enregistrement d'un calque Lambda, le arguments transmis sera également enregistré. Dans ce cas, il contient deux tf.Tensor S. Il semble que Keras ne supporte pas actuellement la sérialisation tf.Tensor Dans la configuration du modèle.

Cependant, les tableaux numpy peuvent être sérialisés sans problème. Ainsi, au lieu de passer tf.Tensor Dans arguments, vous pouvez passer des tableaux numpy et les convertir en tf.Tensor S dans la fonction lambda.

x = Input(shape=(30,3))
low = np.random.Rand(30, 3)
high = 1 + np.random.Rand(30, 3)
clipped_out_position = Lambda(lambda x, low, high: tf.clip_by_value(x, tf.constant(low, dtype='float32'), tf.constant(high, dtype='float32')),
                              arguments={'low': low, 'high': high})(x)

Un problème avec les lignes ci-dessus est que, lorsque vous essayez de charger ce modèle, vous pouvez voir un NameError: name 'tf' is not defined. En effet, TensorFlow n'est pas importé dans le fichier où la couche Lambda est reconstruite (core.py).

Changer tf en K.tf Peut résoudre le problème. Vous pouvez également remplacer tf.constant() par K.constant(), qui transforme automatiquement low et high en tenseurs float32.

from keras import backend as K
x = Input(shape=(30,3))
low = np.random.Rand(30, 3)
high = 1 + np.random.Rand(30, 3)
clipped_out_position = Lambda(lambda x, low, high: K.tf.clip_by_value(x, K.constant(low), K.constant(high)),
                              arguments={'low': low, 'high': high})(x)
13
Yu-Yang

Pour clarifier: ce n'est pas un problème de Keras incapable de décaper un tenseur (autres scénarios possibles, voir ci-dessous ) dans une couche Lambda, mais plutôt que les arguments de la fonction python (ici: une fonction lambda) sont tentés d'être sérialisés indépendamment de la fonction (ici: hors du contexte de la lambda fonction elle-même). Cela fonctionne pour les arguments "statiques", mais échoue dans le cas contraire. Pour le contourner, il faut envelopper les arguments de la fonction non statique dans une autre fonction.

Voici quelques solutions de contournement:


  1. Utilisez des variables statiques , telles que les variables python/numpy (juste une mention ci-dessus):
low = np.random.Rand(30, 3)
high = 1 + np.random.Rand(30, 3)

x = Input(shape=(30,3))
clipped_out_position = Lambda(lambda x: tf.clip_by_value(x, low, high))(x)

  1. Utilisez functools.partial Pour envelopper votre fonction lambda:
import functools

clip_by_value = functools.partial(
   tf.clip_by_value,
   clip_value_min=low,
   clip_value_max=high)

x = Input(shape=(30,3))
clipped_out_position = Lambda(lambda x: clip_by_value(x))(x)

  1. Utilisez une fermeture pour envelopper votre fonction lambda:
low = tf.constant(np.random.Rand(30, 3).astype('float32'))
high = tf.constant(1 + np.random.Rand(30, 3).astype('float32'))

def clip_by_value(t):
    return tf.clip_by_value(t, low, high)

x = Input(shape=(30,3))
clipped_out_position = Lambda(lambda x: clip_by_value(x))(x)

Remarque : bien que vous puissiez parfois supprimer la création d'une fonction lambda- explicite et avoir à la place cet extrait de code plus propre:

clipped_out_position = Lambda(clip_by_value)(x)

l'absence d'une couche enveloppante supplémentaire d'une fonction lambda (c'est-à-direlambda t: clip_by_value(t)) pourrait encore conduire à la même chose problème lors de la copie en profondeur des arguments de la fonction, et doit être évité .


  1. Enfin, vous pouvez encapsuler votre logique de modèle dans une couche Keras distincte , qui dans ce cas particulier peut sembler un peu trop conçue:
x = Input(shape=(30,3))
low = Lambda(lambda t: tf.constant(np.random.Rand(30, 3).astype('float32')))(x)
high = Lambda(lambda t: tf.constant(1 + np.random.Rand(30, 3).astype('float32')))(x)
clipped_out_position = Lambda(lambda x: tf.clip_by_value(*x))((x, low, high))

Remarque : letf.clip_by_value(*x) dans la dernière couche Lambda est juste un décompressé argument Tuple, qui peut également être écrit sous une forme plus verbeuse commetf.clip_by_value(x[0], x[1], x[2]) à la place.


( ci-dessous ) En remarque: un tel scénario, où votre fonction lambda essaie de capturer (une partie de) une instance de classe se cassera également la sérialisation (due à liaison tardive ):

class MyModel:
    def __init__(self):
        self.low = np.random.Rand(30, 3)
        self.high = 1 + np.random.Rand(30, 3)

    def run(self):
        x = Input(shape=(30,3))
        clipped_out_position = Lambda(lambda x: tf.clip_by_value(x, self.low, self.high))(x)
        model = Model(inputs=x, outputs=[clipped_out_position])
        optimizer = Adam(lr=.1)
        model.compile(optimizer=optimizer, loss="mean_squared_error")
        checkpoint = ModelCheckpoint("debug.hdf", monitor="val_loss", verbose=1, save_best_only=True, mode="min")
        training_callbacks = [checkpoint]
        model.fit(np.random.Rand(100, 30, 3), 
                 [np.random.Rand(100, 30, 3)], callbacks=training_callbacks, epochs=50, batch_size=10, validation_split=0.33)

MyModel().run()

Ce qui peut être résolu en assurant une liaison anticipée par cette astuce argument par défaut:

        (...)
        clipped_out_position = Lambda(lambda x, l=self.low, h=self.high: tf.clip_by_value(x, l, h))(x)
        (...)
2
Alaroff

Voir mon article à https://github.com/keras-team/keras/issues/8343#issuecomment-4703767 .

Cette exception est levée car vous essayez de sérialiser un tf.tensor, donc toutes les méthodes qui éviteront cette sérialisation fonctionneraient. comprenant:

  • Ne pas le sérialiser: enregistrez uniquement les poids du modèle, car cette sérialisation se produit lorsque vous essayez d'enregistrer la structure du modèle avec la chaîne json/yaml.

  • Éliminez les tenseurs tensorflow: assurez-vous que chaque tenseur de votre modèle est produit par une couche de kéros. Ou utilisez des données ndarray à la place si possible, tout comme ce que @ Yu-Yang a suggéré.

1
Moyan