tensorflow
GPU memory
training data
machine learning
data storage

tensorflow store training data on GPU memory

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

TensorFlow can place tensors on the GPU, but “store all training data on GPU memory” is usually not the best default strategy. GPU memory is limited and is also needed for model weights, activations, gradients, and temporary workspace buffers. In practice, the right answer is often to keep the full dataset in CPU memory or on disk and feed batches efficiently, only preloading the entire dataset to the GPU when it is genuinely small enough and the training pattern benefits from it.

What It Means to Put Data on the GPU

In TensorFlow, tensors live on devices. If a tensor is created inside a GPU device context, TensorFlow will try to place it on that GPU.

python
1import tensorflow as tf
2import numpy as np
3
4x_np = np.random.rand(1024, 128).astype("float32")
5y_np = np.random.rand(1024, 1).astype("float32")
6
7with tf.device("/GPU:0"):
8    x_gpu = tf.constant(x_np)
9    y_gpu = tf.constant(y_np)
10
11print(x_gpu.device)
12print(y_gpu.device)

This can work well for a small dataset that comfortably fits into available GPU memory.

Why It Is Usually Not the Best General Strategy

GPU memory is far smaller than system RAM on most machines. If you load the entire dataset onto the GPU, you reduce the memory available for:

  • model parameters
  • optimizer state
  • activations during forward pass
  • gradients during backpropagation
  • fused-kernel workspace

That can lead to out-of-memory errors even when the dataset itself would fit, because training needs extra space beyond the raw input tensors.

Good Use Case: Small Fixed Dataset

If the training set is small and reused many times, preloading it to the GPU can reduce repeated host-to-device transfer overhead.

python
1import tensorflow as tf
2import numpy as np
3
4x = np.random.rand(5000, 32).astype("float32")
5y = np.random.randint(0, 2, size=(5000, 1)).astype("float32")
6
7with tf.device("/GPU:0"):
8    x_train = tf.constant(x)
9    y_train = tf.constant(y)
10
11dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(128)
12
13model = tf.keras.Sequential([
14    tf.keras.layers.Input(shape=(32,)),
15    tf.keras.layers.Dense(64, activation="relu"),
16    tf.keras.layers.Dense(1, activation="sigmoid")
17])
18
19model.compile(optimizer="adam", loss="binary_crossentropy")
20model.fit(dataset, epochs=3)

This is reasonable when the dataset is genuinely small and you have verified that memory headroom remains healthy.

Better Default: Stream Efficiently with tf.data

For most real training jobs, the better pattern is to keep the dataset off the GPU and build an efficient pipeline that overlaps input work with model execution.

python
1import tensorflow as tf
2import numpy as np
3
4x = np.random.rand(100000, 32).astype("float32")
5y = np.random.randint(0, 2, size=(100000, 1)).astype("float32")
6
7dataset = (
8    tf.data.Dataset.from_tensor_slices((x, y))
9    .shuffle(10000)
10    .batch(256)
11    .prefetch(tf.data.AUTOTUNE)
12)
13
14model = tf.keras.Sequential([
15    tf.keras.layers.Input(shape=(32,)),
16    tf.keras.layers.Dense(64, activation="relu"),
17    tf.keras.layers.Dense(1, activation="sigmoid")
18])
19
20model.compile(optimizer="adam", loss="binary_crossentropy")
21model.fit(dataset, epochs=3)

This often gives strong performance without the risk of overcommitting GPU memory.

Device Placement Is Not the Same as Input Pipeline Performance

Developers often jump from “the GPU is fast” to “all data should live on the GPU.” That skips the more important question: where is the real bottleneck?

If the bottleneck is:

  • slow file parsing
  • preprocessing in Python
  • missing prefetch
  • low batch size
  • CPU-bound augmentation

then simply moving all data to the GPU may not solve the problem at all.

Watch Memory Growth and OOM Behavior

When experimenting with large tensors on the GPU, it is useful to configure memory growth so TensorFlow does not reserve all GPU memory upfront in some environments.

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

This does not magically create more memory. It just makes allocation behavior less aggressive and sometimes easier to debug.

Hybrid Strategy: Cache Batches, Not the Entire Dataset

Sometimes the right optimization is to cache preprocessed data in CPU memory and keep the GPU fed with prefetching rather than pinning the full dataset on device memory.

python
1dataset = (
2    tf.data.Dataset.from_tensor_slices((x, y))
3    .cache()
4    .shuffle(10000)
5    .batch(256)
6    .prefetch(tf.data.AUTOTUNE)
7)

This often captures much of the performance benefit without spending scarce GPU memory on the entire dataset.

Practical Rule of Thumb

Put the whole dataset on the GPU only when all of these are true:

  1. the dataset is small
  2. preprocessing is minimal
  3. memory headroom is clearly sufficient
  4. you have measured that transfer overhead is a real bottleneck

If those conditions are not met, the safer and usually better approach is a strong tf.data pipeline.

Common Pitfalls

The biggest mistake is assuming GPU memory should hold the entire dataset simply because GPU compute is fast. Another is forgetting that training needs memory for far more than just inputs. Developers also often move data to the GPU before measuring whether input transfer is actually the bottleneck. Finally, preloading a dataset that “barely fits” is risky because a small model change or batch-size increase can tip training into out-of-memory failures.

Summary

  • TensorFlow can place training tensors on the GPU, but that is not usually the best default.
  • Preloading the full dataset onto the GPU only makes sense for genuinely small datasets.
  • Most workloads perform better with an efficient tf.data pipeline and prefetching.
  • GPU memory must also hold model state, activations, gradients, and temporary buffers.
  • Measure the real bottleneck before using GPU memory as a dataset cache.

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.