Guides & benchmarks

Data Streaming for Distributed Training: How to Keep GPUs Fully Utilized

Nov 3, 2026 | Robin Stringer | 12 min read

Share

Data Streaming for Distributed Training: How to Keep GPUs Fully Utilized

Large training datasets can leave GPUs idle and waiting on I/O. In this blog, we show how to stream sharded data from object storage to local NVMe cache.

Why GPUs go idle during large-scale training

GPUs enable fast, parallel operations and typically dominate AI compute costs, so it’s important to constantly feed them data to process. GPU starvation occurs when accelerators that are ready to train instead rest idle as the input pipeline cannot provide the next batch of training data quickly enough.

Teams may witness GPU starvation with standard data loading approaches as the accelerators are faster at processing the data than enterprise NVMe storage can supply it. A drive delivering 14 GB/s in sequential reads provides less than one five hundredth of the bandwidth of the NVIDIA HGX™ B200 or B300 7.7 TB/s onboard memory speeds.

This article will explore leveraging Verda Object Storage, data streaming and local cache memory on multi-node Instant Clusters to maximize GPU and training run efficiency.

What GPU starvation looks like and how to diagnose it

Indicators of GPU starvation include:

  • A high input-wait fraction - training-loop time is blocked waiting for the DataLoader.
  • Low or fluctuating GPU utilization: utilization drops between bursts of compute when the next batches aren’t ready.
  • Poor throughput: low number of data inputs processed every second despite accelerator availability. Throughput may not increase relative to additional GPUs.

Instant Clusters come with a preconfigured Grafana dashboard showing GPU utilization and other metrics. Nvidia’s nvidia-smi is also useful for quick and easy diagnosis. Additional tools include PyTorch Profiler and, for more extensive system-wide performance analysis, Nvidia’s Nsight Systems. Adding metrics and print statements to training runs is also illustrative.

DataLoader limitations

PyTorch's DataLoader provides several tuning options for improving sample-based throughput. Increasing num_workers parallelizes data fetching across CPU cores; setting persistent_workers=True avoids expensive worker respawn overhead between training epochs, and prefetch_factor enables asynchronous batch staging.

However, the underlying sample-based loading model may prove difficult to scale efficiently. Increasing worker counts and prefetch depth raises the amount of data, process state and buffering held in memory at once, while additional workers can bring contention for CPU, storage bandwidth and inter-process communication. DataLoader tuning can lead to diminishing returns for large or throughput-sensitive workloads.

How data streaming works

Data streaming addresses the bottlenecks of DataLoader by using larger, sequential shards rather than staccato loading of data samples from storage. Sharding splits the dataset across distributed nodes or partitions, enabling parallel reads so each shard can be streamed independently without shared state contention. Prefetching means future batches stream asynchronously while current batches execute.

Local caching makes frequently accessed or recently fetched shards available on fast local storage such as NVMe or RAM disks, preventing slower remote fetches and network costs across epochs.

Cold and warm cache

A cold cache run means the required shards are fetched from remote object storage as training progresses and then stored locally. Subsequent warm cache access can reuse those local shards. Cache limits can ensure local storage isn’t overloaded, or additional storage can house extensive caches.

Choosing a format: MosaicML Streaming (MDS), WebDataset, LitData

These libraries use cloud streaming directly from object storage buckets in various file formats for shards including .tar (WebDataset), .mds (MDS) and .bin (LitData). We will use MDS in an end-to-end benchmarking example shortly.

MDS does the heavy lifting of sharding, local caching and distributed partitioning, reducing custom data pipeline code. WebDataset is simple and portable, using .tar shards and sequential streaming. The library achieves high I/O rates and users will take more responsibility for shard layout, distributed sampling and caching behaviour. LitData supports broader data engineering preliminaries to model training, streams raw files directly and optimizes them into chunked datasets. It can also read MDS datasets.

End-to-End on Verda

Let’s walk through a benchmarking example. Our replicable task will be to train a ResNet-18 image classifier on the iNaturalist 2021 mini training dataset of 500,000 images representing 10,000 classes. The benchmark runs training steps including forward pass, loss calculation, backpropagation and optimizer update. These operations are to measure system performance rather than train a model to convergence. We’ll explore the limitations of DataLoaders and whether a streaming data architecture can reduce GPU starvation by capturing various metrics during a measured training window.

A note on measuring GPU utilization: nvidia-smi measures the percentage of the sampling period during which at least one GPU kernel is running. We don’t learn how many streaming multiprocessors (SMs) are busy, or how efficiently they are working. It’s important therefore to interpret utilization alongside training throughput and input-wait metrics.

Setup

The experiments run on an Instant Cluster with a Slinky environment, which offers a preconfigured Slurm environment on top of Kubernetes. This example was written using two nodes of 8 x NVIDIA B300 GPUs each. The experiment can be adapted to fit different clusters with a few configuration changes.

We’ll use Slurm to launch the training runs. If you’re a newcomer to the package, it’s a job scheduler ideal for distributed training across multiple GPUs.

Clone the repository

Shell
git clone https://github.com/verda-cloud/blog.git
cd blog/data-streaming

Repository layout

The code folders include:

  • data_prep - Download, upload and shard conversion scripts.
  • training - Parquet and MDS training benchmarks.
  • slurm - Slurm job scripts.
  • analysis - GPU utilization plotting code.
  • results - Selected logs from our experiments.

Imports

From the repository root:

Shell
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Configure object storage

Verda Object Storage is an S3-compatible system for unstructured data such as datasets, model checkpoints, and media. Buckets and access keys are managed from the Verda console or API, and objects are readable and writable using any S3-compatible tool. To learn more about and set up Verda Object Storage, please see the documentation.

Let’s set some environment variables. Find the relevant details from your storage bucket in the console:

Shell
export VERDA_S3_ENDPOINT="https://YOUR_OBJECT_STORAGE_ENDPOINT"
export VERDA_S3_BUCKET="YOUR_BUCKET"
export VERDA_S3_ACCESS_KEY="YOUR_ACCESS_KEY"
export VERDA_S3_SECRET_KEY="YOUR_SECRET_KEY"

export DATA_PREFIX="inaturalist/data"
export DATA_MDS_PREFIX="inaturalist_mds_v1"

Data

We import the dataset from HuggingFace. We will upload both parquet files for our DataLoader baseline, as well as our MDS shards to our object storage bucket.

Shell
python3 data_prep/download_inaturalist.py 
python3 data_prep/upload_data.py ./downloads/inaturalist --prefix inaturalist # Upload to object storage
export DATA_PREFIX="inaturalist/data" # Change path as appropriate
python3 data_prep/convert_to_mds.py # Convert to MDS and upload

There should now be an inaturalist folder in the root directory.

Dataloader experiments

Our training code is in training/baseline_multinode.py for the DataLoader baseline and training/mds_multinode.py for data streaming. We can run their related Slurm jobs with these commands from the repository root:

Shell
sbatch slurm/baseline.sbatch
sbatch slurm/mds.sbatch

These .sbatch files are the job launchers, communicating to Slurm which resources to reserve, to start GPU monitoring (using nvidia-smi ) and to run the training code.

The MDS job should execute both cold and warm phases within one allocation. To follow the logs, check the job ID Slurm prints:

Shell
tail -f baseline-<JOB_ID>.out
tail -f mds-<JOB_ID>.out  

Running with fewer GPUs

For a single eight-GPU node, change the Slurm node count in slurm/baseline.sbatch to one, and keep eight processes per node. Reduce the GPU allocation and torchrun process count for smaller allocations.

Measurements

We capture various measurements including global throughput, wall time and mean input wait. These and other metrics are described in the results table below.

Results

Metric Description DataLoaders (Parquet) Data streaming (MDS) - cold start Data streaming (MDS) - warm start
Measured sample presentations Samples processed a second during the measured window 204,800 204,800 204,800
Measured wall time Measured training steps completion time 77.63 s 20.54 s 12.95 s
Throughput Images processed a second across all GPUs during measured training 2,638.1 images/s 9,970.7 images/s 15,809 images/s
Max rank time-to-first batch Time until the slowest training process gets its first batch 29.75 s 57.21 s 55.34 s
Mean input wait Average time spent waiting for next data batch 27.1 ms 19.6 ms 0.4 ms
Median input wait Middle waiting time 0.3 ms 0.3 ms 0.3 ms
P95 input wait 95% of batch wait times fall at or below 2.4 ms 33.9 ms 1.0 ms
Mean train time per step Average time executing a step, including DDP communication 361.1 ms 83.1 ms 64.3 ms
Mean total step time Average time for a complete step, including waiting for data and training 388.2 ms 102.7 ms 64.7 ms
Input-wait fraction % of measured step time waiting for next data batch 7% 19.1% 0.7%

The data shows general improvement from DataLoaders to data streaming, with some interesting and unpredictable results. Mean train time per step decreases steadily, however input-wait fraction increases for cold start data streaming. Ultimately, data streaming with warm start greatly improved on all metrics save the mean input wait and time-to-first batch.

Charts plotted from the CSV files of metrics captured by nvidia-smi during the training runs offer a more intuitive look at GPU activity:

In the DataLoaders / Parquet baseline we see drops in individual-GPU utilization, despite generally high activity during training. Some long input waits suggest uneven batch delivery.

For cold-start data streaming, the GPUs still exhibit sharp drops in activity, yet with longer bursts of high utilization above 80%. In the warm start version, GPUs consistently maintain higher utilization.

Finally, let’s compare the image throughput and wall time:

This relatively small experiment of 200 training steps gives a solid indication that implementing data streaming from object storage is a worthwhile experiment to make the most of GPU resources.

When local storage may suffice

For smaller datasets that fit comfortably on local NVMe or SSD storage, traditional PyTorch DataLoaders may be sufficient. If data can be read, transformed and loaded faster than the GPU completes each training step, the workload is compute-bound rather than input-bound, and optimizing the data pipeline may provide little benefit.

For larger workloads, Verda offers Object Storage and on-demand Instant Clusters with either preconfigured Slinky or Managed Kubernetes up to 144× NVIDIA HGX™ B300, 128× NVIDIA HGX™ B200, and 64× NVIDIA HGX™ H200 per cluster, all on InfiniBand. For custom configurations, contact us.

FAQs

What is distributed training?

Model training can be distributed across multiple devices, usually GPUs or other accelerators. Approaches include data parallelism, where devices hold a copy of the model and process different batches of training data; model parallelism, where different parts of the model are trained on different devices and gradients are synched. A model's layers can also be split into stages, with different batches flowing through as if in a factory. Hybrid parallelism involves larger systems that combine data, model and pipeline parallelism.

Distributed training can result in faster training times, manage models or datasets too large for one device, and scale to hundreds or thousands of accelerators.

Where can I find storage for AI training data?

Verda Object Storage, Block Storage, and Shared Filesystem; Major cloud storage providers, Neoclouds and enterprise object platforms. On-premise approaches include building servers, accelerator and storage capacity and adding security, data sovereignty and network layers.

Who provides storage for AI model training?

Verda's Object Storage provides a straightforward path between dataset and model training on single or multiple training nodes. Large cloud providers such as AWS and Azure provide object storage and various model training integrations such as training throughput with caching, lifecycle management and competitive GPU pricing. Enterprise storage options include Everpure's FlashBlade object platforms, VAST Data and IBM Storage Scale.

How much training data is required for machine learning?

It depends! It's important to distinguish between training from scratch, and transfer learning or fine-tuning.

To train a model from scratch typically requires the most data. For example, to train a capable language model from scratch, Terabytes and far beyond have become a realistic starting point. However, to train a narrow model good at classifying online reviews or generating Shakespearean quotes may require megabytes.

Transfer learning means we tweak the last layer of the model on specific data we use to hone the model. A common example is to train pretrained image recognition models to distinguish between specific items, such as images of a particular cuisine, or places. Datasets may be a few gigabytes to terabytes, depending on the complexity of the task and data.

Fine-tuning refers to training an adaptor layer for large models, like a small booklet to add to an encyclopedia. This approach is usually to help add nuance or detail, such as encouraging the model to use a unique voice by providing examples, or to add specific knowledge. Fine-tuning can be done with a few hundred examples (less than 1GB of data). Again, it depends on the complexity of the task.

Who offers cloud-based training clusters?

Verda offers multi-node GPU clusters with InfiniBand interconnect which provision in 20 minutes with managed Slurm or Kubernetes - all self-service with no sales calls necessary.

Hyperscale cloud platforms (AWS, Azure, GCP etc), and specialized providers including CoreWeave, Lambda Labs, Runpod and GMI Cloud.

Spot market providers include Spheron, Vast.ai and TensorDock.

How do leading platforms secure AI training data?

Core security features generally include encryption of data at rest and in transit; zero-trust networking; least-privilege identity access management (IAM) roles; sensitive data redaction or masking. Some providers offer homomorphic encryption, which preserves privacy during computation.

Security obligations tend to be based on a shared responsibility model, whereby the cloud provider handles encryption at the system level; physical security of datacenters, and network protections. Users should pay attention to data classification, access policies and compliance.

Why do GPUs dominate AI training instead of CPUs?

AI training typically features matrix multiplication of numerical representations of data (image pixels, or tokenized words or sentences, for example) by evolving weights and bias values as the model learns to correct itself and make better predictions. Training AI models may require millions, billions or trillions of such operations. GPUs excel at the parallel computation required to perform such operations effectively. Their thousands of cores can achieve far higher throughput than CPUs, which have fewer cores and generally carry out tasks in sequence. Innovation of CPUs to meet parallel operations requirements of neural networks is worth keeping an eye on, however!

These might also interest you

See all