Keras
GPU computing
parallel processing
deep learning
machine learning

Parallel fitting of multiple Keras Models on single GPU

Master System Design with Codemia

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

Introduction

It is possible to fit multiple Keras models on one GPU at the same time, but "possible" does not mean "faster." On a single GPU, concurrent training usually creates memory pressure and kernel contention, so the right question is whether your models are small enough that the GPU would otherwise sit underutilized.

Understand the tradeoff first

A single GPU can schedule kernels from multiple processes or threads, but it still has fixed compute and memory limits. Running two trainings at once can help when:

  • each model is small
  • each training step leaves the GPU partially idle
  • the bottleneck is CPU input preparation rather than GPU math

It often hurts when:

  • models already saturate the GPU
  • GPU memory is tight
  • each job launches many kernels and competes for the same resources

So parallel fitting on one GPU is a tuning experiment, not a guaranteed optimization.

Set memory growth to avoid greedy allocation

By default, TensorFlow may reserve most of the GPU memory for one process. If you want several models to coexist, enable memory growth.

python
1import tensorflow as tf
2
3gpus = tf.config.list_physical_devices("GPU")
4if gpus:
5    for gpu in gpus:
6        tf.config.experimental.set_memory_growth(gpu, True)

Without this, the first process may grab nearly all GPU memory and block the others immediately.

A process-based pattern is more realistic than thread-based training

If you really want concurrent training jobs, separate processes are usually more predictable than trying to drive several model.fit calls from one Python process.

python
1import multiprocessing as mp
2import tensorflow as tf
3import numpy as np
4
5def train_one(seed: int):
6    gpus = tf.config.list_physical_devices("GPU")
7    if gpus:
8        for gpu in gpus:
9            tf.config.experimental.set_memory_growth(gpu, True)
10
11    tf.keras.utils.set_random_seed(seed)
12
13    x = np.random.rand(1024, 20).astype("float32")
14    y = np.random.randint(0, 2, size=(1024,))
15
16    model = tf.keras.Sequential([
17        tf.keras.layers.Dense(64, activation="relu"),
18        tf.keras.layers.Dense(1, activation="sigmoid"),
19    ])
20
21    model.compile(optimizer="adam", loss="binary_crossentropy")
22    model.fit(x, y, epochs=2, batch_size=64, verbose=0)
23    print(f"done seed={seed}")
24
25if __name__ == "__main__":
26    procs = [mp.Process(target=train_one, args=(s,)) for s in (1, 2)]
27    for p in procs:
28        p.start()
29    for p in procs:
30        p.join()

This pattern is more common in hyperparameter search than in normal model development.

Measure before assuming it helps

If one model already keeps the GPU busy, running two at once often makes both slower. Use real measurements:

  • total wall-clock time
  • GPU utilization
  • memory usage
  • time per epoch

If two concurrent jobs take longer than two serial jobs, concurrency is not helping even though the GPU is technically sharing work.

Often better alternatives

Before parallelizing several fits on one GPU, consider simpler options:

  • run trials sequentially on the same GPU
  • reduce model startup overhead
  • improve the data pipeline with tf.data
  • use distributed search tooling to queue jobs intelligently

For many workflows, serialized training with better pipeline utilization beats naive concurrency.

When concurrency is still useful

Parallel fitting on one GPU is most defensible when:

  • models are tiny
  • training jobs are short-lived experiments
  • one process alone shows low GPU utilization
  • you are running a search workload, not one critical production training job

In those cases, concurrency may improve throughput even if individual jobs become slightly slower.

Common Pitfalls

The most common mistake is assuming that one GPU can train multiple models in parallel with near-linear speedup. Another is forgetting that TensorFlow may preallocate most GPU memory unless memory growth is enabled. Developers also often try thread-based concurrency inside one Python process and then blame Keras when the real problem is GPU contention and Python orchestration overhead. Small benchmarks are frequently misleading because they do not reflect end-to-end throughput under real dataset and model sizes. Finally, teams sometimes parallelize model fitting before measuring single-job utilization, so they optimize a bottleneck they never confirmed.

Summary

  • Multiple Keras fits can share one GPU, but that does not automatically improve throughput.
  • Enable GPU memory growth if several processes must coexist.
  • Prefer process-based concurrency for search-style workloads.
  • Measure wall-clock time, utilization, and memory before deciding concurrency is better.
  • If one model already saturates the GPU, parallel fits usually make things worse.
  • Treat single-GPU parallel training as a conditional optimization, not a default design.

Course illustration
Course illustration

All Rights Reserved.