坚持写博客,分享自己的在学习、工作中的所得
- 给自己做备忘
- 对知识点记录、总结,加深理解
- 给有需要的人一些帮助,少踩一个坑,多走几步路
尽量以合适的方式排版,图文兼有
如果写的有误,或者有不理解的,均可在评论区留言
如果内容对你有帮助,欢迎点赞 收藏 ⭐留言 。
虽然平台并不会有任何奖励,但是我会很开心,可以让我保持写博客的热情
文章目录
- 动态学习率
- CosineAnnealingLR
- CosineAnnealingWarmRestarts
- StepLR
- MultiStepLR
- ExponentialLR
- ReduceLROnPlateau
- CyclicLR
- OneCycleLR
- LambdaLR
因为经常会使用到动态学习率,将其可视化会更好理解。
optimizer提供初始lr
lr_scheduler的step()从lr变化到eta_min
如果初始设置的lr比eta_min大,则先减小到eta_min,再增大到lr
如果初始设置的lr比eta_min小,则先增大到eta_min,再减小到lr
CosineAnnealingLRtorch.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()
CosineAnnealingWarmRestarts
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()
StepLR
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()
MultiStepLR
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()
ExponentialLR
torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1, verbose=False)
ExponentialLR:指数学习率。每次更新为lr *= gamma
相当于StepLR的step_size=1
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.9)
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()
ReduceLRonPlateau
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
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()
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()
CyclicLR
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()
oneCycleLR
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()
LambdaLR
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
如果内容对你有帮助,或者觉得写的不错
️欢迎点赞 收藏 ⭐留言
有问题,请在评论区留言



