Keras
TensorFlow
multithreading
exception handling
machine learning

Keras Tensorflow - Exception while predicting from multiple threads

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Prediction errors from multiple threads usually come from sharing one Keras model object without a clear concurrency strategy. The exact exception varies by TensorFlow version, but the root issue is usually the same: concurrent access to model-related state that was never designed to be touched from many threads at once. The safest fix is usually architectural, not a magical one-line TensorFlow flag.

Why Shared Prediction Breaks

Older TensorFlow 1.x code depended heavily on a default graph and session, so multithreaded inference often failed with graph or session mismatch errors. TensorFlow 2 removes some of that pain by running eagerly, but that does not make every shared inference path automatically thread-safe.

You can still hit failures when:

  • several threads call the same model at the same time
  • preprocessing code mutates shared arrays or buffers
  • custom layers keep mutable state
  • old TensorFlow 1.x assumptions remain in otherwise newer code

So the question is not only "can TensorFlow do inference" but also "how is this application sharing the model."

The Conservative Fix: Serialize Access

If one model instance must be shared, the simplest reliable fix is a lock around inference:

python
1import threading
2import numpy as np
3import tensorflow as tf
4
5model = tf.keras.Sequential([
6    tf.keras.layers.Input(shape=(4,)),
7    tf.keras.layers.Dense(8, activation="relu"),
8    tf.keras.layers.Dense(1),
9])
10
11model_lock = threading.Lock()
12
13
14def predict_threadsafe(x: np.ndarray):
15    with model_lock:
16        return model(x, training=False).numpy()
17
18
19x = np.random.rand(1, 4).astype("float32")
20print(predict_threadsafe(x))

This does not make inference parallel, but it does make it predictable. For many desktop tools, APIs, and internal services, correctness is the first requirement.

A Better Service Design: One Inference Worker

If many threads need predictions, a dedicated worker thread is often cleaner than letting all request threads touch the model directly.

python
1import queue
2import threading
3import numpy as np
4import tensorflow as tf
5
6model = tf.keras.Sequential([
7    tf.keras.layers.Input(shape=(4,)),
8    tf.keras.layers.Dense(8, activation="relu"),
9    tf.keras.layers.Dense(1),
10])
11
12jobs = queue.Queue()
13
14
15def prediction_worker():
16    while True:
17        item = jobs.get()
18        if item is None:
19            break
20        x, result_queue = item
21        result = model(x, training=False).numpy()
22        result_queue.put(result)
23        jobs.task_done()
24
25
26worker = threading.Thread(target=prediction_worker, daemon=True)
27worker.start()
28
29result_queue = queue.Queue()
30x = np.random.rand(1, 4).astype("float32")
31jobs.put((x, result_queue))
32print(result_queue.get())

This pattern centralizes model ownership. Request threads stay concurrent, but model execution remains controlled.

Direct Model Calls Versus predict

In TensorFlow 2, direct model calls are often simpler than model.predict(...) for programmatic inference:

python
1import numpy as np
2import tensorflow as tf
3
4model = tf.keras.Sequential([
5    tf.keras.layers.Input(shape=(4,)),
6    tf.keras.layers.Dense(8, activation="relu"),
7    tf.keras.layers.Dense(1),
8])
9
10x = np.random.rand(2, 4).astype("float32")
11out = model(x, training=False)
12print(out.numpy())

predict() is still valid, especially for large batched inference jobs, but direct calls make the path more explicit and often easier to control inside application code.

When Processes Are Better Than Threads

If the real goal is parallel throughput rather than just avoiding crashes, separate processes are often more robust than threads. Each process gets its own Python interpreter state and can load its own model instance.

That costs more memory, but it avoids many shared-state issues and is often the better design for production inference services.

Legacy TensorFlow 1.x Cases

If you maintain old TensorFlow 1.x code with explicit sessions and graphs, modern TensorFlow 2 advice does not always translate directly. In those systems, the prediction path often has to stay bound to one graph and one session, or be moved into a managed worker that owns them.

That is why older answers talk about default graphs and backend sessions. They are not wrong; they are just specific to the older execution model.

Common Pitfalls

The biggest mistake is assuming a shared model is automatically safe because prediction is conceptually read-only. Framework internals, custom layers, or preprocessing state may still be mutable.

Another mistake is adding more threads when the real bottleneck is one model instance or one accelerator. That often adds instability without improving throughput.

People also copy TensorFlow 1.x session advice into TensorFlow 2 code without checking whether the application actually uses eager execution.

Finally, do not ignore preprocessing. Even if the model call is safe, shared mutable NumPy buffers can still create race conditions before inference begins.

Summary

  • Shared Keras models can fail under uncontrolled multithreaded inference.
  • A lock around inference is the fastest way to make one shared model safer.
  • A dedicated inference worker is often a cleaner design than many peer threads calling the model directly.
  • Direct model calls with training=False are often clearer than threaded predict() calls.
  • For true parallelism, separate processes are usually more reliable than threads.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.