Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›Creating Own LLM›Distributed Training: Data Parallelism and Model Parallelism

Building and Training Your Own LLM

Distributed Training: Data Parallelism and Model Parallelism

Distributed training enables scaling large language models (LLMs) across multiple devices or machines, drastically reducing training time and handling models too large for a single GPU. It matters because modern LLMs require immense computational resources, and distributed training makes it feasible to train them efficiently. You reach for it when your model or dataset exceeds the memory or compute capacity of a single device, or when you need to accelerate training to meet deadlines.

Why Distributed Training is Necessary

Training large language models (LLMs) on a single GPU is often impractical due to two primary constraints: memory and compute. A single GPU has limited memory, which restricts the size of the model you can train. For example, even high-end GPUs with 80GB of memory may struggle to fit a model with billions of parameters. Additionally, training on a single GPU is slow, as the computational workload cannot be parallelized. Distributed training addresses these issues by splitting the workload across multiple devices, allowing you to train larger models faster. The key insight is that neural network training is inherently parallelizable—gradients can be computed independently for different batches of data, and model parameters can be split across devices. This parallelism is the foundation of both data and model parallelism, which we will explore in detail. Understanding why distributed training works requires recognizing that the forward and backward passes in deep learning are embarrassingly parallel operations, meaning they can be divided into smaller tasks with minimal communication overhead.

# Example: Checking GPU memory constraints (run on a single GPU)
import torch

def check_gpu_memory():
    # Get the current GPU device
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    if device.type == 'cuda':
        # Print total and available memory on the GPU
        total_memory = torch.cuda.get_device_properties(0).total_memory / (1024 ** 3)  # in GB
        allocated_memory = torch.cuda.memory_allocated(0) / (1024 ** 3)  # in GB
        free_memory = total_memory - allocated_memory
        print(f"Total GPU Memory: {total_memory:.2f} GB")
        print(f"Allocated Memory: {allocated_memory:.2f} GB")
        print(f"Free Memory: {free_memory:.2f} GB")
    else:
        print("CUDA (GPU) is not available. Running on CPU.")

check_gpu_memory()

Data Parallelism: Splitting the Dataset

Data parallelism is the simplest and most common form of distributed training. The core idea is to split the dataset into smaller batches and distribute these batches across multiple GPUs or machines. Each GPU holds a complete copy of the model and processes its assigned batch independently. After computing the gradients locally, the GPUs communicate to aggregate these gradients (typically by averaging them) and update the model parameters synchronously. This approach works because the gradients computed on different batches are statistically similar, so averaging them yields a good approximation of the true gradient. Data parallelism is effective when the model fits entirely in the memory of a single GPU, but the dataset is too large to process quickly on one device. The primary advantage is its simplicity—it requires minimal changes to the training loop. However, it does introduce communication overhead during gradient synchronization, which can become a bottleneck if the model is very large or the network is slow. To mitigate this, techniques like gradient accumulation or mixed precision training are often used alongside data parallelism.

# Data Parallelism using PyTorch's DistributedDataParallel (DDP)
import torch
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data.distributed import DistributedSampler
from torch.utils.data import DataLoader, TensorDataset

def setup(rank, world_size):
    # Initialize the process group for distributed training
    dist.init_process_group("gloo", rank=rank, world_size=world_size)

def cleanup():
    dist.destroy_process_group()

def train(rank, world_size):
    setup(rank, world_size)
    
    # Create a simple model
    model = torch.nn.Linear(10, 2).to(rank)
    ddp_model = DDP(model, device_ids=[rank])
    
    # Create a synthetic dataset
    dataset = TensorDataset(torch.randn(1000, 10), torch.randn(1000, 2))
    sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)
    dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
    
    # Loss and optimizer
    criterion = torch.nn.MSELoss()
    optimizer = torch.optim.SGD(ddp_model.parameters(), lr=0.01)
    
    # Training loop
    for epoch in range(10):
        sampler.set_epoch(epoch)
        for batch_idx, (data, target) in enumerate(dataloader):
            data, target = data.to(rank), target.to(rank)
            optimizer.zero_grad()
            output = ddp_model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()
            if batch_idx % 10 == 0:
                print(f"Rank {rank}, Epoch {epoch}, Batch {batch_idx}, Loss {loss.item():.4f}")
    
    cleanup()

def main():
    world_size = 2  # Number of GPUs
    mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

if __name__ == "__main__":
    main()

Model Parallelism: Splitting the Model

Model parallelism addresses the limitation of data parallelism—when the model itself is too large to fit in the memory of a single GPU. Instead of replicating the model across devices, model parallelism splits the model into smaller parts and assigns each part to a different GPU. For example, you might place the first half of the layers on GPU 0 and the second half on GPU 1. During the forward pass, data flows sequentially through the GPUs, with each GPU processing its portion of the model before passing the intermediate results to the next GPU. The backward pass works similarly, with gradients flowing back through the GPUs in reverse order. Model parallelism is more complex than data parallelism because it requires careful coordination between devices to ensure data is passed correctly and efficiently. The primary challenge is minimizing the communication overhead between GPUs, as the intermediate activations and gradients must be transferred frequently. This approach is essential for training extremely large models, such as those with hundreds of billions of parameters, where even a single layer may not fit on a single GPU. Model parallelism is often combined with data parallelism (a hybrid approach) to maximize efficiency.

# Model Parallelism: Splitting a model across two GPUs
import torch
import torch.nn as nn

class ModelParallelMLP(nn.Module):
    def __init__(self):
        super(ModelParallelMLP, self).__init__()
        # Split the model into two parts: first half on GPU 0, second half on GPU 1
        self.part1 = nn.Sequential(
            nn.Linear(10, 512),
            nn.ReLU()
        ).to('cuda:0')
        
        self.part2 = nn.Sequential(
            nn.Linear(512, 256),
            nn.ReLU(),
            nn.Linear(256, 2)
        ).to('cuda:1')
    
    def forward(self, x):
        # Move input to GPU 0
        x = x.to('cuda:0')
        # Forward pass through part1 on GPU 0
        x = self.part1(x)
        # Move intermediate output to GPU 1
        x = x.to('cuda:1')
        # Forward pass through part2 on GPU 1
        x = self.part2(x)
        return x

def train_model_parallel():
    model = ModelParallelMLP()
    criterion = nn.MSELoss()
    optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
    
    # Synthetic data
    inputs = torch.randn(32, 10).to('cuda:0')
    targets = torch.randn(32, 2).to('cuda:1')
    
    # Training loop
    for epoch in range(10):
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, targets)
        loss.backward()
        optimizer.step()
        print(f"Epoch {epoch}, Loss {loss.item():.4f}")

train_model_parallel()

Hybrid Parallelism: Combining Data and Model Parallelism

Hybrid parallelism combines data parallelism and model parallelism to leverage the strengths of both approaches. This is particularly useful when training very large models that neither fit on a single GPU nor can be efficiently trained with pure data parallelism due to communication bottlenecks. In hybrid parallelism, the model is split across multiple GPUs (model parallelism), and each of these splits is replicated across additional GPUs (data parallelism). For example, you might split a model across 4 GPUs (model parallelism) and then replicate this 4-GPU setup across 8 machines (data parallelism), resulting in 32 GPUs working in parallel. The key advantage of hybrid parallelism is that it allows you to scale both the model size and the batch size simultaneously. However, it introduces significant complexity in managing the communication between GPUs, as you must handle both gradient synchronization (for data parallelism) and intermediate activation transfers (for model parallelism). Frameworks like PyTorch and TensorFlow provide tools to simplify this, such as `DistributedDataParallel` combined with manual model splitting. The challenge lies in balancing the trade-offs between communication overhead and computational efficiency, often requiring experimentation to find the optimal configuration for a given model and hardware setup.

# Hybrid Parallelism: Combining DDP and Model Parallelism
import torch
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data.distributed import DistributedSampler
from torch.utils.data import DataLoader, TensorDataset

class HybridModel(nn.Module):
    def __init__(self, rank):
        super(HybridModel, self).__init__()
        # Split the model across two GPUs (model parallelism)
        if rank == 0:
            self.part = nn.Sequential(
                nn.Linear(10, 512),
                nn.ReLU()
            ).to(f'cuda:{rank}')
        else:
            self.part = nn.Sequential(
                nn.Linear(512, 256),
                nn.ReLU(),
                nn.Linear(256, 2)
            ).to(f'cuda:{rank}')
    
    def forward(self, x):
        if dist.get_rank() == 0:
            x = self.part(x)
            # Send output to GPU 1
            dist.send(x, 1)
            return x
        else:
            # Receive input from GPU 0
            input_shape = (x.size(0), 512)
            x = torch.zeros(input_shape, device=f'cuda:{dist.get_rank()}')
            dist.recv(x, 0)
            x = self.part(x)
            return x

def setup(rank, world_size):
    dist.init_process_group("gloo", rank=rank, world_size=world_size)

def cleanup():
    dist.destroy_process_group()

def train_hybrid(rank, world_size):
    setup(rank, world_size)
    
    # Create model and wrap with DDP (data parallelism)
    model = HybridModel(rank)
    ddp_model = DDP(model, device_ids=[rank])
    
    # Synthetic dataset
    dataset = TensorDataset(torch.randn(1000, 10), torch.randn(1000, 2))
    sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)
    dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
    
    criterion = nn.MSELoss()
    optimizer = torch.optim.SGD(ddp_model.parameters(), lr=0.01)
    
    for epoch in range(10):
        sampler.set_epoch(epoch)
        for batch_idx, (data, target) in enumerate(dataloader):
            data, target = data.to(rank), target.to(rank)
            optimizer.zero_grad()
            output = ddp_model(data)
            if rank == 1:  # Only compute loss on the last GPU
                loss = criterion(output, target)
                loss.backward()
                optimizer.step()
            if batch_idx % 10 == 0 and rank == 1:
                print(f"Rank {rank}, Epoch {epoch}, Batch {batch_idx}, Loss {loss.item():.4f}")
    
    cleanup()

def main():
    world_size = 2  # Number of GPUs (must match model parallelism split)
    mp.spawn(train_hybrid, args=(world_size,), nprocs=world_size, join=True)

if __name__ == "__main__":
    main()

Optimizing Communication and Handling Bottlenecks

The efficiency of distributed training is heavily dependent on minimizing communication overhead between devices. In data parallelism, the primary bottleneck is gradient synchronization, where all GPUs must communicate their gradients to update the model parameters. In model parallelism, the bottleneck is the transfer of intermediate activations and gradients between GPUs during the forward and backward passes. To optimize communication, several strategies can be employed. First, use gradient accumulation to reduce the frequency of synchronization—compute gradients over multiple batches before updating the model. Second, leverage mixed precision training (e.g., FP16) to reduce the size of the data being transferred. Third, use efficient communication libraries like NCCL (NVIDIA Collective Communications Library) for GPU-to-GPU communication, which is optimized for high bandwidth and low latency. Fourth, overlap computation and communication by using asynchronous operations, such as non-blocking sends and receives. Finally, carefully design the model parallelism split to minimize the size of intermediate activations. For example, placing layers with smaller output dimensions earlier in the model can reduce the amount of data transferred between GPUs. Understanding these optimizations is crucial because they directly impact the scalability of distributed training—poor communication strategies can negate the benefits of parallelism, leading to underutilized hardware and longer training times.

# Optimizing Communication with Gradient Accumulation and Mixed Precision
import torch
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.cuda.amp import GradScaler, autocast

def setup(rank, world_size):
    dist.init_process_group("nccl", rank=rank, world_size=world_size)

def cleanup():
    dist.destroy_process_group()

def train_optimized(rank, world_size):
    setup(rank, world_size)
    
    # Model, loss, and optimizer
    model = torch.nn.Linear(10, 2).to(rank)
    ddp_model = DDP(model, device_ids=[rank])
    criterion = torch.nn.MSELoss()
    optimizer = torch.optim.SGD(ddp_model.parameters(), lr=0.01)
    
    # Mixed precision training
    scaler = GradScaler()
    
    # Gradient accumulation
    accumulation_steps = 4
    
    # Synthetic data
    dataset = torch.randn(1000, 10).to(rank)
    targets = torch.randn(1000, 2).to(rank)
    
    # Training loop
    for epoch in range(10):
        optimizer.zero_grad()
        for batch_idx in range(0, len(dataset), 32):
            data = dataset[batch_idx:batch_idx+32]
            target = targets[batch_idx:batch_idx+32]
            
            # Mixed precision forward pass
            with autocast():
                output = ddp_model(data)
                loss = criterion(output, target) / accumulation_steps  # Scale loss for accumulation
            
            # Backward pass with gradient scaling
            scaler.scale(loss).backward()
            
            # Gradient accumulation
            if (batch_idx // 32 + 1) % accumulation_steps == 0:
                scaler.step(optimizer)
                scaler.update()
                optimizer.zero_grad()
        
        if rank == 0:
            print(f"Epoch {epoch}, Loss {loss.item() * accumulation_steps:.4f}")
    
    cleanup()

def main():
    world_size = 2
    mp.spawn(train_optimized, args=(world_size,), nprocs=world_size, join=True)

if __name__ == "__main__":
    main()

Key points

  • Distributed training is necessary because single-GPU training is limited by memory and compute constraints, making it impractical for large models or datasets.
  • Data parallelism splits the dataset across multiple GPUs, with each GPU holding a full copy of the model and synchronizing gradients to update parameters.
  • Model parallelism splits the model itself across multiple GPUs, allowing training of models too large to fit on a single device but introducing communication overhead.
  • Hybrid parallelism combines data and model parallelism to scale both the model size and batch size, but it requires careful management of communication between devices.
  • Communication bottlenecks in distributed training can be mitigated using techniques like gradient accumulation, mixed precision training, and efficient communication libraries.
  • Gradient accumulation reduces the frequency of synchronization by computing gradients over multiple batches before updating the model, improving efficiency.
  • Mixed precision training uses lower-precision data types (e.g., FP16) to reduce memory usage and communication overhead without sacrificing model accuracy.
  • Overlapping computation and communication, such as using non-blocking operations, can further optimize distributed training by hiding latency.

Common mistakes

  • Mistake: Assuming data parallelism alone can handle any model size. Why it's wrong: Data parallelism replicates the model across devices, so the model must fit in a single device's memory. Fix: Combine data parallelism with model parallelism for large models that exceed single-device memory limits.
  • Mistake: Ignoring gradient synchronization overhead in data parallelism. Why it's wrong: All-reduce operations for gradients can become a bottleneck, especially with many devices or slow interconnects. Fix: Use efficient collective communication libraries (e.g., NCCL) and optimize batch sizes to balance computation and communication.
  • Mistake: Placing all layers of a model on a single device in model parallelism. Why it's wrong: This defeats the purpose of model parallelism by not distributing the memory/compute load. Fix: Split the model across devices (e.g., by layers or tensor dimensions) to utilize multiple devices effectively.
  • Mistake: Overlooking device placement for model parallelism. Why it's wrong: Poor placement (e.g., splitting layers across distant devices) increases communication latency. Fix: Place dependent layers on the same device or nearby devices to minimize cross-device communication.
  • Mistake: Using the same batch size for all devices in data parallelism. Why it's wrong: Smaller per-device batch sizes can lead to unstable training or poor GPU utilization. Fix: Scale the global batch size proportionally to the number of devices to maintain effective batch sizes per device.

Interview questions

What is distributed training in the context of creating your own large language model (LLM), and why is it necessary?

Distributed training is the process of training a large language model across multiple computing devices, such as GPUs or TPUs, to speed up the training process and handle models that are too large to fit on a single device. When creating your own LLM, the model's size and the dataset can be enormous, often requiring more memory and computational power than a single device can provide. Distributed training allows you to split the workload, enabling faster convergence and the ability to train larger models. Without it, training an LLM could take months or even years, making it impractical for most use cases. For example, models like GPT-3 or larger require distributed training to be feasible.

Explain data parallelism in distributed training for LLMs. How does it work, and what are its advantages?

Data parallelism is a distributed training technique where the same model is replicated across multiple devices, and each device processes a different subset of the training data. The gradients computed on each device are then averaged and used to update the model's weights synchronously. This approach works well because the model's architecture remains unchanged, and the data is split, allowing each device to contribute to the training process. The key advantage of data parallelism is its simplicity and scalability. It leverages the fact that modern deep learning frameworks, like PyTorch or TensorFlow, can automatically handle gradient synchronization. For example, in PyTorch, you can use `DataParallel` or `DistributedDataParallel` to implement this. Here’s a simple snippet: ```python model = MyLLM() model = torch.nn.DataParallel(model) ``` This splits the input data across available GPUs, making training much faster.

What is model parallelism, and when would you use it instead of data parallelism for training an LLM?

Model parallelism is a distributed training technique where different parts of the model are split across multiple devices, rather than replicating the entire model on each device. This is particularly useful when the model is too large to fit into the memory of a single device, even with techniques like gradient checkpointing. For example, if your LLM has billions of parameters, you might split the layers of the transformer across multiple GPUs. Model parallelism is more complex to implement than data parallelism because it requires careful partitioning of the model and communication between devices to ensure the forward and backward passes work correctly. You would use model parallelism when data parallelism alone isn’t sufficient, such as when the model’s memory footprint exceeds the capacity of a single GPU. For instance, you might place the first half of the transformer layers on one GPU and the second half on another.

Compare data parallelism and model parallelism for training LLMs. What are the trade-offs between the two approaches?

Data parallelism and model parallelism serve different purposes and have distinct trade-offs when training LLMs. Data parallelism is simpler to implement and scales well with the number of devices, as it replicates the model and splits the data. It’s ideal when the model fits into the memory of a single device but the dataset is large, as it speeds up training by processing data in parallel. However, it doesn’t help if the model itself is too large for a single device. Model parallelism, on the other hand, splits the model across devices, allowing you to train models that exceed the memory of a single GPU. The trade-off is increased complexity, as you must manage communication between devices and ensure the model is partitioned correctly. Data parallelism is generally preferred when possible because it’s easier to implement and debug, while model parallelism is a necessity for extremely large models. For example, if your LLM has 10 billion parameters, you might combine both approaches: use model parallelism to split the model and data parallelism to scale across multiple nodes.

How would you implement a hybrid approach combining data parallelism and model parallelism for training a very large LLM? Provide a conceptual example.

To implement a hybrid approach combining data parallelism and model parallelism, you would first partition the model across multiple devices using model parallelism, ensuring that each device holds a portion of the model that fits into its memory. Then, you would replicate this partitioned model across multiple nodes, using data parallelism to split the training data across these nodes. This way, you leverage the strengths of both techniques: model parallelism handles the model’s size, while data parallelism accelerates training by processing data in parallel. For example, imagine training a 100-billion-parameter LLM. You might split the transformer layers across 4 GPUs (model parallelism) and then replicate this setup across 8 nodes, each processing a different batch of data (data parallelism). In PyTorch, you could use `DistributedDataParallel` for data parallelism and manually partition the model for model parallelism. Here’s a conceptual snippet: ```python # Model parallelism: split layers across GPUs layer1 = Layer1().to('cuda:0') layer2 = Layer2().to('cuda:1') # Data parallelism: replicate across nodes model = HybridModel(layer1, layer2) model = torch.nn.parallel.DistributedDataParallel(model) ``` This setup allows you to train very large models efficiently.

What are the key challenges you might face when implementing distributed training for an LLM, and how would you address them?

Implementing distributed training for an LLM comes with several challenges, including communication overhead, load balancing, and fault tolerance. Communication overhead occurs because devices need to synchronize gradients or model updates, which can slow down training if not managed properly. To address this, you can use techniques like gradient accumulation or mixed-precision training to reduce the frequency and size of communication. Load balancing is another challenge, especially with model parallelism, where some devices might be underutilized if the model isn’t partitioned evenly. You can mitigate this by carefully profiling the model and ensuring that each device has a roughly equal computational load. Fault tolerance is critical in distributed training, as a single device failure can halt the entire training process. To handle this, you can implement checkpointing, where the model’s state is saved periodically, allowing you to resume training from the last checkpoint if a failure occurs. Additionally, frameworks like PyTorch offer tools like `torch.distributed.elastic` to handle node failures gracefully. For example, you might save checkpoints every few hours: ```python torch.save(model.state_dict(), 'checkpoint.pth') ``` By addressing these challenges, you can ensure that distributed training is both efficient and reliable.

All Creating Own LLM interview questions →

Check yourself

1. When training a large language model that exceeds the memory of a single GPU, which combination of techniques is most effective?

  • A.Use only data parallelism to distribute the dataset across multiple GPUs.
  • B.Use model parallelism to split the model across GPUs and data parallelism to distribute the dataset.
  • C.Increase the batch size until the model fits in a single GPU's memory.
  • D.Use gradient checkpointing without any parallelism techniques.
Show answer

B. Use model parallelism to split the model across GPUs and data parallelism to distribute the dataset.
The correct answer is combining model parallelism (to split the model) and data parallelism (to distribute the dataset). Option 1 fails because data parallelism alone cannot handle models larger than a single GPU's memory. Option 3 is impractical as it may exceed memory limits or degrade model quality. Option 4 reduces memory usage but doesn't address the core issue of model size.

2. In data parallelism, why is gradient synchronization a potential bottleneck?

  • A.Because gradients are only computed on one device and must be broadcast to others.
  • B.Because all devices must communicate gradients to ensure consistent model updates, which scales poorly with more devices.
  • C.Because gradients are not needed for backpropagation in data parallelism.
  • D.Because synchronization is only required during inference, not training.
Show answer

B. Because all devices must communicate gradients to ensure consistent model updates, which scales poorly with more devices.
The correct answer is that all devices must communicate gradients (e.g., via all-reduce) to ensure consistent model updates, which becomes a bottleneck with more devices or slow interconnects. Option 1 is wrong because gradients are computed on all devices. Option 3 is incorrect because gradients are essential for backpropagation. Option 4 is wrong because synchronization is critical during training.

3. How does model parallelism differ from pipeline parallelism in distributed training?

  • A.Model parallelism splits the model's layers across devices, while pipeline parallelism splits the model's tensors (e.g., attention heads) across devices.
  • B.Model parallelism splits the model's tensors or layers across devices, while pipeline parallelism splits the batch of data into micro-batches and pipelines execution across devices.
  • C.Model parallelism and pipeline parallelism are the same technique with different names.
  • D.Model parallelism is only used for inference, while pipeline parallelism is only used for training.
Show answer

B. Model parallelism splits the model's tensors or layers across devices, while pipeline parallelism splits the batch of data into micro-batches and pipelines execution across devices.
The correct answer is that model parallelism splits the model's tensors or layers across devices, while pipeline parallelism splits the batch into micro-batches and pipelines execution. Option 1 reverses the definitions. Option 3 is incorrect because they are distinct techniques. Option 4 is wrong because both techniques are used for training and inference.

4. What is a key challenge when implementing model parallelism for a transformer-based LLM?

  • A.Ensuring all layers fit in a single GPU's memory to avoid splitting.
  • B.Minimizing communication between devices when layers are split across them.
  • C.Avoiding gradient synchronization since it's not needed in model parallelism.
  • D.Using the same batch size for all devices to simplify implementation.
Show answer

B. Minimizing communication between devices when layers are split across them.
The correct answer is minimizing communication between devices when layers are split, as cross-device communication can introduce latency. Option 1 is wrong because model parallelism is used precisely when layers don't fit in a single GPU. Option 3 is incorrect because gradient synchronization is still required for training. Option 4 is unrelated to model parallelism's core challenge.

5. Why might increasing the number of GPUs in data parallelism lead to diminishing returns?

  • A.Because the model size grows proportionally with the number of GPUs.
  • B.Because the overhead of gradient synchronization increases with more GPUs, outweighing the benefits of additional compute.
  • C.Because data parallelism only works with a fixed number of GPUs (e.g., 2 or 4).
  • D.Because the dataset must be manually split into equal parts for each GPU.
Show answer

B. Because the overhead of gradient synchronization increases with more GPUs, outweighing the benefits of additional compute.
The correct answer is that the overhead of gradient synchronization (e.g., all-reduce operations) increases with more GPUs, eventually outweighing the benefits of additional compute. Option 1 is wrong because model size doesn't grow with GPUs in data parallelism. Option 3 is incorrect because data parallelism scales to many GPUs. Option 4 is misleading because the dataset is automatically split in frameworks like PyTorch or TensorFlow.

Take the full Creating Own LLM quiz →

← PreviousTraining Loops and Optimization Techniques (Adam, Learning Rate Scheduling)Next →Evaluating Model Performance: Perplexity, BLEU, and Human Evaluation

Creating Own LLM

36 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app