關於torch.optim的靈活使用詳解(包括重寫SGD,加上L1正則)
torch.optim的靈活使用詳解
1. 基本用法:
要構建一個優化器Optimizer,必須給它一個包含引數的迭代器來優化,然後,我們可以指定特定的優化選項,
例如學習速率,重量衰減值等。
注:如果要把model放在GPU中,需要在構建一個Optimizer之前就執行model.cuda(),確保優化器裡面的引數也是在GPU中。
例子:
optimizer = optim.SGD(model.parameters(),lr = 0.01,momentum=0.9)
2. 靈活的設定各層的學習率
將model中需要進行BP的層的引數送到torch.optim中,這些層不一定是連續的。
這個時候,Optimizer的引數不是一個可迭代的變數,而是一個可迭代的字典
(字典的key必須包含'params'(檢視原始碼可以得知optimizer通過'params'訪問parameters),
其他的key就是optimizer可以接受的,比如說'lr','weight_decay'),可以將這些字典構成一個list,
這樣就是一個可迭代的字典了。
注:這個時候,可以在optimizer設定選項作為關鍵字引數傳遞,這時它們將被認為是預設值(當字典裡面沒有這個關鍵字引數key-value對時,就使用這個預設的引數)
This is useful when you only want to vary a single option,while keeping all others consistent between parameter groups.
例子:
optimizer = SGD([ {'params': model.features12.parameters(),'lr': 1e-2},{'params': model.features22.parameters()},{'params': model.features32.parameters()},{'params': model.features42.parameters()},{'params': model.features52.parameters()},],weight_decay1=5e-4,lr=1e-1,momentum=0.9)
上面建立的optim.SGD型別的Optimizer,lr預設值為1e-1,momentum預設值為0.9。features12的引數學習率為1e-2。
靈活更改各層的學習率
torch.optim.optimizer.Optimizer的初始化函式如下:
__init__(self,params,lr=<object object>,momentum=0,dampening=0,weight_decay=0,nesterov=False)
params (iterable): iterable of parameters to optimize or dicts defining parameter groups (params可以是可迭代的引數,或者一個定義引數組的字典,如上所示,字典的鍵值包括:params,lr,momentum,dampening,weight_decay,nesterov)
想要改變各層的學習率,可以訪問optimizer的param_groups屬性。type(optimizer.param_groups) -> list
optimizer.param_groups[0].keys() Out[21]: ['dampening','nesterov','params','lr','weight_decay','momentum']
因此,想要更改某層引數的學習率,可以訪問optimizer.param_groups,指定某個索引更改'lr'引數就可以。
def adjust_learning_rate(optimizer,decay_rate=0.9): for para in optimizer.param_groups: para['lr'] = para['lr']*decay_rate
重寫torch.optim,加上L1正則
檢視torch.optim.SGD等Optimizer的原始碼,發現沒有L1正則的選項,而L1正則更容易得到稀疏解。
這個時候,可以更改/home/smiles/anaconda2/lib/python2.7/site-packages/torch/optim/sgd.py檔案,模擬L2正則化的操作。
L1正則化求導如下:
dw = 1 * sign(w)
更改後的sgd.py如下:
import torch from torch.optim.optimizer import Optimizer,required class SGD(Optimizer): def __init__(self,lr=required,weight_decay1=0,weight_decay2=0,nesterov=False): defaults = dict(lr=lr,momentum=momentum,dampening=dampening,weight_decay1=weight_decay1,weight_decay2=weight_decay2,nesterov=nesterov) if nesterov and (momentum <= 0 or dampening != 0): raise ValueError("Nesterov momentum requires a momentum and zero dampening") super(SGD,self).__init__(params,defaults) def __setstate__(self,state): super(SGD,self).__setstate__(state) for group in self.param_groups: group.setdefault('nesterov',False) 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_decay1 = group['weight_decay1'] weight_decay2 = group['weight_decay2'] 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_decay1 != 0: d_p.add_(weight_decay1,torch.sign(p.data)) if weight_decay2 != 0: d_p.add_(weight_decay2,p.data) if momentum != 0: param_state = self.state[p] if 'momentum_buffer' not in param_state: buf = param_state['momentum_buffer'] = torch.zeros_like(p.data) buf.mul_(momentum).add_(d_p) 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
一個使用的例子:
optimizer = SGD([ {'params': model.features12.parameters()},momentum=0.9)
以上這篇關於torch.optim的靈活使用詳解(包括重寫SGD,加上L1正則)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。