天天看點

Pytorch學習筆記(12)———學習率調整政策

關于學習率調整,pytorch提供了

torch.optim.lr_scheduler

主要提供了幾個類:

  • torch.optim.lr_scheduler.LambdaLr

  • torch.optim.lr_scheduler.StepLR

  • torch.optim.lr_scheduler.MultiStepLR

  • torch.optim.lr_scheduler.ExponentialLR

  • torch.optim.lr_sheduler.CosineAnneaingLR

  • torch.optim.lr_scheduler.ReduceLROnPlateau

1. torch.optim.lr_scheduler.StepLR

import torch
import torch.optim as optim
from torch.optim import lr_scheduler
from torchvision.models import AlexNet
import matplotlib.pyplot as plt


model = AlexNet(num_classes=2)
optimizer = optim.SGD(params=model.parameters(), lr=0.05)

# lr_scheduler.StepLR()
# 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

scheduler = lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
plt.figure()
x = list(range(100))
y = []
for epoch in range(100):
    scheduler.step()
    lr = scheduler.get_lr()
    print(epoch, scheduler.get_lr()[0])
    y.append(scheduler.get_lr()[0])

plt.plot(x, y)

           
Pytorch學習筆記(12)———學習率調整政策

0<epoch<30, lr = 0.05

30<=epoch<60, lr = 0.005

60<=epoch<90, lr = 0.0005

2. torch.optim.lr_scheduler.MultiStepLR

StepLR

相比,

MultiStepLR

可以設定指定的區間

# ---------------------------------------------------------------
# 可以指定區間
# lr_scheduler.MultiStepLR()
#  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
print()
plt.figure()
y.clear()
scheduler = lr_scheduler.MultiStepLR(optimizer, [30, 80], 0.1)
for epoch in range(100):
    scheduler.step()
    print(epoch, 'lr={:.6f}'.format(scheduler.get_lr()[0]))
    y.append(scheduler.get_lr()[0])

plt.plot(x, y)
plt.show()
           
Pytorch學習筆記(12)———學習率調整政策

3. torch.optim.lr_scheduler.ExponentialLR

指數衰減

scheduler = lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
print()
plt.figure()
y.clear()
for epoch in range(100):
    scheduler.step()
    print(epoch, 'lr={:.6f}'.format(scheduler.get_lr()[0]))
    y.append(scheduler.get_lr()[0])

plt.plot(x, y)
plt.show()
           
Pytorch學習筆記(12)———學習率調整政策

4. torch.optim.lr_sheduler.CosineAnneaingLR

餘弦退火函數調整學習率:學習率呈餘弦函數型衰減,并以2*T_max為餘弦函數周期,epoch=T_max對應餘弦型學習率調整曲線的eta_min處,随着epoch>T_max,學習率随epoch增加逐漸上升,整個走勢同cos(x)。

參數:

  • T_max(int): 學習率下降到最小值時的epoch數,即當epoch=T_max時,學習率下降到餘弦函數最小值,當epoch>T_max時,學習率将增大;
  • eta_min: 學習率調整的最小值,即epoch=T_max時,eta_min, 預設為0.

    其它參數同上。

5. torch.optim.lr_scheduler.ReduceLROnPlateau

根據名額調整學習率:當某名額(loss或accuracy)在最近幾個epoch中都沒有變化(下降或升高超過給定門檻值)時,調整學習率。如當驗證集的loss不再下降時,調整學習率;或監察驗證集的accuracy不再升高時,調整學習率。

參數:

  • mode(str):模式選擇,有min和max兩種模式,min表示當名額不再降低(如監測loss),max表示當名額不再升高(如監測accuracy)。
  • factor(float): 學習率調整倍數,同前面的gamma,當監測名額達到要求時,lr=lr×factor。
  • patience(int): 忍受該名額多少個epoch不變化,當忍無可忍時,調整學習率。
  • verbose(bool): 是否列印學習率資訊,print( ‘Epoch {:5d} reducing learning rate of group {} to {:.4e}.’.format(epoch, i, new_lr), 預設為False, 即不列印該資訊。
  • 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 == abs, 并且 mode == min時,dynamic_threshold = best - threshold;
  • threshold(float): 配合threshold_mode使用。
  • cooldown(int): “冷卻時間”,當調整學習率之後,讓學習率調整政策冷靜一下,讓模型在訓練一段時間,再重新開機監測模式。
  • min_lr(float or list): 學習率下限,可為float,或者list,當有多個參數組時,可用list進行設定。
  • eps(float): 學習率衰減的最小值,當學習率的變化值小于eps時,則不調整學習率。
optimizer = torch.optim.SGD(model.parameters(), args.lr,
 momentum=args.momentum, weight_decay=args.weight_decay)
 
scheduler = ReducelROnPlateau(optimizer,'min')
for epoch in range( args.start epoch, args.epochs ):
    train(train_loader , model, criterion, optimizer, epoch )
    result_avg, loss_val = validate(val_loader, model, criterion, epoch)
    # Note that step should be called after validate()
    scheduler.step(loss_val )

           

6. torch.optim.lr_scheduler.LambdaLr

自定義調整學習率:為不同參數組設定不同學習率調整政策。調整規則為:

lr = base_lr * lambda(self.last_epoch)

。在fine-tune中特别有用,我們不僅可以為不同層設定不同的學習率,還可以為不同層設定不同的學習率調整政策。

參數:

  • lr_lambda(function or list): 自定義計算學習率調整倍數的函數,通常為epoch的函數,當有多個參數組時,設為list.

    例:

ignored_params = list(map(id, net.fc3.parameters()))
base_params = filter(lambda p: id(p) not in ignored_params, net.parameters())
optimizer = optim.SGD([
        {'params': base_params},
        {'params': net.fc3.parameters(), 'lr': 0.001*100}], 0.001,          momentum=0.9,weight_decay=1e-4)
 # Assuming optimizer has two groups.
lambda1 = lambda epoch: epoch // 3
lambda2 = lambda epoch: 0.95 ** epoch
scheduler = LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])
for epoch in range(100):
    train(...)
    validate(...)
    scheduler.step()
    print('epoch: ', i, 'lr: ', scheduler.get_lr())
    
輸出:
epoch: 0 lr: [0.0, 0.1]
epoch: 1 lr: [0.0, 0.095]
epoch: 2 lr: [0.0, 0.09025]
epoch: 3 lr: [0.001, 0.0857375]
epoch: 4 lr: [0.001, 0.081450625]
epoch: 5 lr: [0.001, 0.07737809374999999]
epoch: 6 lr: [0.002, 0.07350918906249998]
epoch: 7 lr: [0.002, 0.06983372960937498]
epoch: 8 lr: [0.002, 0.06634204312890622]
epoch: 9 lr: [0.003, 0.0630249409724609]
為什麼第一個參數組的學習率會是 0 呢? 來看看學習率是如何計算的。
第一個參數組的初始學習率設定為 0.001, 
lambda1 = lambda epoch: epoch // 3,
第 1 個 epoch 時,由 lr = base_lr * lmbda(self.last_epoch),
可知道 lr = 0.001 *(0//3) ,又因為 1//3 等于 0,是以導緻學習率為 0。
第二個參數組的學習率變化,就很容易看啦,初始為 0.1, lr = 0.1 * 0.95^epoch ,當
epoch 為 0 時, lr=0.1 , epoch 為 1 時, lr=0.1*0.95。

           
# -*- coding:utf-8 -*-
'''本檔案用于測試pytorch學習率調整政策'''
 
__author__ = 'puxitong from UESTC'
 
import torch
import torch.optim as optim
from torch.optim import lr_scheduler
from torchvision.models import AlexNet
import matplotlib.pyplot as plt 
 
 
model = AlexNet(num_classes=2)
optimizer = optim.SGD(params=model.parameters(), lr=0.1)
 
# 等間隔調整學習率,每訓練step_size個epoch,lr*gamma
# scheduler = lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
 
# 多間隔調整學習率,每訓練至milestones中的epoch,lr*gamma
# scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[10, 30, 80], gamma=0.1)
 
# 指數學習率衰減,lr*gamma**epoch
# scheduler = lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
 
# 餘弦退火學習率衰減,T_max表示半個周期,lr的初始值作為餘弦函數0處的極大值逐漸開始下降,
# 在epoch=T_max時lr降至最小值,即pi/2處,然後進入後半個周期,lr增大
# scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=100, eta_min=0)
 
plt.figure()
x = list(range(100))
y = []
for epoch in range(100):
    scheduler.step()
    y.append(scheduler.get_lr()[0])
 
plt.plot(x, y)
plt.show()

           

7. 手動調整學習率

def adjust_learning_rate(optimizer, epoch):
    """Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
    lr = args.lr * (0.1 ** (epoch // 30))
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr

           
def adjust_learning_rate(epoch, lr):
    if epoch <= 81:  # 32k iterations
      return lr
    elif epoch <= 122:  # 48k iterations
      return lr/10
    else:
      return lr/100

           
for epoch in range(epochs):
    lr = adjust_learning_rate(optimizer, epoch)  # 調整學習率
    optimizer = optim.SGD(net.parameters(), lr=lr, momentum=0.9, weight_decay=5e-4)
    ......
    optimizer.step()  # 采用新的學習率進行參數更新
           

什麼是param_groups?

optimizer通過param_group來管理參數組;param_group中儲存了參數組及其對應的學習率,動量等等,是以我們可以通過更改param_group[‘lr’]的值來更改對應參數組的學習率

# 例1:有兩個`param_group`即,len(optim.param_groups)==2
optim.SGD([
                {'params': model.base.parameters()},
                {'params': model.classifier.parameters(), 'lr': 1e-3}
            ], lr=1e-2, momentum=0.9)
 
# 例2:一個參數組
optim.SGD(model.parameters(), lr=1e-2, momentum=.9)


           

上面第一個例子中,我們分别為 model.base 和 model.classifier 的參數設定了不同的學習率,即此時 optimizer.param_grops 中有兩個不同的param_group:

  • param_groups[0]: {‘params’: model.base.parameters()},
  • param_groups[1]: {‘params’: model.classifier.parameters(), ‘lr’: 1e-3}

    每一個param_group都是一個字典,它們共同構成了param_groups,是以此時len(optimizer.param_grops)==2,aijust_learning_rate() 函數就是通過for循環周遊取出每一個param_group,然後修改其中的鍵 ‘lr’ 的值,稱之為手動調整學習率。

第二個例子中len(optimizer.param_grops)==1,利用for循環進行修改同樣成立。

如果想要每次疊代都實時列印學習率,這樣可以每次step都能知道更新的最新學習率,可以使用

它傳回一個學習率清單,由參數組中的不同學習率組成,可通過清單索引來得到不同參數組中的學習率。

連結:https://www.jianshu.com/p/26a7dbc15246

來源:簡書

繼續閱讀