學習率是深度學習訓練中至關重要的引數,很多時候一個合適的學習率才能發揮出模型的較大潛力。所以學習率調整策略同樣至關重要,這篇部落格介紹一下Pytorch中常見的學習率調整方法。
import torch
import numpy as np
from torch.optim import SGD
from torch.optim import lr_scheduler
from torch.nn.parameter import Parameter
model = [Parameter(torch.randn(2, 2, requires_grad=True))]
optimizer = SGD(model, lr=0.1)
以上是一段通用程式碼,這裡將基礎學習率設定為0.1。接下來僅僅展示學習率調節器的程式碼,以及對應的學習率曲線。
1. StepLR
這是最簡單常用的學習率調整方法,每過step_size輪,將此前的學習率乘以gamma。
scheduler=lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
2. MultiStepLR
MultiStepLR同樣也是一個非常常見的學習率調整策略,它會在每個milestone時,將此前學習率乘以gamma。
scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[30,80], gamma=0.5)
3. ExponentialLR
ExponentialLR是指數型下降的學習率調節器,每一輪會將學習率乘以gamma,所以這裡千萬注意gamma不要設定的太小,不然幾輪之後學習率就會降到0。
scheduler=lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
4. LinearLR
LinearLR是線性學習率,給定起始factor和最終的factor,LinearLR會在中間階段做線性插值,比如學習率為0.1,起始factor為1,最終的factor為0.1,那麼第0次迭代,學習率將為0.1,最終輪學習率為0.01。下面設定的總輪數total_iters為80,所以超過80時,學習率恆為0.01。
scheduler=lr_scheduler.LinearLR(optimizer,start_factor=1,end_factor=0.1,total_iters=80)
5. CyclicLR
scheduler=lr_scheduler.CyclicLR(optimizer,base_lr=0.1,max_lr=0.2,step_size_up=30,step_size_down=10)
CyclicLR的引數要更多一些,它的曲線看起來就像是不斷的上坡與下坡,base_lr為谷底的學習率,max_lr為頂峰的學習率,step_size_up是從谷底到頂峰需要的輪數,step_size_down時從頂峰到谷底的輪數。至於為啥這樣設定,可以參見論文,簡單來說最佳學習率會在base_lr和max_lr,CyclicLR不是一味衰減而是出現增大的過程是為了避免陷入鞍點。
scheduler=lr_scheduler.CyclicLR(optimizer,base_lr=0.1,max_lr=0.2,step_size_up=30,step_size_down=10)
6. OneCycleLR
OneCycleLR顧名思義就像是CyclicLR的一週期版本,它也有多個引數,max_lr就是最大學習率,pct_start是學習率上升部分所佔比例,一開始的學習率為max_lr/div_factor,最終的學習率為max_lr/final_div_factor,總的迭代次數為total_steps。
scheduler=lr_scheduler.OneCycleLR(optimizer,max_lr=0.1,pct_start=0.5,total_steps=120,div_factor=10,final_div_factor=10)
7. CosineAnnealingLR
CosineAnnealingLR是餘弦退火學習率,T_max是週期的一半,最大學習率在optimizer中指定,最小學習率為eta_min。這裡同樣能夠幫助逃離鞍點。值得注意的是最大學習率不宜太大,否則loss可能出現和學習率相似週期的上下劇烈波動。
scheduler=lr_scheduler.CosineAnnealingLR(optimizer,T_max=20,eta_min=0.05)
7. CosineAnnealingWarmRestarts
這裡相對負責一些,公式如下,其中T_0是第一個週期,會從optimizer中的學習率下降至eta_min,之後的每個週期變成了前一週期乘以T_mult。
\(eta_t = \eta_{min} + \frac{1}{2}(\eta_{max} - \eta_{min})\left(1 + \cos\left(\frac{T_{cur}}{T_{i}}\pi\right)\right)\)
scheduler=lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=20, T_mult=2, eta_min=0.01)
8. LambdaLR
LambdaLR其實沒有固定的學習率曲線,名字中的lambda指的是可以將學習率自定義為一個有關epoch的lambda函式,比如下面我們定義了一個指數函式,實現了ExponentialLR的功能。
scheduler=lr_scheduler.LambdaLR(optimizer,lr_lambda=lambda epoch:0.9**epoch)
9.SequentialLR
SequentialLR可以將多個學習率調整策略按照順序串聯起來,在milestone時切換到下一個學習率調整策略。下面就是將一個指數衰減的學習率和線性衰減的學習率結合起來。
scheduler=lr_scheduler.SequentialLR(optimizer,schedulers=[lr_scheduler.ExponentialLR(optimizer, gamma=0.9),lr_scheduler.LinearLR(optimizer,start_factor=1,end_factor=0.1,total_iters=80)],milestones=[50])
10.ChainedScheduler
ChainedScheduler和SequentialLR類似,也是按照順序呼叫多個串聯起來的學習率調整策略,不同的是ChainedScheduler裡面的學習率變化是連續的。
scheduler=lr_scheduler.ChainedScheduler([lr_scheduler.LinearLR(optimizer,start_factor=1,end_factor=0.5,total_iters=10),lr_scheduler.ExponentialLR(optimizer, gamma=0.95)])
11.ConstantLR
ConstantLRConstantLR非常簡單,在total_iters輪內將optimizer裡面指定的學習率乘以factor,total_iters輪外恢復原學習率。
scheduler=lr_scheduler.ConstantLRConstantLR(optimizer,factor=0.5,total_iters=80)
12.ReduceLROnPlateau
ReduceLROnPlateau引數非常多,其功能是自適應調節學習率,它在step的時候會觀察驗證集上的loss或者準確率情況,loss當然是越低越好,準確率則是越高越好,所以使用loss作為step的引數時,mode為min,使用準確率作為引數時,mode為max。factor是每次學習率下降的比例,新的學習率等於老的學習率乘以factor。patience是能夠容忍的次數,當patience次後,網路效能仍未提升,則會降低學習率。threshold是測量最佳值的閾值,一般只關注相對大的效能提升。min_lr是最小學習率,eps指最小的學習率變化,當新舊學習率差別小於eps時,維持學習率不變。
因為引數相對複雜,這裡可以看一份完整的程式碼實操。
scheduler=lr_scheduler.ReduceLROnPlateau(optimizer,mode='min',factor=0.5,patience=5,threshold=1e-4,threshold_mode='abs',cooldown=0,min_lr=0.001,eps=1e-8)
scheduler.step(val_score)