Learn how to implement a linear warmup schedule for the learning rate to stabilize early training steps and prevent divergence.
What it is
Warmup Learning Rate is a technique where the learning rate starts at zero (or a very small value) and gradually increases to a target peak over a specified number of initial training steps. This period is called the "warmup phase." After this phase, the learning rate typically follows a different schedule, such as constant, cosine decay, or step decay.
The mental model is similar to warming up before exercise: jumping straight into high-intensity activity can cause injury. Similarly, starting deep learning training with a high learning rate can cause large, unstable gradient updates that push the model parameters into poor regions of the loss landscape, potentially leading to NaN losses or slow convergence.
Related terms: Learning Rate Scheduler, Gradient Descent, Loss Landscape, Convergence Stability.
Why it matters
- Prevents Early Divergence: Large gradients in the first few batches can destabilize weights; warmup mitigates this by scaling down updates initially.
- Improves Final Accuracy: A stable start allows the optimizer to find a better basin in the loss landscape, often resulting in higher final validation performance.
- Enables Higher Peak Rates: By stabilizing the beginning, you can safely use a higher maximum learning rate later in training, which speeds up convergence.
- Standard Practice: It is a default component in many state-of-the-art architectures (e.g., Transformers) and optimizers (e.g., AdamW).
Syntax or steps
To implement linear warmup, you define a function that returns a multiplier for the base learning rate based on the current step count. During the warmup steps, this multiplier increases linearly from 0 to 1. Afterward, it remains at 1 (or transitions to another schedule).
- Define the total number of
warmup_steps. - Create a lambda function that calculates the ratio
current_step / warmup_stepsif the step is less than the limit. - Pass this function to a scheduler like
LambdaLR.
Example
import torch.optim as optim
from torch.optim.lr_scheduler import LambdaLR
# Assume 'model' is already defined
optimizer = optim.AdamW(model.parameters(), lr=0.001)
warmup_steps = 1000
def lr_lambda(step):
# Linear ramp from 0 to 1 during warmup
if step < warmup_steps:
return float(step) / float(max(1, warmup_steps))
# Hold at 1.0 after warmup (constant LR)
return 1.0
scheduler = LambdaLR(optimizer, lr_lambda=lr_lambda)
# Training loop snippet
for epoch in range(num_epochs):
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
# Update scheduler AFTER optimizer step
scheduler.step()
# Optional: Print current LR every 100 steps
if batch_idx % 100 == 0:
print(f"Step {batch_idx}, LR: {scheduler.get_last_lr()[0]:.6f}")
Explanation: The lr_lambda function determines the effective learning rate. At step 0, the multiplier is 0, so the LR is 0. At step 500, the multiplier is 0.5, so the LR is half the base rate. At step 1000, the multiplier becomes 1.0, reaching the full base rate of 0.001. Note that scheduler.step() must be called after optimizer.step().
Common mistakes
- Calling scheduler.step() too early: If you call it before
optimizer.step(), the first update uses the wrong learning rate. Always call it after the optimizer updates weights. - Integer Division Errors: In older Python versions or specific contexts, ensure division results in floats. Using
float(step)prevents integer truncation issues. - Mismatched Warmup Length: Setting warmup steps too low relative to dataset size may not provide enough stabilization; setting it too high wastes training time at low efficiency.
- Forgetting to Reset: When resuming training from a checkpoint, ensure the scheduler's internal step counter matches the global step count, otherwise the warmup might restart incorrectly.
When to use it
Compare warmup with other common strategies:
| Strategy | Best For | Risk |
|---|---|---|
| Linear Warmup + Constant | Short experiments, debugging, simple models. | No decay means potential oscillation near minima. |
| Linear Warmup + Cosine Decay | Long training runs, Transformers, CNNs. | Complexity in tuning both warmup and decay periods. |
| No Warmup | Small datasets, convex problems, SGD with momentum. | High risk of divergence with adaptive optimizers (Adam). |
Use warmup whenever using adaptive optimizers like Adam or AdamW, especially with large batch sizes or complex architectures.
Practice
Guided Exercise: Modify the example above to include a cosine decay after the warmup phase. Hint: Use math.cos and normalize the step count relative to total training steps.
Challenge: Implement an exponential warmup instead of linear. How does the curve differ? Expected Output: The learning rate rises slowly at first, then accelerates toward the peak.
Quick check
Q: Why do we multiply the base learning rate by a factor between 0 and 1 during warmup?
A: To gradually increase the magnitude of weight updates from negligible to full strength, preventing large initial gradients from destabilizing the model parameters.
Summary
Warmup learning rates stabilize the initial phase of training by gently increasing the learning rate from zero to a target value. This practice is essential for modern deep learning workflows, particularly when using adaptive optimizers, as it prevents early divergence and enables faster, more robust convergence.