1. 程式人生 > 程式設計 >關於torch.optim的靈活使用詳解(包括重寫SGD,加上L1正則)

關於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正則)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。