在优化器中有很多超参数,如学习率、momentum等。其中学习率直接控制参数更新的一个大小,在整个训练当中,学习率也不是一成不变的。
为什么要调整学习率?
学习率是直接控制更新的步伐,从梯度下降的公式
可以看出,参数更新中
是学习率乘以一个梯度(更新量),在这里学习率直接控制了参数更新的大小。一般我们在刚开始训练时,学习率会设定比较大,让更新步伐较大,到了后期,学习率LR会下降,让参数更新的步伐变小。
pytorch中提供了多种学习率调整策略,其主要基于下面这个基类:
class _LRScheduler(object):
def __init__(self,optimizer,last_epoch=-1):
def get_lr(self):
raise NotImplementedError
主要属性:
- optimizer:关联的优化器
- last_epoch:记录epoch数
- base_lrs:记录初始学习率
主要方法:
- step():更新下一个epoch的学习率
- get_lr():虚函数,计算下一个epoch的学习率
pytorch提供的6中学习率调整策略:
1. lr_scheduler.StepLR(optimizer,step_size,gamma=0.1,last_epoch=-1)
功能:等间隔调整学习率
主要参数:
- step_size:调整间隔数
- gamma:调整系数
调整方式:
import torch
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
torch.manual_seed(1)
LR = 0.1
iteration = 10
max_epoch = 200
# ------------------------------ fake data and optimizer ------------------------------
weights = torch.randn((1), requires_grad=True)
target = torch.zeros((1))
optimizer = optim.SGD([weights], lr=LR, momentum=0.9)
# ------------------------------ 1 Step LR ------------------------------
# flag = 0
flag = 1
if flag:
scheduler_lr = optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.1) # 设置学习率下降策略
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
lr_list.append(scheduler_lr.get_lr())
epoch_list.append(epoch)
for i in range(iteration):
loss = torch.pow((weights - target), 2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
scheduler_lr.step()
plt.plot(epoch_list, lr_list, label="Step LR Scheduler")
plt.xlabel("Epoch")
plt.ylabel("Learning rate")
plt.legend()
plt.show()
从运行结果可以看出,每隔50个epoch后,就会降低一次学习率,开始的时候lr为0.1,运行50个epoch后,更新lr 为lr*gamma = 0.1*0.1 =0.01,然后同理,每隔50个epoch,则乘以gamma=0.1,来更新lr。
第二个调整策略:
2. lr_scheduler.MultiStepLR(optimizer,milestones,gamma=0.1,last_epoch=-1)
功能:按给定间隔调整学习率
主要参数:
milestones:设定调整时刻数
gamma:调整系数
调整方式:
# ------------------------------ 2 Multi Step LR ------------------------------
# flag = 0
flag = 1
if flag:
milestones = [50, 125, 160]
scheduler_lr = optim.lr_scheduler.MultiStepLR(optimizer, milestones=milestones, gamma=0.1)
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
lr_list.append(scheduler_lr.get_lr())
epoch_list.append(epoch)
for i in range(iteration):
loss = torch.pow((weights - target), 2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
scheduler_lr.step()
plt.plot(epoch_list, lr_list, label="Multi Step LR Scheduler\nmilestones:{}".format(milestones))
plt.xlabel("Epoch")
plt.ylabel("Learning rate")
plt.legend()
plt.show()
在代码中我们设置的milestone为50、125、160,从运行结果可以看出,其在每个milestone处进行lr 更新。这与step LR不同,step LR是等间隔的,这里是自定义间隔。
3. lr_scheduler.ExponentialLR(optimizer,gamma,last_epoch=-1)
功能:按指数衰减调整学习率
主要参数
gamma:指数的底
调整方式:
# ------------------------------ 3 Exponential LR ------------------------------
# flag = 0
flag = 1
if flag:
gamma = 0.95
scheduler_lr = optim.lr_scheduler.ExponentialLR(optimizer, gamma=gamma)
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
lr_list.append(scheduler_lr.get_lr())
epoch_list.append(epoch)
for i in range(iteration):
loss = torch.pow((weights - target), 2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
scheduler_lr.step()
plt.plot(epoch_list, lr_list, label="Exponential LR Scheduler\ngamma:{}".format(gamma))
plt.xlabel("Epoch")
plt.ylabel("Learning rate")
plt.legend()
plt.show()
我们可以看到运行结果中学习率呈指数下降趋势。
4. lr_scheduler.CosineAnnealingLR(optimizer,T_max,eta_min=0,last_epoch=-1)
功能:余弦周期调整学习率
主要参数:
- T_max:下降周期(1/2周期)
- eta_min:学习率下限
调整方式:
# ------------------------------ 4 Cosine Annealing LR ------------------------------
# flag = 0
flag = 1
if flag:
t_max = 50
scheduler_lr = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=t_max, eta_min=0.)
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
lr_list.append(scheduler_lr.get_lr())
epoch_list.append(epoch)
for i in range(iteration):
loss = torch.pow((weights - target), 2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
scheduler_lr.step()
plt.plot(epoch_list, lr_list, label="CosineAnnealingLR Scheduler\nT_max:{}".format(t_max))
plt.xlabel("Epoch")
plt.ylabel("Learning rate")
plt.legend()
plt.show()
从结果可以看出,200个epoch中,学习率从0.1逐渐下降到0,在50个epoch时达到最低,50是有T_max决定的,任何又经过50个epoch后,上升到最高。因此,周期为两个T_max。
5. lr_scheduler.ReduceLROnPlateau(optimizer,mode="min",factor=0.1,patience=10,verbose=False,threshold=0.0001,threshold_mode="rel",cooldown=0,min_lr=0,eps=1e-08)
功能:监控指标,当指标不再变化则调整
主要参数:
- mode:min/max两种模式(min模式下观察检测的指标是否下降,如loss,max则检测观察指标是否上升,如accuracy)
- factor:调整系数(相当于上诉中的gamma)
- patience:“耐心”,接受几次不变化(连续10次没有变化或不满足要求,则调整学习率)
- cooldown:“冷却时间”,停止监控一段时间
- verbose:是否打印日志
- min_lr:学习率下限
- eps:学习率衰减最小值
# ------------------------------ 5 Reduce LR On Plateau ------------------------------
# flag = 0
flag = 1
if flag:
loss_value = 0.5
accuray = 0.9
factor = 0.1
mode = "min"
patience = 10
cooldown = 10
min_lr = 1e-4
verbose = True
scheduler_lr = optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=factor, mode=mode, patience=patience,
cooldown=cooldown, min_lr=min_lr, verbose=verbose)
for epoch in range(max_epoch):
for i in range(iteration):
# train(...)
optimizer.step()
optimizer.zero_grad()
if epoch == 5:
loss_value = 0.4
scheduler_lr.step(loss_value)
6. lr_scheduler.LambdaLR(optimizer,lr_lambda,last_epoch=-1)
功能:自定义调整策略
主要参数:
- lr_lambda:function or list
# ------------------------------ 6 lambda ------------------------------
# flag = 0
flag = 1
if flag:
lr_init = 0.1
weights_1 = torch.randn((6, 3, 5, 5))
weights_2 = torch.ones((5, 5))
optimizer = optim.SGD([
{'params': [weights_1]},
{'params': [weights_2]}], lr=lr_init)
lambda1 = lambda epoch: 0.1 ** (epoch // 20)
lambda2 = lambda epoch: 0.95 ** epoch
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
for i in range(iteration):
# train(...)
optimizer.step()
optimizer.zero_grad()
scheduler.step()
lr_list.append(scheduler.get_lr())
epoch_list.append(epoch)
print('epoch:{:5d}, lr:{}'.format(epoch, scheduler.get_lr()))
plt.plot(epoch_list, [i[0] for i in lr_list], label="lambda 1")
plt.plot(epoch_list, [i[1] for i in lr_list], label="lambda 2")
plt.xlabel("Epoch")
plt.ylabel("Learning Rate")
plt.title("LambdaLR")
plt.legend()
plt.show()
学习率调整总结:
1.有序调整:step、MultiStep、Exponential和CosineAnnealing
2.自适应调整:ReduceLROnPleateau
3.自定义调整:Lambda
学习率初始化:
1. 设置较小数:0.01、0.001、0.0001
2. 搜索最大学习率:《Cyclical Learning Rates for Training Neural Networks》
可视化方法--- TensorBoard的使用
TensorBoard:是TensorFlow中强大的可视化工具,支持标量、图像、文本、音频、视频和Embedding等多种数据可视化。
运行机制:
首先在python脚本中记录可视化的数据,也就是我们在可视化中需要监控哪些数据,我们就需要将这些数据监控起来。将记录的数据放入硬盘当中event file(事件文件),接着我们在终端tensorboard中读取event file,然后tensorboard就会在web端进行可视化,这就是tensorboard的运行机制。
首先安装tensorboard
pip install tensorflow==1.14.0
pip install tensorboard
安装过程中tensorflow版本号需要大于等原因1.14.0,我支持强制让tensorflow为1.14.0,tensorboard也为1.14.0
编写简单的测试代码
import numpy as np
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter(comment='test_tensorboard')
for x in range(100):
writer.add_scalar('y=2x', x * 2, x)
writer.add_scalar('y=pow(2, x)', 2 ** x, x)
writer.add_scalars('data/scalar_group', {"xsinx": x * np.sin(x),
"xcosx": x * np.cos(x),
"arctanx": np.arctan(x)}, x)
writer.close()
运行该脚本,会生成如下文件:
接着在pycharm下的terminal下运行生成的runs文件:
接着在该路径下运行以下代码:
tensorboard --logdir=./runs
接着会生成对应的网址:
TensorBoard 1.14.0 at http://LAPTOP-UVUKGK1D:6006/ (Press CTRL+C to quit)
运行该网址得到如下界面: