前面的課程學習了優化器的概念,優化器中有很多超參數如學習率lr,momentum動量、weight_decay系數,這些超參數中最重要的就是學習率。學習率可以直接控制模型參數更新的步伐,此外,在整個模型訓練過程中學習率也不是一成不變的,而是可以調整變化的。本節內容就可以分為以下3方面展開,分別是:(1)為什么要調整學習率?(2)Pytorch的六種學習率調整策略;(3)學習率調整總結。
為什么要調整學習率?
①僅考慮學習率的梯度下降:
②加入momentum系數后隨機梯度下降更新公式:
從梯度下降法公式可知,參數更新這一項中會有學習率乘以梯度或更新量(\(lr*g(w_i)\) \(or\) \(lr*v_{i}\)),學習率lr直接控制了模型參數更新的步伐。通常,在模型訓練過程中,學習率給的比較大,這樣可以讓模型參數在初期更新比較快;到了后期,學習率有所下降,讓參數更新的步伐減慢。可是,為什么會在模型訓練時對學習率采用 “前期大、后期小” 的賦值特點呢?

由圖1可知,一開始球距離洞口很遠,將球打進洞口這一過程形如模型訓練中讓Loss逐漸下降至0這一過程。
(1)球距離洞口很遠,利用較大的力度去打球,讓球快速的飛躍到洞口附近,這就是一開始采用大學習率訓練模型的原因;
(2)球來到洞口附近,調整力度,輕輕擊打球,讓球可控、緩慢的朝洞口接近。這就是學習率到了后期,讓參數更新的步伐小一點,使得Loss逐漸下降。
這就學習率前期大、后期小的1個形象比喻。下面以函數的優化過程理解學習率“前期大、后期小”的原因。

Pytorch的六種學習率調整策略
Pytorch提供的六種學習率調整策略都是繼承於LRScheduler基類,因此首先學習LRScheduler基本屬性和基本方法。
class_LRScheduler
class_LRScheduler(object)
主要屬性:
optimizer:關聯的優化器
last_epoch:記錄epoch數
base_lrs:記錄初始學習率
主要屬性
(1)optimizer:學習率所關聯的優化器。已知優化器如torch.optim.SGD才是存放學習率lr的,LRScheduler會去修改優化器中的學習率。所以LRScheduler必須要關聯1個優化器才能改動優化器里面的學習率。
optim.SGD(params,lr=<object object>,
momentum=0,dampening=0,
weight_decay=0,nesterov=False)
(2)last_epoch:記錄epoch數。整個學習率調整是以epoch為周期,不要以iteration。
(3)base_lrs:記錄初始學習率。
LRScheduler的_init_函數
class_LRScheduler(object)
def_init_(self,optimizer.last_epoch=-1):
只接受2個參數,分別是optimizer和last_epoch=-1。
主要方法
step()——更新下一個epoch的學習率
一定要放在epoch中而不是iteration。
get_lr()——虛函數,計算下一個epoch的學習率
Pytorch提供的六種學習率調整策略
1、StepLR
功能:等間隔調整學習率
lr_scheduler.StepLR(optimizer,step_size,gamma,last_epoch=-1)
主要參數:step_size調整間隔數 gamma調整系數
設置step_size=50,每隔50個epoch時調整學習率,具體是用當前學習率乘以gamma即\(lr=lr*gamma\) ;
調整方式:\(lr=lr*gamma\) (gamma通常取0.1縮小10倍、0.5縮小一半)
實驗
LR = 0.1 //設置初始學習率
iteration = 10
max_epoch = 200
# --------- fake data and optimizer ---------
weights = torch.randn((1), requires_grad=True)
target = torch.zeros((1))
//構建虛擬優化器,為了 lr_scheduler關聯優化器
optimizer = optim.SGD([weights], lr=LR, momentum=0.9)
# ---------------- 1 Step LR --------
# flag = 0
flag = 1
if flag:
//設置optimizer、step_size等間隔數量:多少個epoch之后就更新學習率lr、gamma
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()
結果

2、MultiStepLR
功能:按給定間隔調整學習率
lr_scheduler.MultiStepLR(optimizer,milestones,gamma,last_epoch=-1)
主要參數:milestones設定調整時刻數 gamma調整系數
如構建個list設置milestones=[50,125,180],在第50次、125次、180次時分別調整學習率,具體是用當前學習率乘以gamma即\(lr=lr*gamma\) ;
調整方式:\(lr=lr*gamma\) (gamma通常取0.1縮小10倍、0.5縮小一半)
# ------------------------------ 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()
3、ExponentialLR
功能:按指數衰減調整學習率
lr_scheduler.ExponentialLR(optimizer,milestones,gamma,last_epoch=-1)
主要參數: gamma指數的底
如構建個list設置milestones=[50,125,180],在第50次、125次、180次時調整學習率,具體是用當前學習率乘以gamma即\(lr=lr*gamma\) ;
調整方式:\(lr=lr*gamma**epoch\) (gamma通常會設置為接近於1的數值,如0.95;\(lr=lr*gamma^{epoch}→0.1*0.95^1→0.1*0.95^2\))
# ------------- 3 Exponential LR -----------
# flag = 0
flag = 1
if flag:
gamma = 0.95
scheduler_lr = optim.lr_scheduler.ExponentialLR(optimizer, gamma=gamma)
...
結果

4、CosineAnnealingLR
功能:余弦周期調整學習率
lr_scheduler.ExponentialLR(optimizer,T_max,eta_min=0,last_epoch=-1)
主要參數: T_max下降周期,eta_min學習率下限
調整方式:
結果

5、ReduceLRonPlateau
功能:監控指標,當指標不再變化則調整(很實用)
比如監控Loss不再下降、或者分類准確率acc不再上升就進行學習率的調整。
lr_scheduler.ExponentialLR(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模式下觀察監控指標是否上升,用於監控分類准確率acc。
fator調整系數——相當於上面幾種調整策略中的gamma值;
patience:"耐心",接收幾次不變化;一定要連續多少次不發生變化(patience=10,某指標連續10次epoch沒有變化就進行lr調整)
cooldown:“冷卻時間”,停止監控一段時間;(cooldown=10,某指標連續10次epoch沒有變化就進行lr調整)
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、LambdaLR
功能:自定義調整策略
lr_scheduler.ExponentialLR(optimizer,lr_lambda,last_epoch=-1)
主要參數:
lr_lambda:function or list
如果是1個list,每1個元素也必須是1個function。
該方法適用於對不同的參數組設置不同的學習率調整策略。
# ------------------------------ 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)設置較小數:10e-2(0.01)、10e-3(0.001)、10e-4(0.0001);
(2)搜索最大學習率 《Cyclical learning Rates for Training Nerual Networks》