坚持写博客,分享自己的在学习、工作中的所得
- 给自己做备忘
- 对知识点记录、总结,加深理解
- 给有需要的人一些帮助,少踩一个坑,多走几步路
尽量以合适的方式排版,图文兼有
如果写的有误,或者有不理解的,均可在评论区留言
如果内容对你有帮助,欢迎点赞 收藏 ⭐留言 。
虽然平台并不会有任何奖励,但是我会很开心,可以让我保持写博客的热情
因为经常会使用到动态学习率,将其可视化会更好理解。
optimizer提供初始lr
lr_scheduler的step()从lr变化到eta_min
如果初始设置的lr比eta_min大,则先减小到eta_min,再增大到lr
如果初始设置的lr比eta_min小,则先增大到eta_min,再减小到lr
last_epoch:上一个epoch数,当为-1时,学习率设置为初始值。
torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=-1, verbose=False)
CosineAnnealingLR:余弦退火学习率,T_max
为半周期,每经过2*T_max
之后lr
回到原来的值,eta_min
与optimizer
的lr
作比较,大的为最大值,小的为最小值,从lr
到eta_min
按余弦更新
T_max:经过多少个iter,学习率达到最大值
eta_min:学习率最小值
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-5, momentum=0.9, nesterov=False)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=30, eta_min=0.01)
EPOCHS = 100
x = list(range(EPOCHS))
y = []
for epoch in range(1,EPOCHS+1):
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step()
# 画出lr的变化
plt.figure()
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("CosineAnnealingLR")
plt.show()
torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0, T_mult=1, eta_min=0, last_epoch=-1, verbose=False)
CosineAnnealingWarmRestarts:带热重启的余弦退火
SGDR: Stochastic Gradient Descent with Warm Restarts.
T_0:第一次restart的迭代次数。
T_mult:restart之后增加 Ti 的因子,大于1的整数
eta_min:学习率最小值
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
scheduler = optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=20, T_mult=1, eta_min=1e-7)
EPOCHS = 100
dataloader = list(range(10))
iters = len(dataloader)
y = []
for epoch in range(EPOCHS):
for i, sample in enumerate(dataloader):
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step(epoch + i / iters)
# 画出lr的变化
plt.figure()
x = list(range(len(y)))
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("CosineAnnealingWarmRestarts")
plt.show()
torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1, verbose=False)
StepLR:阶梯学习率。每隔相同step_size
更新一次lr
,改变gamma
倍。
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.1)
EPOCHS = 100
y = []
for epoch in range(1,EPOCHS+1):
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step()
# 画出lr的变化
x = list(range(EPOCHS))
plt.figure()
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("StepLR")
plt.show()
torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1, verbose=False)
MultiStepLR:多阶梯学习率。milestones
对应位置更新一次lr
,改变gamma
倍。
与StepLR的差别是StepLR是每隔相同step_size更新一次lr;
而MultiStepLR是为milestones提供一个list,每到milestones的一个元素更新一次lr。
注意:milestones的元素必须是随索引增长的,即后一个元素必须比前一个元素大。
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[20,40,80], gamma=0.1)
EPOCHS = 100
y = []
for epoch in range(1,EPOCHS+1):
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step()
# 画出lr的变化
x = list(range(EPOCHS))
plt.figure()
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("MultiStepLR")
plt.show()
torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1, verbose=False)
每个epoch使用gamma衰减学习率lr
ExponentialLR:指数学习率。每次更新为lr *= gamma
相当于StepLR的step_size=1
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.9)
这里说明一下:
有的博客提到
调整公式: lr = lr * gamma**epoch, gamma为学习率调整倍数的底,指数为epoch
按照下面的代码,每个epoch的学习率都是在之前的学习率之前的学习率基础上乘以gamma值得到:lr *= gamma
但是如果是在全局上,加上指数学习率这个名字,公式确实应该是lr = lr * gamma**epoch
,只是这里的学习率是初始化的学习率,而上面我理解的学习率是根据上一个epoch的学习率来计算当前epoch的学习率。其实都是一样的。只是后面这个公式能更好的体现ExponentialLR
,并且在继续训练中,可以通过start_epoch
就能计算出对应的epoch
的lr
。
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
scheduler = optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
EPOCHS = 100
y = []
for epoch in range(1,EPOCHS+1):
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step()
# 画出lr的变化
x = list(range(EPOCHS))
plt.figure()
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("ExponentialLR")
plt.show()
torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08, verbose=False)
ReduceLROnPlateau:当指标停止改进时降低学习率。scheduler.step(val_loss)
,给传入scheduler某个指标(比如val_loss或者val_acc),当patience
个周期中这个指标变化小于threshold
时将lr
衰减factor
倍,如果新旧lr
之间的差异小于eps
,则忽略更新。
注意:跟其他scheduler不太一样的地方是:scheduler.step(val_loss)需要传参,没办法通过get_last_lr或get_lr得到lr
scheduler.get_last_lr()
AttributeError: ‘ReduceLROnPlateau’ object has no attribute ‘get_last_lr’
scheduler.get_lr()
AttributeError: ‘ReduceLROnPlateau’ object has no attribute ‘get_lr’
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08, verbose=False)
EPOCHS = 100
y = []
val_loss = 10
for epoch in range(1,EPOCHS+1):
optimizer.zero_grad()
optimizer.step()
# 如果固定下降val_loss,则lr不更新
# val_loss *= 0.1
if epoch%10 == 0:
val_loss *= 0.1
y.append(optimizer.state_dict()['param_groups'][0]['lr'])
scheduler.step(val_loss)
# 画出lr的变化
x = list(range(EPOCHS))
plt.figure()
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("ReduceLROnPlateau")
plt.show()
torch.optim.lr_scheduler.CyclicLR(optimizer, base_lr, max_lr, step_size_up=2000, step_size_down=None, mode='triangular', gamma=1.0, scale_fn=None, scale_mode='cycle', cycle_momentum=True, base_momentum=0.8, max_momentum=0.9, last_epoch=-1, verbose=False)
CyclicLR:循环学习率策略在每批之后改变学习率。应在批次用于训练后调用步骤。
base_lr:初始学习率,即各参数组在循环中的下边界。
max_lr:每个参数组在循环中的上学习率边界。
step_size_up:学习率上升的迭代次数,参考代码和图片更易理解。
step_size_down:学习率下降的迭代次数,参考代码和图片更易理解。
mode 的参数有:triangular
,triangular2
,exp_range
scale_fn:由单个参数 lambda 函数定义的自定义缩放策略,其中 0 <= scale_fn(x) <= 1 for all x >= 0
。如果指定,则忽略mode
参数
scale_mode:参数有:cycle
,iterations
step_size_up
和step_size_down
配合调整形态,step_size_down为None则默认step_size_down=step_size_up
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
scheduler = optim.lr_scheduler.CyclicLR(optimizer, base_lr=0.01, max_lr=0.0001, step_size_up=2000, step_size_down=500, mode='triangular') #mode in ['triangular', 'triangular2', 'exp_range']
EPOCHS = 100
dataloader = list(range(100))
y = []
for epoch in range(1,EPOCHS+1):
for batch in dataloader:
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step()
# 画出lr的变化
x = list(range(len(y)))
plt.figure()
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("CyclicLR")
plt.show()
torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr, total_steps=None, epochs=None, steps_per_epoch=None, pct_start=0.3, anneal_strategy='cos', cycle_momentum=True, base_momentum=0.85, max_momentum=0.95, div_factor=25.0, final_div_factor=10000.0, three_phase=False, last_epoch=-1, verbose=False)
OneCycleLR:OneCycle 学习率策略在每个batch之后改变学习率。应在每个batch
训练后调用step()
。学习率与optimizer
设置的学习率完全无关。
根据OneCycle学习率策略设置每个参数组的学习率。 OneCycle 策略将学习率从初始学习率退火到某个最大学习率,然后从该最大学习率退火到远低于初始学习率的某个最小学习率。
循环中的总步骤数可以通过以下两种方式之一确定(按优先顺序列出):
1.提供了 total_steps 的值。
2.了多个时代 (epoch) 和每个时代的多个步骤 (steps_per_epoch)。在这种情况下,总步数由 total_steps = epochs * steps_per_epoch 推断
pct_start:于提高学习率的周期百分比(以步数计)。就是上升阶段的占比
div_factor:通过initial_lr = max_lr/div_factor
确定初始学习率
final_div_factor:通过min_lr = initial_lr/final_div_factor
确定最小学习率
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
EPOCHS = 100
dataloader = list(range(100))
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
scheduler = optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.01, total_steps=None, epochs=EPOCHS, steps_per_epoch=len(dataloader), pct_start=0.1, anneal_strategy='cos') # anneal_strategy:'cos', 'linear'
y = []
for epoch in range(1,EPOCHS+1):
for batch in dataloader:
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step()
# 画出lr的变化
x = list(range(len(y)))
plt.figure()
plt.plot(x, y)
plt.xlabel("step")
plt.ylabel("lr")
plt.title("OneCycleLR")
plt.show()
torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1, verbose=False)
LambdaLR:按照自定义规则更新lr
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
y1=0.0
y2=1.0
steps=100
lf = lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1
scheduler = optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)
EPOCHS = 100
y = []
for epoch in range(1,EPOCHS+1):
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step()
# 画出lr的变化
x = list(range(EPOCHS))
plt.figure()
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("LambdaLR")
plt.show()
import torch
from torchvision.models import AlexNet
from torch import optim
import matplotlib.pyplot as plt
import math
model = AlexNet(num_classes=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=False)
lambda1 = lambda epoch: epoch // 30
lambda2 = lambda epoch: 0.95 ** epoch
scheduler = optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda2)
EPOCHS = 100
y = []
for epoch in range(1,EPOCHS+1):
optimizer.zero_grad()
optimizer.step()
y.append(scheduler.get_last_lr()[0])
scheduler.step()
# 画出lr的变化
x = list(range(EPOCHS))
plt.figure()
plt.plot(x, y)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("LambdaLR")
plt.show()
参考:https://pytorch.org/docs/stable/optim.html
如果内容对你有帮助,或者觉得写的不错
️欢迎点赞 收藏 ⭐留言
有问题,请在评论区留言