Reduce AI Storage Bottlenecks Without Slowing Training
This guide shows you how to reduce storage bottlenecks in AI training pipelines without sacrificing throughput. You’ll learn to identify where storage stalls occur, then apply practical techniques like data streaming, caching, and filesystem tuning to keep your GPUs fed with data. Nothing special is needed beyond access to your training environment and permission to adjust storage settings.
What You’ll Need
- Access to the training cluster or machine (root or sudo for some filesystem settings)
- Knowledge of your current storage setup (local NVMe, network filesystem, object store)
- Ability to modify your data loading code (PyTorch, TensorFlow, or custom)
- Optional: a tool like
iostat,nvidia-smi, ordstatto monitor I/O and GPU utilization
Step-by-Step
- Measure your current bottleneck. Run a training step and watch GPU utilization. If GPU utilization is below 80% while storage I/O is at 100%, you have a storage bottleneck. Use
iostat -x 1to see read/write throughput and queue depth. - Prefer local NVMe over network storage for hot data. If your dataset fits on a local SSD/NVMe, copy it there before training. Network filesystems (NFS, Lustre) add latency per read. Use
rsyncor a parallel copy tool to stage data. - Use a fast data format. Convert your dataset to a format that supports random access and efficient reading, like TFRecord (TensorFlow) or WebDataset (PyTorch). Avoid thousands of small files; pack them into shards of 100-500MB each.
- Implement a data loader with multiple worker processes. In PyTorch, set
num_workers=4or more in your DataLoader. In TensorFlow, usetf.data.Dataset.map(num_parallel_calls=tf.data.AUTOTUNE). This allows prefetching and parallel I/O. - Enable prefetching. Use
prefetchin your data pipeline (e.g.,dataset.prefetch(buffer_size=tf.data.AUTOTUNE)in TensorFlow, orDataLoader(prefetch_factor=2)in PyTorch). This overlaps data loading with GPU computation. - Cache preprocessed data in memory. If your dataset is small enough to fit in RAM (e.g., <10GB), cache it after preprocessing. In PyTorch, use
torch.utils.data.DataLoader(…, pin_memory=True)and considercachein TensorFlow. This eliminates disk reads entirely after the first epoch. - Use asynchronous data loading with a separate queue. Implement a producer-consumer pattern where a background thread reads and preprocesses data while the GPU trains. Libraries like
torch.utils.data.DataLoaderalready do this; ensure you don’t block it with heavy CPU work in the main process. - Optimize filesystem settings. For Linux, mount NVMe with
noatimeto reduce metadata writes. For NFS, increase read-ahead and I/O size (e.g.,mount -o rsize=1048576,wsize=1048576). For ext4, considernodelallocto reduce latency. - Consider using a distributed cache layer. If multiple nodes read the same data, use a shared cache like Alluxio or a simple Redis-based cache to avoid repeated reads from slow storage.
- Monitor and adjust. After applying changes, re-run
iostatand check GPU utilization. Tweak the number of workers, prefetch size, and shard size until GPU utilization is above 90%.
Common Mistakes
- Using too many worker processes, which can saturate CPU and cause context switching overhead. Start with 4-8 and measure.
- Ignoring the cost of decompression. If you use compressed images (JPEG, PNG), the CPU decompression can become the bottleneck. Use uncompressed formats or a fast decoder like Pillow-SIMD.
- Keeping data on a network filesystem when local storage is available. Even with caching, network latency adds up.
- Not using sharded formats. Thousands of small files cause high metadata overhead and slow random access.
- Forgetting to call
prefetchin TensorFlow orpin_memory=Truein PyTorch—these are simple but often missed.
Tips
- Profile your I/O with
strace -cto see system call counts and time. - Use
dstat -dto view disk throughput andnvidia-smito see GPU utilization side-by-side. - If your data is on object storage (S3, GCS), use a caching layer like
s3fswith a local cache directory, or better, download to local disk first. - For very large datasets, use a streaming approach: load only the next batch while the GPU trains, rather than loading the whole dataset into memory.
- Experiment with different shard sizes. Larger shards reduce overhead but may require more RAM to hold buffers.
Troubleshooting
GPU utilization still low after adding workers. Check CPU usage. If CPU is at 100%, you need to reduce preprocessing load or use a faster library. Try converting images to a raw format or using a simpler augmentation pipeline.
Data loading causes OOM (out of memory). Reduce prefetch_factor or num_workers. Also check that you’re not caching the entire dataset in memory unintentionally.
Network filesystem is slow even with tuning. Consider moving to local storage or using a distributed file system designed for AI, like GPFS or BeeGFS. If that’s not possible, increase the client-side read cache.
Training is fast but disk is still 100%. This may be due to write operations (checkpoints, logs). Write checkpoints to a different disk or use asynchronous writes. Also, disable debug logging.
After converting to TFRecord/WebDataset, training slowed down. Check that your shards are not too large (e.g., >1GB) causing slow reads. Also ensure you’re using a sufficient number of readers.
Frequently Asked Questions
What is the ideal number of DataLoader workers?
It depends on your CPU and storage. Start with 4 and increase until GPU utilization plateaus. A good rule of thumb is the number of CPU cores, but not more than 8-16 to avoid overhead.
Should I store data in RAM or on disk?
If your dataset fits in RAM (say <50GB), caching in memory is fastest. Otherwise, use fast NVMe and a sharded format. For datasets larger than RAM, streaming is necessary.
How do I know if storage is the bottleneck?
If GPU utilization is below 80% and disk I/O is near 100% (or network I/O for remote storage), storage is likely the issue. Also, if increasing workers improves throughput, you have a storage bottleneck.
Is it better to use TFRecord or WebDataset?
Both are efficient. TFRecord is native to TensorFlow, WebDataset is more flexible and works well with PyTorch. Choose based on your framework and preference.
Can I use a RAM disk for training data?
Yes, if you have enough RAM. Mount a tmpfs and copy your dataset there. This is fast but volatile; you’ll need to copy again after reboot.
Why is my data loading slow even with NVMe?
It could be due to small file sizes, metadata overhead, or CPU-bound preprocessing. Use a sharded format and profile your preprocessing to find the bottleneck.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.