文章目录

  • 一、优化算法
  • 二、学习率策略
  • 1、StepLR:均匀分步策略
  • 2、MultiStepLR:不均匀分步策略
  • 3、ExponentialLR:指数变换策略
  • 4、LambdaLR:自定义调整策略
  • 5、ReduceLROnPlateau:自适应调整策略
  • 三、参考资料



一、优化算法

pytorch的优化器:管理并更新模型中可学习参数的值,使得模型输出更接近真实标签

  • 导数:函数在指定坐标轴上的变化率
  • 方向导数:指定方向上的变化率
  • 梯度:一个向量,方向为方向导数 取得最大值的方向
# 常用优化算法
torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)
>>> params:管理的参数组
>>> lr:初始学习率
>>> momentum:动量系数,贝塔 
>>> weight_decay:L2 正则化系数 
>>> nesterov:是否采用 NAG

# alpha、rho、betas 为梯度(平方)的滑动平均衰减率,控制着历史梯度(平方)信息滑动平均的长度范围
torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)
torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0) # 无学习率参数,lr 为 delta 的系数
torch.optim.Adam(params, lr=0.001, =(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False) 
# 其它变种
torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)  # 随机平均梯度下降D
torch.optim.SparseAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08) # 稀疏版的 Adam
torch.optim.AdamW(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0.01, amsgrad=False)

# 优化器基本属性
defaults:优化器超参数 
state:参数的缓存,如 momentum 的缓存 
params_groups:管理的参数组 
_step_count:记录更新次数,学习率调整中使用


# 优化器常用方法
zero_grad(): Clears the gradients of all optimized torch.Tensors(清空所管理参数的梯度)
step(closure): Performs a single optimization step (parameter update, 执行一步更新)
add_param_group(param_group): Add a param group to the Optimizers param_groups(添加参数组)
load_state_dict(state_dict): Loads the optimizer state(加载状态信息字典)
state_dict(): Returns the state of the optimizer as a dict, contains two entries state and param_groups(获取优化器当前状态信息字典)


# Examples
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

optimizer = torch.optim.Adam([var1, var2], lr=0.0001)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

fc_params_id = list(map(id, res18.fc.parameters()))  # 返回的是 parameters 的内存地址
base_params = filter(lambda p: id(p) not in fc_params_id, res18.parameters())
optimizer = torch.optim.SGD([
    {'params': base_params, 'lr': LR * 0},  # 冻结最终分类层前所有层的参数
    {'params': res18.fc.parameters(), 'lr': LR}], momentum=0.9)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)  # 每迭代 step_size 个 epoch, 学习率降低为原来的 gamma 倍

# Taking an optimization step, update the parameters
for epoch in range(MAX_EPOCH):
    loss_mean = 0.
    correct = 0.
    total = 0.
    res18.train()  # 设置为训练模式

	for i, data in enumerate(train_loader):
	    # forward
	    inputs, labels = data
	    inputs, labels = inputs.to(device), labels.to(device)
	    outputs = res18(inputs)
	
	    # backward
	    optimizer.zero_grad()  # 将梯度清零
	    loss = criterion(outputs, labels)
	    loss.backward()
	
	    # update weights
	    optimizer.step()

	scheduler.step()  # 更新学习率

    # validate the model
    if (epoch + 1) % val_interval == 0:
        correct_val = 0.
        total_val = 0.
        loss_val = 0.
        res18.eval()  # 设置为验证模型
        
        # Disabling gradient calculation is useful for inference
        # In this mode, the result of every computation will have requires_grad=False
        with torch.no_grad():
            for j, data in enumerate(valid_loader):
                inputs, labels = data
                inputs, labels = inputs.to(device), labels.to(device)
                
                outputs = res18(inputs)
                loss = criterion(outputs, labels)

                _, predicted = torch.max(outputs.data, 1)

二、学习率策略

1、StepLR:均匀分步策略

# 采用均匀降低的方式,每迭代 step_size 个 epoch, 学习率降低为原来的 gamma 倍 
# 计算公式:base_lr * self.gamma ** (self.last_epoch // self.step_size)
torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)
>>> optimizer:关联的优化器
>>> step_size/gamma:每迭代 step_size 个 epoch, 学习率降低为原来的 gamma 倍
>>> last_epoch:记录 epoch 数
>>> 
>>> 常用方法:
>>> step():更新下一个 epoch 的学习率 
>>> get_lr():虚函数,计算下一个 epoch 的学习率
>>>
>>> # Assuming optimizer uses lr = 0.05 for all groups
>>> # lr = 0.05     if epoch < 30
>>> # lr = 0.005    if 30 <= epoch < 60
>>> # lr = 0.0005   if 60 <= epoch < 90
>>> # ...
>>> # Learning rate scheduling should be applied after optimizer’s update
>>> scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()

2、MultiStepLR:不均匀分步策略

# 采用非均匀降低策略,按设定的间隔(epoch)将学习率降低为原来的 gamma 倍
# 计算公式:base_lr * self.gamma ** bisect_right(self.milestones, self.last_epoch)
torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)
>>> milestones:设定学习率改变的时刻,可为 list 形式指定 
>>> gamma:调整系数
>>>
>>> # Assuming optimizer uses lr = 0.05 for all groups
>>> # lr = 0.05     if epoch < 30
>>> # lr = 0.005    if 30 <= epoch < 80
>>> # lr = 0.0005   if epoch >= 80
>>> # Learning rate scheduling should be applied after optimizer’s update
>>> scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[30, 80], gamma=0.1)
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()  # 执行一次 epoch 会加 1,因此 scheduler.step()要放在 epoch 的 for 循环当中执行
>>>     print('epoch: ', epoch, 'lr: ', scheduler.get_lr())  # 获取当前 epoch,参数组的学习率

3、ExponentialLR:指数变换策略

# 计算公式:base_lr * self.gamma ** self.last_epoch
torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1)  # 按指数衰减调整学习率, gamma 为指数的底

4、LambdaLR:自定义调整策略

# 为不同参数组设定不同学习率调整策略,调整规则为:lr = base_lr * lmbda(self.last_epoch)
torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1)
- lr_lambda(function or list):一个计算学习率调整倍数的函数,输入通常为 epoch,当有多个参数组时,设为 list
- last_epoch(int):上一个 epoch 数

>>> # Assuming optimizer has two groups.
>>> lambda1 = lambda epoch: epoch // 30
>>> lambda2 = lambda epoch: 0.95 ** epoch
>>> scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()

5、ReduceLROnPlateau:自适应调整策略

# 当某指标不再变化(下降或升高),调整学习率
torch.optim.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(str):'min' 表示当指标不再降低(如监测 loss),'max' 表示当指标不再升高(如监测 accuracy)
- factor(float):学习率调整倍数, new_lr = lr * factor
- patience(int):loss&acc 在多少个 epoch 变化不大时(缓冲期),才开始降低学习率
- verbose(bool):是否打印更新后的学习率
- threshold(float):在多少个 epoch 变化不超过此阈值,则开始降低学习率
- threshold_mode(str):阈值模式,按比例(rel) 还是按数值(abs)
	- rel mode, dynamic_threshold = best * ( 1 + threshold ) or best * ( 1 - threshold )  # max or min mode
	- abs mode, dynamic_threshold = best + threshold or best - threshold  # max or min mode
- cooldown(int):当调整学习率之后,让学习率调整策略冷静一下(多少个 epoch),让模型再训练一段时间,再重启监测模式
- min_lr(float or list):学习率下限
- eps(float):学习率衰减的最小值,当学习率变化小于 eps 时,则不调整学习率

三、参考资料

1、https://pytorch.org/docs/stable/optim.html2、PyTorch 的十个优化器3、PyTorch 的六个学习率调整方法