New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keras model pickle-able but tf.keras model not pickle-able #34697
Comments
Can you please check with nightly version( |
Automatically closing due to lack of recent activity. Please update the issue when new information becomes available, and we will reopen the issue. Thanks! |
@ravikyram I'm still seeing this issue on tensorflow==2.1.0: 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() results in
|
I have tried on colab with TF version 2.1.0-rc2, 2.2.0-dev20200113 and was able to reproduce the issue.Please, find the gist here. Thanks! |
@ravikyram, should keras functional models be picklable too or not? I'd assume if Sequential models are then functional models should too be? Or does functional models have some properties that make them harder to pickle?
|
Hi everyone, System information:
Script to reproduce: 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') Output: TypeError: can't pickle _thread.RLock objects |
…) have new default learning rates" This reverts commit f6edcd5. The switch is blocked: we are hitting tensorflow/tensorflow#34697. Left a comment at tensorflow/tensorflow#34697 (comment)
Here's a fix adapted from http://zachmoshe.com/2017/04/03/pickling-keras-models.html intended for solving the same issue back when Keras models used to not be pickleable. 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 Should I call this code whenever I'm about to pickle a model or can I just call it at the beginning of my application (before creating the model)? |
You can definitely just call it once at the beginning of your app after importing |
Here is an alternative to @epetrovski 's answer that does not require saving to a file: 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) Source: https://docs.python.org/3/library/pickle.html#object.__reduce__ I feel like maybe this could be added to Model? Are there any cases where this would not work? |
@Edwin-Koh1 Could you please refer to the link1 ,link2 and let us know if it helps ? Thanks! |
@Edwin-Koh1 , indeed, the problem seems fixed in TF 2.6.0! 👍 This now works (while it failed in TF 2.5.1): import joblib
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
model = Sequential([Dense(1, input_shape=[42], activation='sigmoid')])
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])
joblib.dump(model, 'model.pkl') |
Glad we could fix it for you @ageron! It should also work with Functional models by the way. @Edwin-Koh1 should we close the issue? |
It works with joblib in TF 2.6.0, but not with pickle, however: import pickle
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
model = Sequential([Dense(1, input_shape=[42], activation='sigmoid')])
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])
with open('model.pkl', 'wb') as f:
pickle.dump(model, f) Raises:
|
Can you try with |
@Edwin-Koh1 Could you please let us know if this issue is resolved for you ? If it is resolved please feel free to move this ticket to closed status .Thank you! |
@adriangb you're right, both the joblib and pickle code examples work with tf-nightly (while only the joblib example worked in 2.6.0). 👍 |
This issue has been automatically marked as stale because it has no recent activity. It will be closed if no further activity occurs. Thank you. |
Closing as stale. Please reopen if you'd like to work on this further. |
Issue resolved |
That really worked for me, But I got an issue while using pickle to load the model, so I should to keep using tensorflow so the pickle load function can load the model. |
Try this instead of pickle.dump or joblilb.dump |
System information
Hello everybody! This is my first post so please forgive me if I have missed something. So I'm trying to use a genetic algorithm to train and evaluate multiple NN architectures so I need to parallelize them on a multi-core CPU. Therefore I have used joblib to try to parallelize this. However, I was stuck on my tf.keras code because it wasn't pickleable. After many hours of debugging I finally realised that the tf.keras models are not pickleable whereas keras models are.
Describe the current behavior
The code below works but if you replaced keras with tf.keras, there will be an error:
Could not pickle the task to send it to the workers.
Describe the expected behavior
Moving forward, tf.keras should be replacing keras and therefore tf.keras should also be pickleable.
Code to reproduce the issue
Other comments
I guess a quick fix would just be to replace all the existing code with tf.keras to just keras but seeing as keras support will be discontinued and absorbed by Tensorflow 2.0, I think this should be fixed.
The text was updated successfully, but these errors were encountered: