5.2 十三個優化器
Optimizer 簡介
有了資料、模型和損失函數,就要選擇一個合適的優化器(Optimizer)來優化該模型,使loss不斷降低,直到模型收斂。本節將介紹pytorch中優化器——Optimizer。 優化器的實現在torch.optim中,torch.optim is a package implementing various optimization algorithms. 在其中有一個核心類是Optimizer,Optimizer在pytorch提供的功能是所有具體優化器的基類,它對優化器進行了抽象與定義,約定了一個優化器應有的功能,Optimizer與十三個優化器的關係如下圖所示:
通過上圖可知道Optimizer定義了優化器應當具備的基礎功能,如獲取狀態資料,載入狀態資料,梯度清零,執行一步優化和添加參數組。
不同的優化方法會繼承Optimizer,同時只需要實現不同的step()即可。這一點與損失函數類似,不同的損失函數只需要在forward()函數中定義好不同的公式計算即可。
本小節將以SGD為例,深入講解優化器的以下函數,並具體地觀察SGD演算法的實現過程。
state_dict(self)
load_state_dict(self, state_dict)
zero_grad(self, set_to_none: bool = False)
step(self, closure)
add_param_group(self, param_group)
優化器工作方式
優化器如何工作,使得模型精度逐漸提高的?在此就不詳細講解,請大家自行補充機器學習基礎概念。
眾所周知,優化器是根據權重的梯度作為指導,定義權重更新的力度,對權重進行更新。
過程很簡單,實現起來卻是複雜的,上述過程涉及幾個問題:
- 梯度哪裡來?
- 更新哪些權重?
- 怎麼執行權重更新?
依次回答上述問題,便可熟悉優化器工作方式。
梯度哪裡來? 梯度通過loss的反向傳播,得到每個權重的梯度值,其中利用pytorch的autograd機制自動求導獲得各權重的梯度。 (如果對autograd機制不熟悉,請查看第二章第六節)
更新哪些權重?通過loss的反向傳播,模型(nn.Module)的權重(Parameter)上有了梯度(.grad)值,但是優化器對哪些權重進行操作呢?實際上優化器會對需要操作的權重進行管理,只有被管理的權重,優化器才會對其進行操作。在Optimizer基類中就定義了add_param_group()函數來實現參數的管理。通常在產生實體的時候,第一個參數就是需要被管理的參數。
怎麼執行權重更新?通過上述UML類圖不難發現,step()函數是進行優化操作的,step()函數中實現了對所管理的參數進行更新的步驟。
總結一下:優化器在產生實體時告訴它,需要對哪些參數進行管理,然後再每個iteration反覆運算時,借助loss.backward()得到梯度,接著優化器幹活 optimizer.step()完成一步參數更新。
(此過程可以回顧第二章第二節的模型訓練代碼)
優化器基類 Optimizer
Optimizer類是所有具體優化器的基類(Base class for all optimizers.)
下面分別介紹Optimizer的基礎屬性及方法。
屬性:
- 參數組(param_groups):
在finetune、某層定制學習率,某層學習率置零操作中,都會設計參數組的概念,因此首先瞭解參數組的概念非常有必要。
參數組是用於管理需要進行優化的那些參數,例如權值weight,偏置bias,BN的alpha/beta等。
注意,這裡是參數組不是參數,表明可以將所有參數進行分組,區別對待。
例如在finetune過程中,通常讓前面層的網路採用較小的學習率,後面幾層全連接層採用較大的學習率,
這是我們就要把網路的參數劃分為兩組,每一組有它對應的學習率。正是因為這種針對不同參數需要不同的更新策略的需求,才有了參數組的概念。
參數組是一個list,其元素是一個dict,dict中包含,所管理的參數,對應的超參,例如學習率,momentum,weight_decay等等。
- state:
用於存儲優化策略中需要保存的一些緩存值,例如在用momentum時,需要保存之前的梯度,這些資料保存在state中。
- defaults:
優化方法默認的超參數;
方法:
- zero_grad()
功能:清零所管理參數的梯度。由於pytorch不會自動清零梯度,因此需要再optimizer中手動清零,然後再執行反向傳播,得出當前iteration的loss對權值的梯度。
- step()
功能:執行一步更新,依據當前的梯度進行更新參數
- add_param_group(param_group)
功能:給optimizer管理的參數組中增加一組參數,可為該組參數定制lr,momentum,weight_decay等,在finetune中常用。
例如:optimizer_1.add_param_group({'params': w3, 'lr': 0.001, 'momentum': 0.8})
- state_dict()
功能:獲取當前state屬性。
通常在保存模型時同時保存優化器狀態,用於中斷點保存,下次繼續從當前狀態訓練;
- load_state_dict(state_dict)
功能:載入所保存的state屬性,恢復訓練狀態。
對優化器工作方式熟悉後,再看Optimizer的屬性和方法就簡單了,下面通過一個具體的優化演算法來熟悉完整的優化器使用。
SGD概念
torch.optim.SGD詳情請參照[官方文檔](
https://pytorch.org/docs/stable/generated/torch.optim.SGD.html#torch.optim.SGD)
SGD(stochastic gradient descent,隨機梯度下降)是深度學習模型優化過程中最基礎、最受歡迎、最穩定的一個,即使優化演算法層出不窮,僅pytorch就提供了十三個,但目前絕大多數論文中仍舊採用SGD進行訓練,因此SGD必須掌握。
SGD核心理論知識是梯度下降( gradient descent),即沿著梯度的負方向,是變化最快的方向。
而隨機則指的是一次更新中,採用了一部分樣本進行計算,即一個batch的資料可以看作是整個訓練樣本的隨機採樣。更多關於SGD的理論知識請自行學習機器學習基礎。
SGD更新公式可簡化為 w新 = w舊 - w_grad,即參數減去梯度(學習率為1)
不過通常會加入學習率來調整更新的步伐:w_新 = w_舊 - (lr * w_grad)
對於加入L2正則(weight decay)時,變為:w_新 = w_舊 - (lr (w_grad + weight_decay w_舊))
L2正則稱之為weight decay的原因,對比公式1發現W需要乘以一個小於1的係數,因此是衰減的:w_新 = w_舊 - (lr (w_grad + weight_decay w_舊)) = w_舊(1 - lrweight_decay) - (lr w_grad)
對於其它momentum 、dampening 和nesterov 的加入就不詳細展開,可通過官方文檔查閱:
SGD使用
請結合代碼觀察SGD的使用
第一步:產生實體:optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4)
第二步:loss.backward()之前進行梯度清零:optimizer.zero_grad()
第三步:loss.backward()之後執行一步更新:optimizer.step()
在代碼中還有一處用到了optimizer,那就是學習率調整模組:
scheduler = optim.lr_scheduler.StepLR(optimizer, gamma=0.1, step_size=50)
原理是將optimizer放到lr_scheduler進行管理,lr_scheduler會修改optimizer中的學習率
SGD代碼實現
SGD類繼承於Optimizer類,並重寫step函數實現核心功能。
SGD類中step函數首先對各參數組、參數進行超參數的獲取確定:for group in self.param_groups:
然後借助functional.sgd函數實現公式計算:
F.sgd(params_with_grad,
d_p_list,
momentum_buffer_list,
weight_decay=weight_decay,
momentum=momentum,
lr=lr,
dampening=dampening,
nesterov=nesterov,
maximize=maximize,)
Copy
下面重點進入/torch/optim/_functional.py 的sgd()觀察:這裡為了講解過程,省略了momentum的代碼:
d_p:是梯度
weight_decay:是權重衰減係數,如 0.0001
param:是具體的權重參數
lr:是學習率
依194行代碼: param = param + (alpha)* d_p
依193行代碼: param = param + (-lr) d_p = **param - lr \ d_p**
依177行代碼: param = param - lr (d_p + weight_decay param) = param(1 - lr * weight_decay) - lr*d_p
到這裡,就可以與上述理論部分對應上了。
小結
其餘十二個優化器可通過官方文檔查閱,相信大家熟悉SGD以及優化器使用邏輯,其它的優化器都可輕鬆掌握。
Implements Adadelta algorithm. |
|
---|---|
Implements Adagrad algorithm. |
|
Implements Adam algorithm. |
|
Implements AdamW algorithm. |
|
Implements lazy version of Adam algorithm suitable for sparse tensors. |
|
Implements Adamax algorithm (a variant of Adam based on infinity norm). |
|
Implements Averaged Stochastic Gradient Descent. |
|
Implements L-BFGS algorithm, heavily inspired by minFunc. |
|
Implements NAdam algorithm. |
|
Implements RAdam algorithm. |
|
Implements RMSprop algorithm. |
|
Implements the resilient backpropagation algorithm. |
|
Implements stochastic gradient descent (optionally with momentum). |
下面梳理pytorch整個優化器實現的邏輯關係: