聊聊pytorch中Optimizer與optimizer.step()的用法
當(dāng)我們想指定每一層的學(xué)習(xí)率時(shí):
optim.SGD([ {'params': model.base.parameters()}, {'params': model.classifier.parameters(), 'lr': 1e-3} ], lr=1e-2, momentum=0.9)
這意味著model.base的參數(shù)將會(huì)使用1e-2的學(xué)習(xí)率,model.classifier的參數(shù)將會(huì)使用1e-3的學(xué)習(xí)率,并且0.9的momentum將會(huì)被用于所有的參數(shù)。
進(jìn)行單次優(yōu)化
所有的optimizer都實(shí)現(xiàn)了step()方法,這個(gè)方法會(huì)更新所有的參數(shù)。它能按兩種方式來(lái)使用:
optimizer.step()
這是大多數(shù)optimizer所支持的簡(jiǎn)化版本。一旦梯度被如backward()之類的函數(shù)計(jì)算好后,我們就可以調(diào)用這個(gè)函數(shù)。
例子
for input, target in dataset: optimizer.zero_grad() output = model(input) loss = loss_fn(output, target) loss.backward() optimizer.step() optimizer.step(closure)
一些優(yōu)化算法例如Conjugate Gradient和LBFGS需要重復(fù)多次計(jì)算函數(shù),因此你需要傳入一個(gè)閉包去允許它們重新計(jì)算你的模型。這個(gè)閉包應(yīng)當(dāng)清空梯度,計(jì)算損失,然后返回。
例子:
for input, target in dataset: def closure(): optimizer.zero_grad() output = model(input) loss = loss_fn(output, target) loss.backward() return loss optimizer.step(closure)
補(bǔ)充:Pytorch optimizer.step() 和loss.backward()和scheduler.step()的關(guān)系與區(qū)別
首先需要明確optimzier優(yōu)化器的作用, 形象地來(lái)說(shuō),優(yōu)化器就是需要根據(jù)網(wǎng)絡(luò)反向傳播的梯度信息來(lái)更新網(wǎng)絡(luò)的參數(shù),以起到降低loss函數(shù)計(jì)算值的作用,這也是機(jī)器學(xué)習(xí)里面最一般的方法論。
從優(yōu)化器的作用出發(fā),要使得優(yōu)化器能夠起作用,需要主要兩個(gè)東西:
1. 優(yōu)化器需要知道當(dāng)前的網(wǎng)絡(luò)或者別的什么模型的參數(shù)空間
這也就是為什么在訓(xùn)練文件中,正式開(kāi)始訓(xùn)練之前需要將網(wǎng)絡(luò)的參數(shù)放到優(yōu)化器里面,比如使用pytorch的話總會(huì)出現(xiàn)類似如下的代碼:
optimizer_G = Adam(model_G.parameters(), lr=train_c.lr_G) # lr 使用的是初始lr optimizer_D = Adam(model_D.parameters(), lr=train_c.lr_D)
2. 需要知道反向傳播的梯度信息
我們還是從代碼入手,如下所示是Pytorch 中SGD優(yōu)化算法的step()函數(shù)具體寫法,具體SGD的寫法放在參考部分。
def step(self, closure=None): """Performs a single optimization step. Arguments: closure (callable, optional): A closure that reevaluates the model and returns the loss. """ loss = None if closure is not None: loss = closure() for group in self.param_groups: weight_decay = group['weight_decay'] momentum = group['momentum'] dampening = group['dampening'] nesterov = group['nesterov'] for p in group['params']: if p.grad is None: continue d_p = p.grad.data if weight_decay != 0: d_p.add_(weight_decay, p.data) if momentum != 0: param_state = self.state[p] if 'momentum_buffer' not in param_state: buf = param_state['momentum_buffer'] = d_p.clone() else: buf = param_state['momentum_buffer'] buf.mul_(momentum).add_(1 - dampening, d_p) if nesterov: d_p = d_p.add(momentum, buf) else: d_p = buf p.data.add_(-group['lr'], d_p) return loss
從上面的代碼可以看到step這個(gè)函數(shù)使用的是參數(shù)空間(param_groups)中的grad,也就是當(dāng)前參數(shù)空間對(duì)應(yīng)的梯度,這也就解釋了為什么optimzier使用之前需要zero清零一下,因?yàn)槿绻磺辶?,那么使用的這個(gè)grad就得同上一個(gè)mini-batch有關(guān),這不是我們需要的結(jié)果。
再回過(guò)頭來(lái)看,我們知道optimizer更新參數(shù)空間需要基于反向梯度,因此,當(dāng)調(diào)用optimizer.step()的時(shí)候應(yīng)當(dāng)是loss.backward()的時(shí)候,這也就是經(jīng)常會(huì)碰到,如下情況
total_loss.backward() optimizer_G.step()
loss.backward()在前,然后跟一個(gè)step。
那么為什么optimizer.step()需要放在每一個(gè)batch訓(xùn)練中,而不是epoch訓(xùn)練中,這是因?yàn)楝F(xiàn)在的mini-batch訓(xùn)練模式是假定每一個(gè)訓(xùn)練集就只有mini-batch這樣大,因此實(shí)際上可以將每一次mini-batch看做是一次訓(xùn)練,一次訓(xùn)練更新一次參數(shù)空間,因而optimizer.step()放在這里。
scheduler.step()按照Pytorch的定義是用來(lái)更新優(yōu)化器的學(xué)習(xí)率的,一般是按照epoch為單位進(jìn)行更換,即多少個(gè)epoch后更換一次學(xué)習(xí)率,因而scheduler.step()放在epoch這個(gè)大循環(huán)下。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
用Python實(shí)現(xiàn)控制電腦鼠標(biāo)
大家好,本篇文章主要講的是用Python實(shí)現(xiàn)控制電腦鼠標(biāo),感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01python 進(jìn)程 進(jìn)程池 進(jìn)程間通信實(shí)現(xiàn)解析
這篇文章主要介紹了python 進(jìn)程 進(jìn)程池 進(jìn)程間通信實(shí)現(xiàn)解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08Windows下Python2與Python3兩個(gè)版本共存的方法詳解
這篇文章主要介紹了Windows下Python2與Python3兩個(gè)版本共存的方法,文中介紹的很詳細(xì),對(duì)大家具有一定的參考價(jià)值,有需要的朋友們下面來(lái)一起看看吧。2017-02-02Python?Pygame繪制直線實(shí)現(xiàn)光線反射效果
這篇文章主要為大家詳細(xì)介紹了如何利用Python?Pygame繪制直線以實(shí)現(xiàn)光線反射效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11Python寫的Socks5協(xié)議代理服務(wù)器
這篇文章主要介紹了Python寫的Socks5協(xié)議代理服務(wù)器,代碼來(lái)自網(wǎng)上,需要的朋友可以參考下2014-08-08