详细理解pytorch的六种学习率

深度学习本身是一个不断优化,逼近真实映射函数的过程。而这个过程是需要优化器不断的迭代更新参数,不断降低损失值,这其中最基础也是关键的参数就是学习率。可以说用好学习率策略,准确率至少上升十几个点。
下面依次通过实例来看下相应的学习率策略

import torch
from torch import nn, optim
from torch.autograd import Variable
import numpy as np
import matplotlib.pyplot as plt

x_train = np.array([[3.3], [4.4], [5.5], [6.71], [6.93], [4.168],
                    [9.779], [6.182], [7.59], [2.167], [7.042],
                    [10.791], [5.313], [7.997], [3.1]], dtype=np.float32)

y_train = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573],
                    [3.366], [2.596], [2.53], [1.221], [2.827],
                    [3.465], [1.65], [2.904], [1.3]], dtype=np.float32)


x_train = torch.from_numpy(x_train)

y_train = torch.from_numpy(y_train)


# Linear Regression Model
class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.linear1 = nn.Linear(1, 5)  # input and output is 1 dimension
        self.linear2 = nn.Linear(5,1)
    def forward(self, x):
        out = self.linear1(x)
        out = self.linear2(out)
        return out


model = LinearRegression()
print(model.linear1)
# 微调:自定义每一层的学习率

# 定义loss和优化函数
criterion = nn.MSELoss()
optimizer = optim.SGD(
                [{
    
    "params":model.linear1.parameters(),"lr":0.01},
                 {
    
    "params":model.linear2.parameters()}],
                      lr=0.02)
lambda1 = lambda epoch: epoch//100
lambda2 = lambda epoch: 0.95**epoch

step_schedule = optim.lr_scheduler.StepLR(step_size=20,gamma=0.9,optimizer=optimizer)
cosine_schedule = optim.lr_scheduler.CosineAnnealingLR(optimizer=optimizer,T_max=20,eta_min=0.0004)
exponent_schedule = optim.lr_scheduler.ExponentialLR(optimizer=optimizer,gamma=0.9)
reduce_schedule = optim.lr_scheduler.ReduceLROnPlateau(optimizer=optimizer)
multi_schedule = optim.lr_scheduler.MultiStepLR(optimizer=optimizer,milestones=[120,180])
lambda_schedule = optim.lr_scheduler.LambdaLR(optimizer=optimizer,lr_lambda=[lambda1,lambda2])

step_lr_list = []
cosine_lr_list = []
exponent_lr_list = []
reduce_lr_list = []
loss_list = []
multi_list = []
lambda1_list = []
lambda2_list = []
# 开始训练
num_epochs = 240
for epoch in range(num_epochs):
    inputs = Variable(x_train)
    target = Variable(y_train)

    # forward
    out = model(inputs)
    loss = criterion(out, target)
    # backward
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    step_schedule.step()
    cosine_schedule.step()
    exponent_schedule.step()
    reduce_schedule.step(loss)
    multi_schedule.step()
    lambda_schedule.step()

    # print(schedule.get_lr())
    loss_list.append(loss.item())
    # print(optimizer.param_groups[0]["lr"])
    step_lr_list.append(step_schedule.get_lr()[0])
    cosine_lr_list.append(cosine_schedule.get_lr()[0])
    exponent_lr_list.append(exponent_schedule.get_lr()[0])
    reduce_lr_list.append(optimizer.param_groups[0]["lr"])
    multi_list.append(multi_schedule.get_lr()[0])
    lambda1_list.append(optimizer.param_groups[0]["lr"])
    lambda2_list.append(optimizer.param_groups[1]["lr"])
# print(optimizer.param_groups[0]["lr"])
#     print(optimizer.param_groups[1]["lr"])

    # if (epoch+1) % 20 == 0:
    #     print('Epoch[{}/{}], loss: {:.6f}'
    #           .format(epoch+1, num_epochs, loss.item()))
plt.subplot(121)
plt.plot(range(len(loss_list)),loss_list,label="loss")
plt.legend()
plt.subplot(122)
plt.plot(range(len(step_lr_list)),step_lr_list,label="step_lr")
plt.plot(range(len(cosine_lr_list)),cosine_lr_list,label="cosine_lr")
plt.plot(range(len(exponent_lr_list)),exponent_lr_list,label="exponent_lr")
plt.plot(range(len(reduce_lr_list)),reduce_lr_list,label="reduce_lr")
plt.plot(range(len(multi_list)),multi_list,label="multi_lr")
plt.plot(range(len(lambda1_list)),lambda1_list,label="lambda1_lr")
plt.plot(range(len(lambda2_list)),lambda2_list,label="lambda2_lr")
plt.legend()
plt.show()

使用的是简单的两层全连接网络,不必深究主要是展示学习率的变化。

等步长间隔调整学习率

optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)

step_size是每隔多少个epoch学习率衰减一次,last_epoch=-1时epoch初始值为0。gamma设置的衰减率即 lr = lr*gamma,我这里取step_size=20,gamma=0.9
Alt

cosine学习率

 optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0)

T_max表示半个周期( π \pi π)的长度,eta_min表示最小的cos值。这里设置T_max=50,eta_min=0.0004
Alt

指数衰减学习率

optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1)

公式 l r = l r ∗ γ e p o c h lr=lr*\gamma^{epoch} lr=lrγepoch这里每全部迭代一次数据成为一个epoch
通常 γ \gamma γ值设置会比较大。这是参数 γ \gamma γ = 0.99
Alt

自适应调整学习率

optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10,
                 verbose=False, threshold=1e-4, threshold_mode='rel',
                 cooldown=0, min_lr=0, eps=1e-8)

参数:

mode(str)- 模式选择,有 min 和 max 两种模式, min 表示当指标不再降低(如监测loss), max 表示当指标不再升高(如监测 accuracy)factor(float)- 学习率调整倍数(等同于其它方法的 gamma),即学习率更新为 lr = lr * factor
patience(int)- 忍受该指标多少个 step 不变化,当忍无可忍时,调整学习率。
verbose(bool)- 是否打印学习率信息, print(‘Epoch {
    
    :5d}: reducing learning rate of group {
    
    } to {
    
    :.4e}..format(epoch, i, new_lr))
threshold_mode(str)- 选择判断指标是否达最优的模式,有两种模式, rel 和 abs。
当 threshold_mode == rel,并且 mode == max 时, dynamic_threshold = best * ( 1 +threshold );
当 threshold_mode == rel,并且 mode == min 时, dynamic_threshold = best * ( 1 -threshold );
当 threshold_mode == abs,并且 mode== max 时, dynamic_threshold = best + threshold ;
当 threshold_mode == rel,并且 mode == max 时, dynamic_threshold = best - threshold;
threshold(float)- 配合 threshold_mode 使用。
cooldown(int)- “冷却时间“,当调整学习率之后,让学习率调整策略冷静一下,让模型再训练一段时间,再重启监测模式。
min_lr(float or list)- 学习率下限,可为 float,或者 list,当有多个参数组时,可用 list 进行设置。

这里使用loss作为检测值,其他参数为默认值
Alt

非等间隔调整学习率

optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)

通过参数milestones给定衰减的epoch列表,可以在指定的epoch时期进行衰减。

参数设置 milestones=[120,180]
Alt

自定义网络层隔学习率

optim.lr_scheduler.LambdaLR( optimizer, lr_lambda, last_epoch=-1)

这里第一层去全连接设置的是上升的学习率lambda1,第二层是下降的学习率lambda2。lambda匿名函数得出学习率的衰减值,lr=lr*decay,decay有lambda函数得出。

lambda1 = lambda epoch: epoch//100
lambda2 = lambda epoch: 0.95**epoch

参数设置,第一层学习率为0.01,第二层学习率为0.02
Alt
经过基础的尝试,发现一些比较骚的操作实际效果一般。反而简单设置的会好一点,像等间隔衰减和非等间隔衰减。非等间隔衰减适合在对损失函数初步了解后进行细致给定衰减epoch。给定每一层的学习率适合迁移学习的微调,多用在卷积网路的全连接层。
炼丹不易,多提意见!

参考博文 https://blog.csdn.net/shanglianlm/article/details/85143614

猜你喜欢

转载自blog.csdn.net/weixin_42662358/article/details/93732852