Based on the MLA-C01 exam guideReport an error
When the model does not fit on one machine, or the data is so large that one GPU would take days, you split training across several machines and GPUs. First, clearly distinguish the two paradigms.
| Aspect | Data Parallel | Model Parallel |
|---|---|---|
| What is split | Data (batch) is distributed per GPU | The model itself is divided across GPUs |
| What each GPU holds | A full copy of the model | Some layers/parameters of the model |
| Problem it solves | Training speed (throughput) | The model does not fit in one GPU's memory |
| Synchronization | Gradients averaged with all-reduce | Activations and gradients passed between stages |
| Typical situation | Lots of data, and the model fits on the GPU | Very large models (billions of parameters) |
To understand "does not fit" precisely, you need to know what occupies GPU memory. Counting only the parameters leads to a wrong judgment.
| What occupies it | Description | Which parallelism reduces it |
|---|---|---|
| Parameters (weights) | The model itself | Tensor/pipeline parallel, parameter sharding |
| Gradients | Needed again at the same size as the parameters | Gradient sharding |
| Optimizer state | Adam-family optimizers hold extra state such as momentum | Optimizer state sharding |
| Activations | Grow in proportion to batch and sequence length | Smaller batch, activation checkpointing |
💡 Related theory: The mathematical basis of data parallel is the linearity of the mini-batch gradient. The gradient of the full batch equals the average of the partial-batch gradients each GPU computes. So if each GPU processes a partial batch with its model copy and then the gradients are summed and averaged with all-reduce, the update is mathematically equivalent to processing a large batch on one machine. Model parallel is different. Because it cuts the computation graph itself, and one GPU's output (activations) becomes the next GPU's input, the dependencies and communication cost between GPUs are inherently larger.
Data parallel is the most common distribution method. Each GPU (or machine) holds a full copy of the model, performs forward/backward on a different slice of data, and then the gradients are gathered and averaged.
[GPU 0] batch slice 0 → gradient g0 ┐
[GPU 1] batch slice 1 → gradient g1 ├─ all-reduce → average ḡ → all GPUs updated identically
[GPU 2] batch slice 2 → gradient g2 ┘
from sagemaker.pytorch import PyTorch
estimator = PyTorch(
entry_point='train.py',
instance_type='ml.p4d.24xlarge',
instance_count=2, # multiple machines
framework_version='2.0', py_version='py310',
distribution={ # enable SageMaker data parallel
'smdistributed': {'dataparallel': {'enabled': True}}
}
)SageMaker Distributed Data Parallel (SMDDP) provides an all-reduce optimized for the AWS network (EFA and so on), so its communication efficiency is better than standard PyTorch DDP. Increasing data parallelism raises throughput almost linearly, but because of communication overhead it is not linear forever.
Even for the same data parallelism, SageMaker lets you choose among several backends through the distribution argument.
| Backend | distribution setting | Characteristics |
|---|---|---|
| SMDDP | {'smdistributed': {'dataparallel': {'enabled': True}}} | All-reduce optimized for the AWS network. Excellent communication efficiency on supported instances |
| PyTorch native distributed | {'torch_distributed': {'enabled': True}} | Standard torch.distributed. Good code portability and works well with FSDP too |
| MPI (Horovod, etc.) | {'mpi': {'enabled': True, 'processes_per_host': 8}} | Framework neutral. When moving existing Horovod code over as is |
Exam perspective: if you see the phrase "a distributed training library optimized for AWS infrastructure," it is SMDDP. Conversely, "almost as is with existing code" points to native distributed/MPI.
| Observation | Cause | Action |
|---|---|---|
| Accuracy dropped after raising GPUs 8x | The effective batch is 8x → the learning rate is relatively too small | Learning-rate scaling (linear scaling, etc.) + warmup |
| Diverges in the first few steps | Initial instability from a large batch + large learning rate | Add a learning-rate warmup period |
| GPUs doubled but speed only 1.2x | All-reduce communication overhead dominates | EFA-capable instances, prefer GPUs per node over the number of nodes |
| Memory to spare but throughput is low | The GPU is waiting for data | Data-loading bottleneck — FSx cache, more workers |
⚠️ Pitfall: When you raise the number of GPUs N-fold with data parallel, the effective batch size also becomes N times larger. If you leave the learning rate as is, convergence may get worse, so you usually adjust the learning rate together (for example, linear scaling). The exam targets the misconception that "just adding GPUs automatically trains better."
Model parallel is used when the model itself does not fit in one GPU's memory. Giant language models with billions to hundreds of billions of parameters are the typical case. Model parallel has two flavors.
estimator = PyTorch(
entry_point='train.py',
instance_type='ml.p4d.24xlarge', instance_count=2,
framework_version='2.0', py_version='py310',
distribution={
'smdistributed': {
'modelparallel': { # SageMaker model parallel
'enabled': True,
'parameters': {'partitions': 4, 'tensor_parallel_degree': 2}
}
}
}
)SageMaker Distributed Model Parallel (SMP) automates model partitioning, pipeline execution, and sharding. Even if the user does not place layers on GPUs by hand, the library sets a partitioning strategy to fit memory.
Large-scale training in practice combines the axes below. What each axis "splits and what it gains" is the distinguishing point on the exam.
| Parallel axis | What is split | What it gains | Communication burden |
|---|---|---|---|
| Data parallel | Batch (data) | Throughput | Gradient all-reduce every step |
| Tensor parallel | Tensor operations of one layer | Memory per GPU ↓ | Very large → used within a node (NVLink) |
| Pipeline parallel | Groups of layers (stages) | Memory per GPU ↓ | Activations passed between stages. Bubbles (idle time) occur |
| Sharding (ZeRO/FSDP family) | Parameters, gradients, optimizer state | Memory per GPU ↓↓ | Communication to gather and scatter parameters when needed |
Hybrid parallelism — match the communication cost to the topology
Node 0 [GPU0 GPU1 GPU2 GPU3] ← within a node: tensor/pipeline parallel (fast NVLink)
│
EFA ← between nodes: data parallel (relatively slow network, all-reduce only)
│
Node 1 [GPU0 GPU1 GPU2 GPU3]Concept: sharding is "an exchange of memory for communication." If you split the parameters into pieces per GPU, memory shrinks a lot in normal times, but just before computing you must gather the needed pieces, and scatter them again afterward. So the higher the sharding stage (optimizer state only → + gradients → + parameters), the more memory shrinks and the more communication grows. It is not "the strongest sharding is best" — the weakest sharding at which the model still fits is usually the fastest.
The core trade-off when splitting a giant model is "memory savings vs communication cost." The finer you split the model, the less memory per GPU, but the more activations and parameters are sent between GPUs, and it gets slower. So in practice "hybrid parallelism" that combines data parallel, tensor parallel, pipeline parallel, and sharding is used. For example, tensor parallel within a node (fast NVLink) and data parallel between nodes (a relatively slow network), matching the communication pattern to the topology.
Distributed training performance is determined not only by the algorithm but by the infrastructure.
S3 (source data)
└─ FSx for Lustre (high-speed cache) → quickly supplies multiple training nodes
Training nodes ── EFA (low-latency network) ── all-reduce / model-parallel communication
Where you intervene differs depending on where the bottleneck is.
| Bottleneck symptom | Real cause | Where to intervene |
|---|---|---|
| GPU utilization is high but it does not scale | All-reduce communication between nodes | EFA-capable instances, increase GPUs per node instead of the node count |
| GPU utilization is low and uneven | Data supply cannot keep up | FSx for Lustre cache, more loader workers, prefetch |
| Tens of minutes of waiting at every training start | File mode copies all the large data | FastFile/Pipe mode or FSx |
| Long training is lost entirely midway | Node failure, Spot interruption | Checkpoints periodically to S3, resume logic |
Concept: scaling efficiency. If throughput becomes N times when you raise the GPUs N-fold, the efficiency is 100%. In reality, because of communication and synchronization it is always below 100%, and it drops as you add nodes. That is why "one node with 8 GPUs" is generally faster than "four nodes with 2 GPUs each" — even with the same GPU count, communication within a node (NVLink) is much faster than communication between nodes. The order is first make the node bigger, then add more nodes.
A research team tried to train a 7-billion-parameter model on a single ml.g5 instance and hit GPU OOM. Adding nodes with data parallel was no use, because each replica still did not fit on one GPU. When they used SMP's model parallel plus sharding to distribute the parameters and optimizer state across the GPUs, it fit in memory, and by adding EFA between nodes and FSx for Lustre for data supply they cut the training time substantially. Lesson: OOM is solved with model parallel, not with adding GPUs (data parallel).
Because distributed training runs for a long time, "what happens if it dies midway" governs the cost in practice.
estimator = PyTorch(
entry_point='train.py', source_dir='src', role=role,
framework_version='2.0', py_version='py310',
instance_type='ml.p4d.24xlarge', instance_count=4,
distribution={'torch_distributed': {'enabled': True}},
checkpoint_s3_uri='s3://my-bucket/ckpt/', # sync the container's checkpoint path with S3
use_spot_instances=True,
max_run=86400,
max_wait=172800,
)Does one model replica fit on 1 GPU?
├─ It fits
│ ├─ But it is slow / the data is large → data parallel (SMDDP, torch_distributed)
│ └─ Data supply cannot keep up → FSx for Lustre + loader workers, prefetch
└─ It does not fit (OOM)
├─ Slightly short → mixed precision · smaller batch + gradient accumulation · activation checkpointing
├─ Very short → sharding (ZeRO/FSDP) → tensor/pipeline parallel (SMP)
└─ Not covered even with several nodes → hybrid parallel + EFAIn the next lesson we look at debugging and profiling, which examine whether training is running well and where it slows down or breaks.
Click a choice to reveal the answer and explanation.
Question 1
The model to train fits comfortably in single-GPU memory, but the dataset is so large that training on one GPU would take days. What is the most suitable distributed strategy?
Question 2
You want to train a 7-billion-parameter model but run out of memory (OOM) on a single GPU. Adding nodes with data parallelism does not solve it. What is the fundamental solution?
Question 3
In data parallelism, increasing the number of GPUs has increased the effective batch size. What commonly needs to be adjusted along with it?
Question 4
All-reduce communication between many GPU nodes has become a bottleneck, reducing the scaling efficiency of distributed training. Which AWS offering provides low-latency, high-bandwidth communication between nodes?
Question 5
You want to supply large training datasets to multiple GPU nodes with high throughput to reduce the data loading bottleneck. Which service is appropriate?