keras
model checkpointing
TypeError
pickle error
troubleshooting

Checkpointing keras model TypeError can't pickle _thread.lock objects

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

TypeError: can't pickle _thread.lock objects appears during Keras checkpointing when Python tries to serialize an object graph that includes thread synchronization primitives. The issue is common in custom training setups with generators, callbacks, or multiprocessing. The solution is to checkpoint only serializable state and keep non serializable runtime objects out of model save paths.

Why The Error Happens

Keras checkpointing writes model state, and in some workflows the save logic indirectly touches Python objects that are not pickle safe. A _thread.lock instance cannot be serialized by pickle, so checkpointing fails.

Typical sources include:

  • Custom data generators that keep open thread pools.
  • Callback objects storing queue or lock members.
  • Lambda closures capturing thread aware resources.
  • Attempting to pickle an entire training wrapper object instead of model weights.

The key distinction is model state versus runtime state. Runtime state should be recreated, not serialized.

Use ModelCheckpoint For Model State Only

A safe baseline is saving weights or full model files via Keras callbacks without passing non serializable custom objects.

python
1import tensorflow as tf
2
3model = tf.keras.Sequential([
4    tf.keras.layers.Input(shape=(10,)),
5    tf.keras.layers.Dense(32, activation="relu"),
6    tf.keras.layers.Dense(1)
7])
8
9model.compile(optimizer="adam", loss="mse")
10
11x = tf.random.normal((256, 10))
12y = tf.random.normal((256, 1))
13
14checkpoint_cb = tf.keras.callbacks.ModelCheckpoint(
15    filepath="checkpoints/epoch-{epoch:02d}.weights.h5",
16    save_weights_only=True,
17    save_best_only=False
18)
19
20model.fit(x, y, epochs=3, callbacks=[checkpoint_cb], verbose=0)

This pattern avoids pickling custom Python containers and focuses on TensorFlow managed tensors.

Prefer SavedModel Or Keras Native Format

If you need architecture plus weights, use a model save format designed for TensorFlow objects.

python
1import tensorflow as tf
2
3model = tf.keras.Sequential([
4    tf.keras.layers.Input(shape=(4,)),
5    tf.keras.layers.Dense(8, activation="relu"),
6    tf.keras.layers.Dense(2)
7])
8
9model.compile(optimizer="adam", loss="mse")
10model.save("artifacts/my_model.keras")
11
12reloaded = tf.keras.models.load_model("artifacts/my_model.keras")
13print(reloaded(tf.ones((1, 4))))

This avoids ad hoc pickle usage and provides better forward compatibility.

Keep Custom Objects Serializable

If you write custom callbacks, keep state simple and JSON friendly where possible. Do not store locks, open file handles, or active threads in callback fields that may be serialized.

python
1import tensorflow as tf
2
3class MetricsLogger(tf.keras.callbacks.Callback):
4    def __init__(self):
5        super().__init__()
6        self.loss_history = []
7
8    def on_epoch_end(self, epoch, logs=None):
9        logs = logs or {}
10        self.loss_history.append(float(logs.get("loss", 0.0)))
11
12# Safe callback state
13cb = MetricsLogger()

For advanced pipelines, keep threading primitives inside local function scope, not persistent callback attributes.

Distributed And Multiprocessing Considerations

When using multiprocessing data loading, each worker process must construct its own runtime resources. Passing shared lock objects through serialized configs can trigger this error.

Use process safe inputs like file paths and numeric parameters. Recreate queues and worker pools after process startup. Also pin TensorFlow and Python versions consistently across environments to avoid behavior differences.

Troubleshooting Checklist

  1. Reproduce with a minimal model and checkpoint callback.
  2. Remove custom callbacks and generator wrappers temporarily.
  3. Add objects back one by one until failure returns.
  4. Inspect custom objects for lock, queue, file, or thread members.
  5. Replace pickle based saving with native Keras save paths.

This method isolates the problematic object quickly.

Common Pitfalls

  • Pickling full trainer objects that include runtime threads.
  • Storing lock or queue objects in callback instance fields.
  • Combining multiprocessing generators with non serializable closures.
  • Assuming all Python objects referenced in training are checkpoint safe.
  • Using inconsistent TensorFlow versions between training and restore environments.

Summary

  • The error comes from non serializable thread lock objects entering save paths.
  • Save model state with ModelCheckpoint or native Keras model formats.
  • Keep custom callback and generator state serialization friendly.
  • Recreate runtime thread resources instead of serializing them.
  • Debug by reducing to a minimal checkpoint workflow and reintroducing components gradually.

Course illustration
Course illustration

All Rights Reserved.