Tensorflow: Keras-Modell beizbar, aber tf.keras-Modell nicht beizbar

Erstellt am 29. Nov. 2019  ·  34Kommentare  ·  Quelle: tensorflow/tensorflow

System Information

  • Windows 10
  • Tensorflow 2.0 (CPU)
  • joblib 0.14.0
  • Python 3.7.5
  • Keras 2.3.1

Hallo zusammen! Dies ist mein erster Beitrag. Bitte vergib mir, wenn ich etwas verpasst habe. Daher versuche ich, mithilfe eines genetischen Algorithmus mehrere NN-Architekturen zu trainieren und zu bewerten, sodass ich sie auf einer Multi-Core-CPU parallelisieren muss. Deshalb habe ich joblib verwendet, um dies zu parallelisieren. Ich steckte jedoch in meinem tf.keras-Code fest, weil er nicht auswählbar war. Nach vielen Stunden des Debuggens wurde mir endlich klar, dass die tf.keras-Modelle nicht auswählbar sind, während dies bei Keras-Modellen der Fall ist.

Beschreiben Sie das aktuelle Verhalten
Der folgende Code funktioniert, aber wenn Sie Keras durch tf.keras ersetzt haben, tritt ein Fehler auf:
Die Aufgabe konnte nicht erledigt werden, um sie an die Arbeiter zu senden.

Beschreiben Sie das erwartete Verhalten
In Zukunft sollten tf.keras Keras ersetzen und daher sollten tf.keras auch pickelbar sein.

Code zur Reproduktion des Problems

#The following is a simple code to illustrate the problem:
from joblib import Parallel, delayed
import keras
import tensorflow as tf

def test():
    model = keras.models.Sequential()
    return

Parallel(n_jobs=8)(delayed(test)(i) for i in range(10)) #this works as intended

def test_tf():
    model = tf.keras.models.Sequential()
    return

Parallel(n_jobs=8)(delayed(test_tf)(i) for i in range(10)) #this will spit out the error above

Andere Kommentare
Ich denke, eine schnelle Lösung wäre nur, den gesamten vorhandenen Code durch tf.keras zu ersetzen, aber da die Unterstützung für Keras von Tensorflow 2.0 eingestellt und absorbiert wird, sollte dies behoben werden.

TF 2.2 keras awaiting tensorflower bug

Hilfreichster Kommentar

Hier ist eine Alternative zu @epetrovskis Antwort, für die kein Speichern in einer Datei erforderlich ist:

import pickle

from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense
from tensorflow.python.keras.layers import deserialize, serialize
from tensorflow.python.keras.saving import saving_utils


def unpack(model, training_config, weights):
    restored_model = deserialize(model)
    if training_config is not None:
        restored_model.compile(
            **saving_utils.compile_args_from_training_config(
                training_config
            )
        )
    restored_model.set_weights(weights)
    return restored_model

# Hotfix function
def make_keras_picklable():

    def __reduce__(self):
        model_metadata = saving_utils.model_metadata(self)
        training_config = model_metadata.get("training_config", None)
        model = serialize(self)
        weights = self.get_weights()
        return (unpack, (model, training_config, weights))

    cls = Model
    cls.__reduce__ = __reduce__

# Run the function
make_keras_picklable()

# Create the model
model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])

# Save
with open('model.pkl', 'wb') as f:
    pickle.dump(model, f)

Quelle: https://docs.python.org/3/library/pickle.html#object.__reduce__

Ich habe das Gefühl, dass dies vielleicht zu Model hinzugefügt werden könnte. Gibt es Fälle, in denen dies nicht funktionieren würde?

Alle 34 Kommentare

@ Edwin-Koh1

Können Sie bitte mit der nächtlichen Version ( !pip install tf-nightly==2.1.0dev20191201 ) prüfen, ob der Fehler weiterhin besteht? In den neuesten nächtlichen Versionen gibt es viele Leistungsverbesserungen. Vielen Dank!

Automatisches Schließen aufgrund fehlender aktueller Aktivitäten. Bitte aktualisieren Sie das Problem, sobald neue Informationen verfügbar sind, und wir werden das Problem erneut öffnen. Vielen Dank!

@ravikyram Ich

import pickle

import tensorflow as tf


def main():
    model_1 = tf.keras.Sequential((
        tf.keras.layers.Dense(16, activation='relu'),
        tf.keras.layers.Dense(1, activation='linear'),
    ))

    _ = model_1(tf.random.uniform((15, 3)))

    model_2 = pickle.loads(pickle.dumps(model_1))

    for w1, w2 in zip(model_1.get_weights(), model_2.get_weights()):
        tf.debugging.assert_equal(w1, w2)


if __name__ == '__main__':
    main()

führt zu

Traceback (most recent call last):
  File "/Users/hartikainen/conda/envs/softlearning-3/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/Users/hartikainen/conda/envs/softlearning-3/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/hartikainen/github/rail-berkeley/softlearning-3/tests/test_pickle_keras_model.py", line 25, in <module>
    main()
  File "/Users/hartikainen/github/rail-berkeley/softlearning-3/tests/test_pickle_keras_model.py", line 18, in main
    model_2 = pickle.loads(pickle.dumps(model_1))
TypeError: can't pickle weakref objects
$ pip freeze | grep "tf\|tensor"
tensorboard==2.1.0
tensorflow==2.1.0
tensorflow-estimator==2.1.0
tensorflow-probability==0.9.0
$ python --version
Python 3.7.5

Ich habe colab mit TF Version 2.1.0-rc2, 2.2.0-dev20200113 ausprobiert und konnte das Problem reproduzieren. Bitte finden Sie das Wesentliche hier . Vielen Dank!

@ravikyram , sollten Keras Funktionsmodelle auch auswählbar sein oder nicht? Ich würde annehmen, wenn sequentielle Modelle funktionale Modelle sind, sollten es auch sein? Oder haben Funktionsmodelle einige Eigenschaften, die das Beizen erschweren?

$ python -m tests.test_pickle_keras_functional_model
2020-01-17 16:47:08.567598: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-01-17 16:47:08.581327: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7fa0a55aa6c0 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-01-17 16:47:08.581362: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Traceback (most recent call last):
  File "/Users/hartikainen/conda/envs/softlearning-3/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/Users/hartikainen/conda/envs/softlearning-3/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/hartikainen/github/rail-berkeley/softlearning-3/tests/test_pickle_keras_functional_model.py", line 20, in <module>
    main()
  File "/Users/hartikainen/github/rail-berkeley/softlearning-3/tests/test_pickle_keras_functional_model.py", line 13, in main
    model_2 = pickle.loads(pickle.dumps(model_1))
TypeError: can't pickle _thread.RLock objects

Hallo allerseits,
Ich versuche, gemäß der Empfehlung unter https://keras.io/ von eigenständigem keras zu tensorflow.keras zu wechseln .
Ich treffe die gleiche Ausnahme wie https://github.com/tensorflow/tensorflow/issues/34697#issuecomment -575705599 mit joblib (wobei pickle unter der Haube verwendet wird).

System Information:

  • Debian 10 (Buster)
  • Python 3.7.6
  • joblib 0.14.1
  • Tensorflow 2.1.0

Zu reproduzierendes Skript:

import joblib
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])
joblib.dump(model, 'model.pkl')

Ausgabe:

TypeError: can't pickle _thread.RLock objects

Hier ist ein Fix, der von http://zachmoshe.com/2017/04/03/pickling-keras-models.html angepasst wurde, um das gleiche Problem zu lösen, als Keras-Modelle früher nicht auswählbar waren.

import pickle
import tempfile
from tensorflow.keras.models import Sequential, load_model, save_model, Model
from tensorflow.keras.layers import Dense

# Hotfix function
def make_keras_picklable():
    def __getstate__(self):
        model_str = ""
        with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
            save_model(self, fd.name, overwrite=True)
            model_str = fd.read()
        d = {'model_str': model_str}
        return d

    def __setstate__(self, state):
        with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
            fd.write(state['model_str'])
            fd.flush()
            model = load_model(fd.name)
        self.__dict__ = model.__dict__


    cls = Model
    cls.__getstate__ = __getstate__
    cls.__setstate__ = __setstate__

# Run the function
make_keras_picklable()

# Create the model
model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])

# Save
with open('model.pkl', 'wb') as f:
    pickle.dump(model, f)

@epetrovski Soll ich diesen Code aufrufen, wenn ich ein Modell

@epetrovski Soll ich diesen Code aufrufen, wenn ich ein Modell

Sie können es definitiv nur einmal am Anfang Ihrer App aufrufen, nachdem Sie tensorflow.keras.models.Model importiert haben. Durch Ausführen der Funktion werden der Klasse tensorflow.keras.models.Model zwei neue Methoden __getstate__() und __setstate__() hinzugefügt, sodass sie jedes Mal funktionieren sollten, wenn Sie ein Mitglied der aktualisierten tf.keras-Modellklasse auswählen möchten - dh. dein eigenes Modell.

Hier ist eine Alternative zu @epetrovskis Antwort, für die kein Speichern in einer Datei erforderlich ist:

import pickle

from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense
from tensorflow.python.keras.layers import deserialize, serialize
from tensorflow.python.keras.saving import saving_utils


def unpack(model, training_config, weights):
    restored_model = deserialize(model)
    if training_config is not None:
        restored_model.compile(
            **saving_utils.compile_args_from_training_config(
                training_config
            )
        )
    restored_model.set_weights(weights)
    return restored_model

# Hotfix function
def make_keras_picklable():

    def __reduce__(self):
        model_metadata = saving_utils.model_metadata(self)
        training_config = model_metadata.get("training_config", None)
        model = serialize(self)
        weights = self.get_weights()
        return (unpack, (model, training_config, weights))

    cls = Model
    cls.__reduce__ = __reduce__

# Run the function
make_keras_picklable()

# Create the model
model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])

# Save
with open('model.pkl', 'wb') as f:
    pickle.dump(model, f)

Quelle: https://docs.python.org/3/library/pickle.html#object.__reduce__

Ich habe das Gefühl, dass dies vielleicht zu Model hinzugefügt werden könnte. Gibt es Fälle, in denen dies nicht funktionieren würde?

Es scheint, dass es zwei Attribute gibt, die in der sequentiellen Klasse nicht ausgewählt werden können. Dieser Fix hat auch bei mir funktioniert:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

class PickableSequential(Sequential):
    def __getstate__(self):
        state = super().__getstate__()
        state.pop("_trackable_saver")
        state.pop("_compiled_trainable_state")
        return state

model = PickableSequential(Dense(10))

import pickle

pickle.dumps(model)
~                     

Ich habe es in colab mit TF Version 2.2, nächtlichen Versionen, versucht und konnte das Problem reproduzieren. Bitte finden Sie das Wesentliche hier. Danke!

Ich habe es in colab mit TF Version 2.2, nächtlichen Versionen, versucht und konnte das Problem reproduzieren. Bitte finden Sie das Wesentliche hier. Danke!

Das Keras-Modell ist auswählbar, aber tf.keras ist nicht auswählbar. Die alternative Lösung hierfür ist der folgende Code: -
Ich habe Ihr Colab-Notizbuch gesehen und die erforderlichen Änderungen vorgenommen. Kopieren Sie einfach den gleichen Code wie unten, und Sie sind mit der Behebung des Fehlers fertig

Tensorflow als tf importieren

def main ():
model_1 = tf.keras.Sequential ((
tf.keras.layers.Dense (16, Aktivierung = 'relu'),
tf.keras.layers.Dense (1, Aktivierung = 'linear'),
))

_ = model_1(tf.random.uniform((15, 3)))
model_1.save('model_2.h5')
model_2 = tf.keras.models.load_model('model_2.h5')

for w1, w2 in zip(model_1.get_weights(), model_2.get_weights()):
    tf.debugging.assert_equal(w1, w2)

if __name__ == '__main__':
Main()

@ Edwin-Koh1

Gemäß dem Vorschlag von hier. Danke!

Hallo allerseits,
Ich versuche, gemäß der Empfehlung unter https://keras.io/ von eigenständigem keras zu tensorflow.keras zu wechseln .
Ich treffe die gleiche Ausnahme wie joblib (das pickle unter der Haube verwendet).

System Information:

  • Debian 10 (Buster)
  • Python 3.7.6
  • joblib 0.14.1
  • Tensorflow 2.1.0

Zu reproduzierendes Skript:

import joblib
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])
joblib.dump(model, 'model.pkl')

Ausgabe:

TypeError: can't pickle _thread.RLock objects

Die Verwendung von pickle oder joblib löst Ihr Problem nicht, da tensorflow.keras dies nicht unterstützt.
Die alternative Lösung hierfür lautet also:

unter Berücksichtigung Ihres Codes: -
Ersetzen Sie diese Zeile: - joblib.dump (model, 'model.pkl')
mit: -
Um das Modell zu speichern, verwenden Sie: -
-----> model.save ('new_model.h5')
und wenn Sie dieses Modell laden möchten, verwenden Sie: -
-----> new_model = tf.keras.models.load_model ('new_model.h5')

unter Berücksichtigung Ihres Codes: -
Ersetzen Sie diese Zeile: - joblib.dump (model, 'model.pkl')
mit: -
Um das Modell zu speichern, verwenden Sie: -
-----> model.save ('new_model.h5')
und wenn Sie dieses Modell laden möchten, verwenden Sie: -
-----> new_model = tf.keras.models.load_model ('new_model.h5')

Dies funktioniert in einigen Fällen, es hilft jedoch nicht, wenn ein Modell als Teil einer anderen Funktion ausgewählt wird. In meinem Fall geschieht dies, wenn die Python-Bibliothek multiprocessing verwendet wird.

@ Edwin-Koh1

Ist das noch ein Problem?
Bitte bestätigen. Danke!

Ist es möglich, das Keras Sequential Model im byteIO-Container abzulegen?

bytes_container = BytesIO()
joblib.dump(Keras_model, bytes_container, protocol=4)
# Error
TypeError: can't pickle _thread.RLock objects

pickle.dump(Keras_model, bytes_container, protocol=4)
# Error
TypeError: can't pickle _thread.RLock objects

dill.dump(Keras_model, bytes_container, protocol=4)
# Error
TypeError: can't pickle tensorflow.python._tf_stack.StackSummary objects

oder in einem tempfile

tempfile.TemporaryFile().write(Keras_model)

oder

save_model(Keras_model, bytes_container)
# Error
TypeError: expected str, bytes or os.PathLike object, not _io.BytesIO

Dies hat perfekt funktioniert, möglicherweise müssen Sie nicht base64 verwenden, damit ich in der Datenbank, die ich erstellt habe, alles im Speicher speichere, keine berührende Festplatte

from io import BytesIO
import dill,base64,tempfile

#Saving Model as base64
model_json = Keras_model.to_json()

def Base64Converter(ObjectFile):
    bytes_container = BytesIO()
    dill.dump(ObjectFile, bytes_container)
    bytes_container.seek(0)
    bytes_file = bytes_container.read()
    base64File = base64.b64encode(bytes_file)
    return base64File

base64KModelJson = Base64Converter(model_json)  
base64KModelJsonWeights = Base64Converter(Keras_model.get_weights())  

#Loading Back
from joblib import load
from keras.models import model_from_json
def ObjectConverter(base64_File):
    loaded_binary = base64.b64decode(base64_File)
    loaded_object = tempfile.TemporaryFile()
    loaded_object.write(loaded_binary)
    loaded_object.seek(0)
    ObjectFile = load(loaded_object)
    loaded_object.close()
    return ObjectFile

modeljson = ObjectConverter(base64KModelJson)
modelweights = ObjectConverter(base64KModelJsonWeights)
loaded_model = model_from_json(modeljson)
loaded_model.set_weights(modelweights)

@hanzigs
Dies ist eine schöne Lösung, danke. Seien Sie nur vorsichtig, wenn Sie dieses Modell weiter trainieren möchten, da diese Methode den Optimierungsstatus nicht beibehält.

@ JohannesAck
Ja, wir müssen mit dem Optimierer kompilieren, bevor wir neue Daten anpassen können. Das sollte nicht zeitaufwändig sein.

Die andere Möglichkeit, model.save zu speichern, ist sehr schwer im Speicher zu speichern.

Eine andere Möglichkeit ist, get_config () und from_config () mit Initialisierung und Kompilierung auszuführen. Dann muss die Anpassung für neue Daten erfolgen.

@ Edwin-Koh1

Jedes Update zu diesem Thema bitte. Danke!

Dieses Problem wurde automatisch als veraltet markiert, da es in letzter Zeit keine Aktivitäten gab. Es wird geschlossen, wenn keine weitere Aktivität stattfindet. Vielen Dank.

unter Berücksichtigung Ihres Codes: -
Ersetzen Sie diese Zeile: - joblib.dump (model, 'model.pkl')
mit: -
Um das Modell zu speichern, verwenden Sie: -
-----> model.save ('new_model.h5')
und wenn Sie dieses Modell laden möchten, verwenden Sie: -
-----> new_model = tf.keras.models.load_model ('new_model.h5')

Dies funktioniert in einigen Fällen, es hilft jedoch nicht, wenn ein Modell als Teil einer anderen Funktion ausgewählt wird. In meinem Fall geschieht dies, wenn die Python-Bibliothek multiprocessing verwendet wird.

@ JohannesAck , ich denke, ich könnte ein ähnliches Problem haben. Ich trainiere ein Keras-Modell auf einer GPU, speichere es mithilfe des TensorFlow SavedModel-Formats mithilfe der Keras-API, lade es in einer neuen Sitzung neu und versuche, mithilfe der multiprocessing -Bibliothek und der starmap parallel Vorhersagen auf mehreren CPUs zu treffen TypeError: can't pickle _thread.RLock objects ). Wenn ich das Modell jedes Mal in meine Vorhersagefunktion lade und es am Ende jedes Funktionsaufrufs lösche, hängt es nach einigen Vorhersagen. Haben Sie eine Idee, was hier los sein könnte?

Schließen als abgestanden. Bitte öffnen Sie erneut, wenn Sie weiter daran arbeiten möchten.

Sind Sie mit der Lösung Ihres Problems zufrieden?
Ja
Nein

Soweit ich weiß, ist das nicht abgestanden.

Am Dienstag, 25. August 2020, 05:26 Uhr Tensorflow-Butler [Bot] <
[email protected]> schrieb:

Sind Sie mit der Lösung Ihres Problems zufrieden?
Ja
https://docs.google.com/forms/d/e/1FAIpQLSfaP12TRhd9xSxjXZjcZFNXPGk4kc1-qMdv3gc6bEP90vY1ew/viewform?entry.85265664=Yes&entry.2137816233=httor//
Nein
https://docs.google.com/forms/d/e/1FAIpQLSfaP12TRhd9xSxjXZjcZFNXPGk4kc1-qMdv3gc6bEP90vY1ew/viewform?entry.85265664=No&entry.2137816233=httor//

- -
Sie erhalten dies, weil Sie kommentiert haben.
Antworte direkt auf diese E-Mail und sieh sie dir auf GitHub an
https://github.com/tensorflow/tensorflow/issues/34697#issuecomment-679941192 ,
oder abbestellen
https://github.com/notifications/unsubscribe-auth/AANMPP2EF3PRKBYRYHOHY3TSCOGTXANCNFSM4JSZ4QSA
.

Ist dies ein WONTFIX, nachdem das Problem jetzt geschlossen wurde?

In meinem Fall kann ich model.save() nicht einfach verwenden, da das Beizen von einem externen Tool aus durchgeführt wird, für das mein Code lediglich ein mit Scikit-Learn kompatibles Modell bereitstellt (meine Klasse bietet eine get_clf -Methode). Ich konnte das Problem umgehen, da mein Code (fast) Keras-kompatibel war (nicht tf.keras) und mit Keras 2.3.1 (TF 1.15.0) das Beizen ohne Probleme funktioniert.

@mimxrt Wenn Sie Keras-Modelle in einer Scikit-Lernumgebung verwenden möchten , SciKeras (vollständige Offenlegung: Ich bin der Autor). Wenn Sie nur nach einer Möglichkeit suchen, Keras-Objekte auswählbar zu machen, überprüfen Sie https://github.com/tensorflow/tensorflow/pull/39609 und insbesondere https://github.com/tensorflow/tensorflow/pull/39609#issuecomment -683370566

Bearbeiten: fester Link

Wir arbeiten derzeit nicht aktiv daran, sondern öffnen es wieder, da es immer noch ein Problem ist.

Schließen als abgestanden. Bitte öffnen Sie erneut, wenn Sie weiter daran arbeiten möchten.

Sind Sie mit der Lösung Ihres Problems zufrieden?
Ja
Nein

Dies wird wieder ins Stocken geraten.

Dieses Problem wurde automatisch als veraltet markiert, da es in letzter Zeit keine Aktivitäten gab. Es wird geschlossen, wenn keine weitere Aktivität stattfindet. Vielen Dank.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen