Mixed precision training helps your model learn faster and use less memory by mixing small and normal numbers smartly.
Mixed precision training (AMP) in PyTorch
import torch from torch.cuda.amp import autocast, GradScaler scaler = GradScaler() for data, target in dataloader: optimizer.zero_grad() with autocast(): output = model(data) loss = loss_fn(output, target) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()
autocast() runs operations in mixed precision automatically.
GradScaler helps keep training stable by scaling gradients.
with autocast():
output = model(data)
loss = loss_fn(output, target)scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()
This code trains a simple model for 3 epochs using mixed precision. It prints the loss each epoch.
import torch import torch.nn as nn import torch.optim as optim from torch.cuda.amp import autocast, GradScaler # Simple model class SimpleModel(nn.Module): def __init__(self): super().__init__() self.linear = nn.Linear(10, 1) def forward(self, x): return self.linear(x) # Data x = torch.randn(20, 10).cuda() y = torch.randn(20, 1).cuda() model = SimpleModel().cuda() optimizer = optim.SGD(model.parameters(), lr=0.1) loss_fn = nn.MSELoss() scaler = GradScaler() model.train() for epoch in range(3): optimizer.zero_grad() with autocast(): output = model(x) loss = loss_fn(output, y) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")
Mixed precision works best on GPUs with Tensor Cores (like NVIDIA RTX series).
Always use GradScaler to avoid problems with very small gradients.
Check your model's accuracy to ensure mixed precision does not reduce it.
Mixed precision training speeds up learning and saves memory by using smaller numbers where possible.
Use autocast() for automatic mixed precision during forward pass.
Use GradScaler to keep training stable when using mixed precision.
Practice
Solution
Step 1: Understand mixed precision training purpose
Mixed precision training uses smaller floating point numbers (like float16) to speed up computation and reduce memory use.Step 2: Identify the main benefit
This leads to faster training and less memory consumption without losing much accuracy.Final Answer:
It speeds up training and reduces memory usage by using smaller number formats. -> Option CQuick Check:
Mixed precision = faster training + less memory [OK]
- Thinking AMP guarantees perfect accuracy
- Believing AMP removes need for GPUs
- Confusing AMP with hyperparameter tuning
Solution
Step 1: Recall correct autocast usage
The correct syntax requires specifying device_type (usually 'cuda') and dtype (usually torch.float16) for mixed precision.Step 2: Check each option
with torch.autocast(device_type='cuda', dtype=torch.float16): output = model(input) correctly uses device_type='cuda' and dtype=torch.float16. B uses wrong device_type='cpu', C uses invalid parameter 'device', D uses unsupported dtype.Final Answer:
with torch.autocast(device_type='cuda', dtype=torch.float16): output = model(input) -> Option AQuick Check:
Correct autocast needs device_type and dtype [OK]
- Omitting device_type parameter
- Using CPU device for autocast
- Using unsupported dtypes like int32
scaler = torch.cuda.amp.GradScaler()
for input, target in dataloader:
optimizer.zero_grad()
with torch.cuda.amp.autocast():
output = model(input)
loss = loss_fn(output, target)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
What is the role of scaler.scale(loss).backward() here?Solution
Step 1: Understand GradScaler's purpose
GradScaler scales the loss to avoid very small gradient values (underflow) during mixed precision backward pass.Step 2: Analyze scaler.scale(loss).backward()
This scales the loss before calling backward(), ensuring stable gradient computation.Final Answer:
It scales the loss to prevent underflow during backward pass with mixed precision. -> Option AQuick Check:
GradScaler scales loss to keep gradients stable [OK]
- Thinking it converts loss to float32
- Believing it disables gradients
- Confusing it with zeroing gradients
scaler = torch.cuda.amp.GradScaler()
for input, target in dataloader:
optimizer.zero_grad()
with torch.cuda.amp.autocast():
output = model(input)
loss = loss_fn(output, target)
loss.backward()
scaler.step(optimizer)
scaler.update()
What is the error and how to fix it?Solution
Step 1: Identify missing scaler scaling
The code calls loss.backward() directly without scaling, which causes gradient underflow errors in AMP.Step 2: Correct usage with GradScaler
Replace loss.backward() with scaler.scale(loss).backward() to properly scale gradients before backward pass.Final Answer:
loss.backward() should be replaced with scaler.scale(loss).backward() to scale gradients. -> Option BQuick Check:
Use scaler.scale(loss).backward() with AMP [OK]
- Calling loss.backward() without scaling
- Calling zero_grad() after backward
- Misplacing autocast context
Solution
Step 1: Understand AMP with gradient clipping
When using AMP, gradients must be unscaled before clipping to get correct values.Step 2: Check code correctness
with torch.cuda.amp.autocast(): output = model(input) loss = loss_fn(output, target) scaler.scale(loss).backward() scaler.unscale_(optimizer) torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) scaler.step(optimizer) scaler.update() correctly calls scaler.unscale_(optimizer) before clipping gradients, then steps optimizer and updates scaler.Step 3: Identify errors in other options
with torch.cuda.amp.autocast(): output = model(input) loss = loss_fn(output, target) loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) optimizer.step() lacks scaler usage and uses loss.backward() directly. with torch.cuda.amp.autocast(): output = model(input) loss = loss_fn(output, target) scaler.scale(loss).backward() torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) scaler.step(optimizer) scaler.update() clips gradients before unscale, which is incorrect. with torch.cuda.amp.autocast(): output = model(input) loss = loss_fn(output, target) scaler.scale(loss).backward() optimizer.zero_grad() torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) scaler.step(optimizer) scaler.update() calls optimizer.zero_grad() after backward, which is wrong.Final Answer:
Correctly unscales gradients before clipping and uses scaler properly. -> Option DQuick Check:
Unscale before clip_grad_norm with scaler [OK]
- Clipping gradients before unscale
- Not using scaler with backward
- Calling zero_grad after backward
Ready to prove it?
Pass the test and this pattern moves unknown
