Pipeline Parallelism › Micro-Batching: Filling the Bubble

Michael BrenndoerferJanuary 20, 20266 min read
Language AI HandbookAll chapters
Part 31 of 67Training Infrastructure
Chapter 224Pipeline Parallelism › Micro-Batching: Filling the Bubble
Reading section 4 of 10 · Micro-Batching: Filling the Bubble · 6 minSection 4 of 10 · 6 min

Book contents

Section 4 of 10 · 6 min read

Pipeline Parallelism › Micro-Batching: Filling the BubbleOne section · Sections in this chapter4 / 10 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

The solution to the bubble problem is to process multiple micro-batches simultaneously. A micro-batch is a small chunk of the full mini-batch. Instead of waiting for one full mini-batch to complete its forward pass before starting the next one, we split the mini-batch into MM equal micro-batches and inject them into the pipeline as fast as the first stage can produce them.

Micro-Batch

A micro-batch is a subdivision of the full training mini-batch. When using pipeline parallelism, the mini-batch is split into MM equal parts. Each part flows through the pipeline independently, and the gradients from all MM micro-batches are accumulated before the optimizer step is applied. From the optimizer's perspective, the result is identical to processing the full mini-batch at once.

The pipeline schedule looks quite different with multiple micro-batches in flight. While S1 is processing micro-batch B2B_2, S2 is simultaneously processing micro-batch B1B_1. While S1 processes B3B_3, S2 processes B2B_2 and S3 processes B1B_1. The stages are kept busy by overlapping the processing of different micro-batches on different stages. The bubble still exists at the beginning and end of the sequence (there is no way to avoid the startup ramp for a strictly sequential pipeline), but the bubble fraction decreases as MM increases because the useful work time grows while the ramp time stays constant.

The key insight is that all MM micro-batches share the same model weights and contribute to the same gradient update. At the end of the pipeline run, all stages have produced their partial gradients, these are accumulated across micro-batches, and the optimizer takes a single parameter update step. From the optimizer's perspective, the pipeline processed one mini-batch of size Btotal=M×BmicroB_{\text{total}} = M \times B_{\text{micro}}. The decomposition into micro-batches is an implementation detail for managing pipeline utilization. It is transparent to the loss function and the optimizer.

One important subtlety is the choice of micro-batch size. Smaller micro-batches mean more micro-batches for the same total mini-batch size, which reduces the bubble fraction. But very small micro-batches can underutilize the GPU's tensor cores. Modern GPU tensor cores achieve peak efficiency when matrix dimensions are large multiples of 8 or 16 (and ideally 64 or 128 for the best hardware utilization on A100s and H100s). A micro-batch with too few sequences may result in matrix multiplications with tiny leading dimensions, causing the GPU to spend most of its time on memory access rather than computation. There is a sweet spot where micro-batches are large enough to keep the GPU's arithmetic units busy but small enough that MM is large enough to suppress the bubble. Finding this sweet spot requires profiling on the specific hardware configuration, though a rule of thumb is that the micro-batch size should be at least 8 sequences for standard transformer models.

Gradient Accumulation and Weight Updates

The relationship between micro-batches, mini-batches, and gradient accumulation is worth understanding precisely, because it affects both memory usage and training stability.

During the forward pass for micro-batch mm, each stage kk computes the activations ak,m\mathbf{a}_{k,m} and passes them to stage k+1k+1. Each stage also stores ak,m\mathbf{a}_{k,m} for use during the backward pass. During the backward pass for micro-batch mm, stage kk receives gradients ∇ak+1,m\nabla \mathbf{a}_{k+1,m} from stage k+1k+1, computes gradients with respect to its own parameters, and passes ∇ak,m\nabla \mathbf{a}_{k,m} to stage k−1k-1.

The parameter gradients are accumulated across micro-batches. After all MM micro-batches have completed their backward passes, stage kk holds the accumulated gradient:

∇Wk=1M∑m=1M∇Wk,m\nabla W_k = \frac{1}{M} \sum_{m=1}^{M} \nabla W_{k,m}

where:

  • ∇Wk\nabla W_k: the accumulated gradient used for the parameter update at stage kk
  • ∇Wk,m\nabla W_{k,m}: the contribution to the gradient from micro-batch mm at stage kk
  • MM: the number of micro-batches per optimizer step

This accumulated gradient is mathematically equivalent to computing the gradient over the full mini-batch simultaneously, assuming the micro-batch splits are uniform and all micro-batches use the same parameter values. The optimizer step then proceeds exactly as it would in single-device training. This equivalence is what makes synchronous pipeline parallelism a valid distributed training strategy: the model sees the same gradient signal it would see in non-pipelined training, just computed in parallel across devices.

One practical consideration is that different micro-batches could in principle encounter different parameter values if weights are updated between micro-batches. The standard synchronous pipeline parallelism approach avoids this by processing all MM micro-batches before taking any weight update step. This ensures gradient coherence: all micro-batches see the same model weights, so their gradients can be averaged. Asynchronous variants that update weights between micro-batches introduce a form of weight staleness, where later micro-batches in the same optimizer step observe slightly different weights than earlier ones. Asynchronous schedules can potentially achieve better device utilization, but the staleness introduces gradient inconsistency that tends to harm convergence for large models. For this reason, synchronous pipeline parallelism is the standard approach in practice.

The Micro-Batch Size and Total Batch Size Relationship

Understanding the relationship between micro-batch size, the number of micro-batches, and the total effective batch size is essential for correctly configuring pipeline parallelism training runs.

If each micro-batch contains BμB_{\mu} sequences and there are MM micro-batches per optimizer step, the total batch size processed per step per pipeline replica is:

Btotal=M×BμB_{\text{total}} = M \times B_{\mu}

When this pipeline is also combined with data parallelism, where RR replicas of the full pipeline are run in parallel, the global effective batch size is:

Bglobal=R×M×BμB_{\text{global}} = R \times M \times B_{\mu}

Large-scale training runs often target a specific global batch size for training stability reasons (the learning rate and its schedule are typically tuned for a specific batch size). Pipeline parallelism and data parallelism together give you multiple levers to hit the target batch size: you can increase MM to reduce the bubble fraction, increase RR to add more data-parallel replicas, and adjust BμB_{\mu} to satisfy hardware utilization constraints. The flexibility to tune these independently, rather than treating the batch size as a single monolithic parameter, is one of the practical benefits of the 3D parallelism approach used by modern large model training frameworks.