PyTorch
learning rate
deep learning
machine learning
training process

PyTorch - How to get learning rate during training?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

In PyTorch, the current learning rate is stored on the optimizer, not on the model. The usual way to inspect it during training is to read optimizer.param_groups, and if you are using a scheduler you may also want to query the scheduler after each step.

Read the learning rate from the optimizer

Every optimizer has one or more parameter groups, and each group has its own lr value.

python
1import torch
2
3model = torch.nn.Linear(10, 1)
4optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
5
6print(optimizer.param_groups[0]["lr"])

That is the simplest answer when you have only one parameter group.

A common pattern is to log it at the start of each epoch.

python
1for epoch in range(5):
2    current_lr = optimizer.param_groups[0]["lr"]
3    print(f"Epoch {epoch}: lr={current_lr}")
4
5    for batch_x, batch_y in train_loader:
6        optimizer.zero_grad()
7        loss = criterion(model(batch_x), batch_y)
8        loss.backward()
9        optimizer.step()

This works well when the learning rate changes infrequently or only once per epoch.

If you have multiple parameter groups

Sometimes different layers use different learning rates. In that case, there is no single global learning rate.

python
1optimizer = torch.optim.SGD([
2    {"params": model.weight, "lr": 0.01},
3    {"params": model.bias, "lr": 0.001},
4], momentum=0.9)
5
6for i, group in enumerate(optimizer.param_groups):
7    print(f"group {i} lr = {group['lr']}")

If your optimizer has multiple groups, read all of them rather than assuming param_groups[0] tells the whole story.

Using a scheduler changes when you should inspect it

If you use a learning rate scheduler, the logged value depends on when you call scheduler.step().

python
1scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=2, gamma=0.1)
2
3for epoch in range(5):
4    print("before step:", optimizer.param_groups[0]["lr"])
5
6    for batch_x, batch_y in train_loader:
7        optimizer.zero_grad()
8        loss = criterion(model(batch_x), batch_y)
9        loss.backward()
10        optimizer.step()
11
12    scheduler.step()
13    print("after step:", optimizer.param_groups[0]["lr"])

That is why learning rate logs can look "off" if you print them before the scheduler update but mentally interpret them as post-update values.

get_last_lr() can be clearer with schedulers

For scheduler-aware logging, PyTorch schedulers also expose get_last_lr().

python
print(scheduler.get_last_lr())

This returns a list because, again, there may be multiple parameter groups. It is often the cleanest way to log learning rates when a scheduler is in control.

Where to log it

The right frequency depends on the schedule:

  • per epoch for epoch-based schedulers
  • per batch for batch-based schedules
  • whenever you need diagnostics for debugging training instability

If the learning rate is constant, logging it every batch is just noise.

Logging to experiment trackers

If you use TensorBoard, Weights and Biases, or a custom logger, log the learning rate from the optimizer at the same moment you log loss. That keeps the training curve and the learning-rate history aligned, which makes scheduler debugging much easier.

Per-batch versus per-epoch schedules

Always match your logging cadence to the scheduler cadence. If the scheduler updates every batch, epoch-level logging can hide important learning-rate changes.

Common Pitfalls

  • Looking for the learning rate on the model instead of the optimizer.
  • Assuming there is only one learning rate when the optimizer has multiple parameter groups.
  • Logging the value before scheduler.step() and interpreting it as the updated rate.
  • Using get_last_lr() without realizing it returns a list, not a scalar.
  • Forgetting that some schedulers change the rate every batch rather than every epoch.

Summary

  • Read the learning rate from optimizer.param_groups.
  • For a single parameter group, optimizer.param_groups[0]["lr"] is usually enough.
  • If you use multiple groups, inspect each group's lr.
  • With schedulers, scheduler.get_last_lr() is often the clearest logging interface.
  • Always be explicit about whether you are reading the rate before or after the scheduler step.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.