Tuesday, June 2, 2026
banner
Top Selling Multipurpose WP Theme

within the knowledge enter pipeline of a machine studying mannequin working on a GPU might be significantly irritating. In most workloads, the host (CPU) and the machine (GPU) work in tandem: the CPU is accountable for making ready and feeding knowledge, whereas the GPU handles the heavy lifting — executing the mannequin, performing backpropagation throughout coaching, and updating weights.

In an excellent scenario, we would like the GPU — the most costly part of our AI/ML infrastructure — to be extremely utilized. This results in sooner growth cycles, decrease coaching prices, and diminished latency in deployment. To realize this, the GPU should be constantly fed with enter knowledge. Particularly, we want to stop the onset of “GPU hunger” — a scenario by which our most costly useful resource lays idle whereas it waits for enter knowledge. Sadly, “GPU hunger” on account of bottlenecks within the knowledge enter pipeline is kind of frequent and may dramatically cut back system effectivity. As such, it’s vital for AI/ML builders to have dependable instruments and methods for diagnosing and addressing such points.

This put up — the eighth in our sequence on the subject of PyTorch Mannequin Efficiency Evaluation and Optimization — introduces a easy caching technique for figuring out bottlenecks within the knowledge enter pipeline. As in earlier posts, we intention to strengthen two key concepts:

  1. AI/ML builders should take accountability for the runtime efficiency of their fashions.
  2. You do not want to be a CUDA or programs knowledgeable to implement important efficiency optimizations.

We’ll begin by outlining among the frequent causes of GPU hunger. Then we’ll introduce our caching-based technique for figuring out and analyzing enter pipeline efficiency points. We’ll shut by reviewing a set of sensible instruments, methods, and methods (TTTs) for overcoming efficiency bottlenecks within the knowledge enter pipeline.

To facilitate our dialogue we are going to outline a toy PyTorch mannequin and an related knowledge enter pipeline. The code that we are going to share is meant for demonstrative functions — please don’t depend on its correctness or optimality. Moreover, please don’t our point out of any device, or approach as an endorsement of its use.

A Toy PyTorch Mannequin

We outline a easy PyTorch-based picture classification mannequin mannequin:

undefined

We outline an artificial dataset with plenty of transformations — deliberately designed to incorporate a extreme enter pipeline bottleneck. For extra particulars on the dataset definition please see this put up.

import numpy as np
from PIL import Picture
from torchvision.datasets.imaginative and prescient import VisionDataset
import torchvision.transforms as T

class FakeDataset(VisionDataset):
    def __init__(self, rework):
        tremendous().__init__(root=None, rework=rework)
        self.dimension = 10000

    def __getitem__(self, index):
        # create a random 1024x1024 picture
        img = Picture.fromarray(np.random.randint(
            low=0,
            excessive=256,
            dimension=(input_img_size[0], input_img_size[1], 3),
            dtype=np.uint8
        ))
        # create a random label
        goal = np.random.randint(low=0, excessive=num_classes, 
                                   dtype=np.uint8).merchandise()
        # Apply tranformations
        img = self.rework(img)
        return img, goal

    def __len__(self):
        return self.dimension

class RandomMask(torch.nn.Module):
    def __init__(self, ratio=0.25):
        tremendous().__init__()
        self.ratio=ratio

    def dilate_mask(self, masks):
        # carry out 4 neighbor dilation on masks
        from scipy.sign import convolve2d
        dilated = convolve2d(masks, [[0, 1, 0],
                                    [1, 1, 1],
                                    [0, 1, 0]], mode='identical').astype(bool)
        return dilated

    def ahead(self, img):
        masks = np.random.uniform(dimension=(img_size, img_size)) < self.ratio
        dilated_mask = torch.unsqueeze(torch.tensor(self.dilate_mask(masks)),0)
        dilated_mask = dilated_mask.broaden(3,-1,-1)
        img[dilated_mask] = 0.
        return img

class ConvertColor(torch.nn.Module):
    def __init__(self):
        tremendous().__init__()
        self.A=torch.tensor(
            [[0.299, 0.587, 0.114],
             [-0.16874, -0.33126, 0.5],
             [0.5, -0.41869, -0.08131]]
        )
        self.b=torch.tensor([0.,128.,128.])

    def ahead(self, img):
        img = img.to(dtype=torch.get_default_dtype())
        img = torch.matmul(self.A,img.view([3,-1])).view(img.form)
        img = img + self.b[:,None,None]
        return img

class Scale(object):
    def __call__(self, img):
        return img.to(dtype=torch.get_default_dtype()).div(255)

rework = T.Compose(
    [T.PILToTensor(),
     T.RandomCrop(img_size),
     RandomMask(),
     ConvertColor(),
     Scale()])

train_set = FakeDataset(rework=rework)
train_loader = torch.utils.knowledge.DataLoader(train_set, batch_size=256,
                                           num_workers=4, pin_memory=True)

Subsequent, we outline the mannequin, loss perform, optimizer, coaching step, and coaching loop, which we wrap with a PyTorch Profiler context manager to seize efficiency knowledge.

from statistics import imply, variance
from time import time

machine = torch.machine("cuda:0")
mannequin = Internet().cuda(machine)
criterion = nn.CrossEntropyLoss().cuda(machine)
optimizer = torch.optim.SGD(mannequin.parameters(), lr=0.001, momentum=0.9)

def train_step(mannequin, criterion, optimizer, inputs, labels):
    outputs = mannequin(inputs)
    loss = criterion(outputs, labels)
    optimizer.zero_grad(set_to_none=True)
    loss.backward()
    optimizer.step()


mannequin.practice()

t0 = time()
instances = []

with torch.profiler.profile(
    schedule=torch.profiler.schedule(wait=10, warmup=2, energetic=10, repeat=1),
    on_trace_ready=torch.profiler.tensorboard_trace_handler('/tmp/prof'),
    record_shapes=True,
    profile_memory=True,
    with_stack=True
) as prof:
    for step, knowledge in enumerate(train_loader):
        # copy knowledge to machine
        inputs = knowledge[0].to(machine=machine, non_blocking=True)
        labels = knowledge[1].to(machine=machine, non_blocking=True)

        # run practice step
        train_step(mannequin, criterion, optimizer, inputs, labels)
        prof.step()
        instances.append(time()-t0)
        t0 = time()
        if step >= 100:
            break

print(f'common time: {imply(instances[1:])}, variance: {variance(instances[1:])}')

For our experiments, we use an Amazon EC2 g5.xlarge occasion (containing an NVIDIA A10G GPU and 4 vCPUs) working a PyTorch (2.6) Deep Learning AMI (DLAMI). Working our toy script on this setting leads to a median throughput of 0.89 steps per second, an underwhelming GPU utilization of twenty-two%, and within the following profiling hint:

Profiling Hint of GPU Hunger (by Writer)

As mentioned intimately in a earlier put up, the profiling hint reveals a transparent sample of GPU hunger — the place the GPU spends most of its time ready for knowledge from the PyTorch DataLoader. This implies that there’s a efficiency bottleneck within the knowledge enter pipeline, which prevents enter batches from being ready shortly sufficient to maintain the GPU absolutely occupied. Importantly, enter pipeline efficiency points can stem from a wide range of sources. Within the case of our toy instance, the reason for the bottleneck will not be obvious from the hint captured above.

A short observe for readers/builders that (regardless of all of our lecturing) stay aversive to using PyTorch Profiler: The info caching-based approach we are going to focus on under will current another manner of figuring out GPU hunger — so don’t despair.

GPU Hunger — Discovering the Root Trigger

On this part, we briefly evaluate frequent causes of efficiency bottlenecks on the enter knowledge pipeline.

Recall, that in a typical mannequin execution circulate:

  1. Uncooked knowledge is is loaded or streamed from storage (e.g., native RAM or disk, a distant community file system, or a cloud-based object retailer equivalent to Amazon S3 or Google Cloud Storage).
  2. It’s then preprocessed on the CPU.
  3. Lastly, the processed knowledge is copied to the GPU for inference or coaching.

Correspondingly, bottlenecks can emerge at every of the next phases:

  1. Gradual knowledge retrieval: There are a number of elements that may restrict how shortly uncooked knowledge might be retrieved by the CPU, together with: the selection of storage backend (e.g., cloud storage vs. native SSD), the accessible community bandwidth, the info format, and extra.
  2. CPU useful resource exhaustion or misuse: Preprocessing duties — equivalent to knowledge augmentation, picture transformations, or decompression — might be CPU-intensive. When the quantity or complexity of those operations exceeds the accessible CPU capability, or if the CPU sources are managed inefficiently (e.g., an in-optimal alternative of variety of staff), a bottleneck can happen. It’s value noting that CPUs are additionally accountable for different model-related duties like loading GPU kernels, reminiscence administration, metric reporting, and extra.
  3. Host-to-device switch bottlenecks: As soon as knowledge is processed, it should be transferred to the GPU. This will turn out to be a bottleneck if knowledge batches are massive relative to the CPU-GPU reminiscence bandwidth, or if the reminiscence copying is carried out inefficiently (e.g., particular person samples are copied moderately than full batches).

The Limitation of Efficiency Profilers

A typical strategy to establish knowledge pipeline bottlenecks is by utilizing a efficiency profiler. Partly 4 of this sequence, Fixing Bottlenecks on the Knowledge Enter Pipeline with PyTorch Profiler and TensorBoard, we demonstrated how to do that utilizing PyTorch’s built-in profiler. Nevertheless, provided that the enter knowledge pipeline runs on the CPU, any Python profiler may very well be used.

The issue with this method is that we sometimes use a number of employee processes for knowledge loading, making efficiency profiling significantly advanced. In our earlier put up, we overcame this by working the data-loading and the mannequin execution in a single course of (i.e., we set the num_workers argument of the DataLoader constructor to zero). Nevertheless, it is a extremely intrusive configuration change that may have a big influence on the general efficiency of our mannequin.

The caching-based methodology we current on this put up goals to pinpoint the supply of the efficiency bottleneck in a far much less intrusive method. Particularly, it’ll allow us to measure the mannequin efficiency with out altering the multi-worker data-loading habits.

Bottleneck Detection by way of Caching

On this part, we suggest a multi-step method for analyzing the efficiency of the enter knowledge pipeline. We’ll display how this methodology might be utilized to our toy coaching workload to establish the causes of the GPU hunger.

Step 1: Cache a Batch on the System

We start by making a single enter batch, copying it to the GPU, after which measuring the runtime efficiency of the mannequin when iterating over simply that batch. This gives a theoretical higher certain on the mannequin’s throughput — i.e., the utmost throughput achievable when the GPU will not be data-starved.

Within the following code block we modify the coaching loop of our toy script in order that it runs on a single batch that’s cached on the GPU:

knowledge = subsequent(iter(train_loader))
inputs = knowledge[0].to(machine=machine, non_blocking=True)
labels = knowledge[1].to(machine=machine, non_blocking=True)
t0 = time()
instances = []
for step in vary(100):
    train_step(mannequin, criterion, optimizer, inputs, labels)
    instances.append(time()-t0)
    t0 = time()

The resultant common throughput is 3.45 steps per second — practically 4 instances greater than our baseline consequence. Not solely does this verify a big knowledge pipeline bottleneck, however it additionally quantifies its influence.

Bonus Tip: Profile and Optimize with System-Cached Knowledge
Working a profiler on a single batch cached on the GPU isolates the mannequin execution from the enter pipeline. This helps you establish inefficiencies within the mannequin’s uncooked compute path. Ideally, GPU utilization right here ought to method 100%. In our case, utilization is round 95%, which is suitable.

Step 2: Cache a Batch on the Host (CPU)

Subsequent, we cache a single enter batch on the host (CPU) as an alternative of the machine. Now, every step contains each a reminiscence copy from CPU to GPU and the mannequin execution.

Since PyTorch’s memory pinning permits for asynchronous knowledge transfers, we count on the host-to-device reminiscence copy for batch N+1 to overlap with the mannequin execution on batch N. Consequently, our expectation is that the throughput will likely be in the identical ballpark as within the device-cached case. If not, this could be a transparent indication of a bottleneck within the host to machine reminiscence copy.

The next block of code incorporates our software of this step to our toy mannequin:

knowledge = subsequent(iter(train_loader))
t0 = time()
instances = []
for step in vary(100):
    inputs = knowledge[0].to(machine=machine, non_blocking=True)
    labels = knowledge[1].to(machine=machine, non_blocking=True)
    train_step(mannequin, criterion, optimizer, inputs, labels)
    instances.append(time()-t0)
    t0 = time()

The resultant throughput following this alteration is 3.33 steps per second — a minor drop from the earlier consequence — indicating that the host-to-device switch will not be a bottleneck. We have to preserve in search of the supply of our efficiency bottleneck.

Steps 3 and on: Cache at Intermediate Phases within the Knowledge Pipeline

We proceed our search by “climbing” up the info enter pipeline, caching at numerous intermediate factors to pinpoint the bottleneck. The exact software of this course of will range based mostly on the main points of the pipeline. Suppose the pipeline might be damaged into Okay phases. If caching after stage N yields a considerably worse throughput when caching after stage N+1, we will deduce that that the inclusion of the processing of stage N+1 is what’s slowing us down.

Step 3a: Cache a Single Processed Pattern
Within the code block under, we modify our dataset to cache one absolutely processed pattern. This simulates a pipeline that features knowledge collation and the CPU to GPU knowledge copy.

class FakeDataset(VisionDataset):
    def __init__(self, rework):
        tremendous().__init__(root=None, rework=rework)
        self.dimension = 10000
        self.cache = None

    def __getitem__(self, index):
        if self.cache is None:
            # create a random 1024x1024 picture
            img = Picture.fromarray(np.random.randint(
                low=0,
                excessive=256,
                dimension=(input_img_size[0], input_img_size[1], 3),
                dtype=np.uint8
            ))
            # create a random label
            goal = np.random.randint(low=0, excessive=num_classes,
                                       dtype=np.uint8).merchandise()
            # Apply tranformations
            img = self.rework(img)
            self.cache = img, goal
        return self.cache

The resultant throughput is 3.23 steps per second— nonetheless far greater than our baseline of 0.89. We nonetheless haven’t discovered the perpetrator.

Step 3b: Cache Uncooked Knowledge (Earlier than Transformation)
Subsequent, we modify the dataset in order to cache the uncooked knowledge (e.g., unprocessed picture recordsdata). The enter knowledge pipeline now contains the info transformations, knowledge collation, and the CPU to GPU knowledge copy.

class FakeDataset(VisionDataset):
    def __init__(self, rework):
        tremendous().__init__(root=None, rework=rework)
        self.dimension = 10000
        self.cache = None

    def __getitem__(self, index):
        if self.cache is None:
            # create a random 1024x1024 picture
            img = Picture.fromarray(np.random.randint(
                low=0,
                excessive=256,
                dimension=(input_img_size[0], input_img_size[1], 3),
                dtype=np.uint8
            ))
            # create a random label
            goal = np.random.randint(low=0, excessive=num_classes,
                                       dtype=np.uint8).merchandise()
            self.cache = img, goal
        # Apply tranformations
        img = self.rework(self.cache[0])
        return img, self.cache[1]

This time, the throughput drops sharply — all the way in which all the way down to 1.72 steps per second. We’ve got discovered our first perpetrator: the info transformation perform.

Interim Outcomes

Right here’s a abstract of the experiments to date:

Caching Experiment Outcomes (by Writer)

The outcomes level to a big slowdown launched by the info transformation step. The hole between the uncooked knowledge caching consequence and the baseline additionally means that uncooked knowledge loading could also be one other perpetrator. Let’s start with the info processing bottleneck.

Optimizing the Knowledge Transformation

We now proceed with our newfound discovery of a efficiency bottleneck within the knowledge processing perform. The following logical step can be to interrupt the rework perform into particular person parts and apply our caching approach to every one so as to derive extra perception into the exact sources of our GPU hunger. For the sake of brevity, we are going to skip forward and apply the info processing optimizations mentioned in our earlier put up, Fixing Bottlenecks on the Knowledge Enter Pipeline with PyTorch Profiler and TensorBoard. Please see there for particulars.

Following the info transformation optimizations, the throughput of the cached uncooked knowledge experiment shoots as much as 3.23. We’ve got eradicated the bottleneck within the knowledge processing perform.

Nevertheless, our new baseline throughput (with out caching) turns into 1.28 steps per second, indicating that there stays a bottleneck within the uncooked knowledge loading. That is much like the tip consequence we reached in our earlier put up.

Throughput Following Remodel Optimization (by Writer)

Optimizing Uncooked Knowledge Loading

To resolve the remaining bottleneck, we simulate the optimization demonstrated partly 5 of this sequence, How to Optimize Your DL Data-Input Pipeline with a Custom PyTorch Operator. We do that by lowering the dimensions of our preliminary random picture from 1024×1024 to 256×256. Following, this alteration the tip to finish (un-cached) coaching step will increase to three.23. Drawback solved!

Vital Caveats

We conclude with a number of vital notes and caveats.

  1. A drop in throughput ensuing from inclusion of a sure data-processing step within the knowledge pipeline, doesn’t essentially imply that it’s that particular step that requires optimization. It’s solely attainable that it’s one other step CPU utilization close to the restrict, and the brand new step simply tipped it over.
  2. In case your enter knowledge varies in dimension, throughput from a single cached knowledge pattern or batch of samples might not replicate real-world efficiency.
  3. The identical caveat applies if the AI mannequin contains dynamic, data-dependent , options, e.g., if parts of the mannequin graph are depending on the enter knowledge.

Suggestions, Tips, and Strategies for Addressing Bottlenecks on the Knowledge Enter Pipeline

We conclude this put up with a listing of ideas, methods, and methods for optimizing the info enter pipeline of PyTorch-based AI fashions. This listing is certainly not exhaustive — quite a few extra optimizations exist relying in your particular use case and infrastructure. We divide the optimizations into three classes:

  • Optimizing Uncooked Knowledge Entry/Retrieval
  • Optimizing Knowledge Processing
  • Optimizing Host-to-System Knowledge Switch

Optimizing Uncooked Knowledge Entry/Retrieval

Environment friendly knowledge loading begins with quick and dependable entry to uncooked knowledge. The next ideas will help:

  • Select an occasion kind with ample community ingress bandwidth.
  • Use a quick and cost-effective knowledge storage resolution. Native SSDs are quick however costly. Cloud-based options like S3 supply scalability, however might introduce latency.
  • Maximize storage community egress. Take into account partitioning datasets in S3 or tuning parallel downloads to cut back throttling.
  • Take into account uncooked knowledge compression. Compressing recordsdata can cut back switch time — however be careful for elevated CPU price throughout decompression.
  • Group small samples into bigger recordsdata. This will cut back overhead related to opening and shutting many recordsdata.
  • Use optimized knowledge switch instruments. For instance, s5cmd can considerably outperforms AWS CLI for bulk S3 downloads.
  • Tune knowledge retrieval parameters. Adjusting chunk dimension or concurrency settings can significantly influence learn efficiency.

Addressing Knowledge Processing Bottlenecks

  • Tune the variety of knowledge loading staff and prefetch issue.
  • Each time attainable, offload data-processing to the info preparation part.
  • Select an occasion kind with an optimum CPU/GPU compute ratio.
  • Optimize the order of transformations. For instance, making use of a crop earlier than blurring will likely be sooner blurring the complete sized picture and solely then cropping.
  • Leverage Python acceleration libraries. For instance, Numba and JAX can velocity up pure Python operations by way of JIT compilation.
  • Create customized PyTorch CPU operators the place acceptable (e.g., see here).
  • Take into account including auxiliary CPUs (knowledge servers) — (e.g., see here).
  • Transfer GPU-friendly transforms to the GPU graph. Some transforms (e.g., normalization) might be executed post-loading on the GPU for higher overlap.
  • Tune OS-level thread and reminiscence configurations.

Optimizing the Host to System Knowledge Copy

  • Use memory pinning and non-blocking data copies to prefetch knowledge instantly onto the GPU. Additionally see the devoted CudaDataPrefetcher supplied by TorchTNT.
  • Postpone int8 to float32 datatype conversions to the GPU to cut back reminiscence copy payload by an element of 4.
  • In case your mannequin is utilizing decrease precision floats (e.g., fp16/bfloat16) forged the floats on the CPU to cut back payload by half.
  • Postpone unpacking of one-hot vectors to the GPU — i.e., preserve them as label ids till the final attainable second.
  • When you’ve got many binary values, think about using bitmasks to compress the payload. For instance, in case you have 8 binary maps, contemplate compressing them right into a single uint8.
  • In case your enter knowledge is sparse, think about using sparse data representations.
  • Keep away from pointless padding. Whereas zero-padding is a well-liked approach for coping with variable sized enter samples, it could actually considerably enhance the dimensions of the reminiscence copy. Take into account various choices (e.g., see here).
  • Be sure to will not be copying knowledge that you don’t really want on the GPU!!

Abstract

Whereas GPUs are thought-about important for modern-day AI/ML growth they arrive at a steep worth. When you’ve determined to make the mandatory funding into their acquisition, it would be best to be certain that they’re getting used as a lot as attainable. The very last thing you need is in your GPU to sit down idle, ready for enter knowledge on account of a preventable bottleneck elsewhere within the pipeline.

Sadly, such inefficiencies are all too frequent. On this put up, we launched a easy approach for diagnosing these points by iteratively caching knowledge at totally different phases of the enter pipeline. By isolating the runtime influence of every pipeline part, this methodology helps establish particular bottlenecks — whether or not in uncooked knowledge loading, preprocessing, or host-to-device switch.

In fact, the precise implementation will range throughout tasks and pipelines, however we hope this technique gives a helpful framework for diagnosing and resolving efficiency points in your individual AI/ML workflows.

banner
Top Selling Multipurpose WP Theme

Converter

Top Selling Multipurpose WP Theme

Newsletter

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

banner
Top Selling Multipurpose WP Theme

Leave a Comment

banner
Top Selling Multipurpose WP Theme

Latest

Best selling

22000,00 $
16000,00 $
6500,00 $

Top rated

6500,00 $
22000,00 $
900000,00 $

Products

Knowledge Unleashed
Knowledge Unleashed

Welcome to Ivugangingo!

At Ivugangingo, we're passionate about delivering insightful content that empowers and informs our readers across a spectrum of crucial topics. Whether you're delving into the world of insurance, navigating the complexities of cryptocurrency, or seeking wellness tips in health and fitness, we've got you covered.