使用SGD,学习率在时期内不应该改变,但确实如此。请帮助我理解为什么会发生这种情况,以及如何防止这种LR改变?
import torch
params = [torch.nn.Parameter(torch.randn(1, 1))]
optimizer = torch.optim.SGD(params, lr=0.9)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1, gamma=0.9)
for epoch in range(5):
print(scheduler.get_lr())
scheduler.step()
输出为:
[0.9]
[0.7290000000000001]
[0.6561000000000001]
[0.5904900000000002]
[0.5314410000000002]
我的torch版本是1.4.0
由于您使用的是命令torch.optim.lr_scheduler.StepLR(optimizer, 1, gamma=0.9)
(实际上是指torch.optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.9)
(,因此每step_size=1
步都要将学习率乘以gamma=0.9
:
- 0.9=0.9
- 0.729=0.9*0.9*0.9
- 0.6561=0.9*0.9*0.9*0.9
- 0.59049=0.9*0.9*0.9*0.9
唯一"奇怪"的一点是,它在第二步中缺少0.81=0.9*0.9(更新:请参阅Szymon Maszke的答案以获得解释(
为了防止早期减少,如果数据集中有N
样本,并且批次大小为D,则将torch.optim.lr_scheduler.StepLR(optimizer, step_size=N/D, gamma=0.9)
设置为在每个历元减少。减少每个E历元集合torch.optim.lr_scheduler.StepLR(optimizer, step_size=E*N/D, gamma=0.9)
这正是torch.optim.lr_scheduler.StepLR
应该做的。它改变了学习率。来自pytorch文档:
在每个步长_大小的时期内通过gamma衰减每个参数组的学习率。请注意,这种衰减可以与来自该调度器外部的学习速率的其他变化同时发生。当last_epoch=-1时,将初始lr设置为lr
如果您正在尝试优化params
,您的代码应该更像这样(只是一个玩具示例,loss
的精确形式将取决于您的应用程序(
for epoch in range(5):
optimizer.zero_grad()
loss = (params[0]**2).sum()
loss.backward()
optimizer.step()
要扩展xiawi关于"奇怪"行为的答案(缺少0.81
(:这是PyTorch自1.1.0
发布以来的默认方式,请查看文档,即这部分:
[…]如果您使用学习率调度程序(调用
scheduler.step()
((调用optimizer.step()
(,这将跳过学习率的第一个值日程
此外,您应该在第一次get_lr()
调用后获得此函数抛出的UserWarning
,因为您根本没有调用optimizer.step()
。