pytorch中的正則化,自定義優化器設置等操作

(1) pytorch中的L2和L1正則化,自定義優化器設置等操作

https://ptorch.com/docs/1/optim

在pytorch中進行L2正則化,最直接的方式可以直接用優化器自帶的weight_decay選項指定權值衰減率,相當於L2正則化中的λ \lambdaλ,也就是:

中的λ \lambdaλ。但是有一個問題就是,這個指定的權值衰減是會對網絡中的所有參數,包括權值w ww和偏置b bb同時進行的,很多時候如果對b bb進行L2正則化將會導致嚴重的欠擬合1,因此這個時候一般只需要對權值進行正則即可,當然,你可以獲取模型中的所有權值,然後按照定義的方法顯式地進行處理,得到一個正則損失之後在交給優化器優化,這是一個通用的方法。但是其實還有更爲簡單的方法,同樣在優化器中提供了。

torch.optim中包含了很多現成的優化器,包括SGD,Adadelta,Adam,Adagrad,RMSprop等,使用它很簡單,你需要傳入一個可迭代的參數列表(裏面必須都是Variable類型的)進行優化,然後你可以指定一些優化器的參數,如學習率,動量,權值衰減等。例子如:

optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum=0.9,weight_decay=1e-5)
optimizer = optim.Adam([var1, var2], lr = 0.0001)

此外,優化器還支持一種稱之爲Per-parameter options的操作,就是對每一個參數進行特定的指定,以滿足更爲細緻的要求。做法也很簡單,與上面不同的,我們傳入的待優化變量不是一個Variable而是一個可迭代的字典,字典中必須有params的key,用於指定待優化變量,而其他的key需要匹配優化器本身的參數設置。我們看一下例子:

optim.SGD([
                {'params': model.base.parameters()},
                {'params': model.classifier.parameters(), 'lr': 1e-3}
            ], lr=1e-2, momentum=0.9)

其中,我們可以看到,傳入的list中有兩個字典,每一個都是一個獨立的參數組,其中每一組中都有一個paramskey,用於指定需要訓練的參數,如model.base.parameters()就是base網絡中的所有參數,爾後,也可以在每一組內單獨設置學習率,權值衰減等。如果不顯式地在組內設定,那麼就會繼承優化器的全局參數,如lr=1e-2,momentum=0.9等,如果組內指定了,那麼全局的將不會覆蓋掉組內的參數設置。
這樣我們就可以靈活的給每一個子網絡設定不同的學習率,權值衰減,momentum了,我們也可以給權值設定權值衰減,而不作用與偏置,如:

weight_p, bias_p = [],[]
for name, p in model.named_parameters():
  if 'bias' in name:
     bias_p += [p]
   else:
     weight_p += [p]
# 這裏的model中每個參數的名字都是系統自動命名的,只要是權值都是帶有weight,偏置都帶有bias,
# 因此可以通過名字判斷屬性,這個和tensorflow不同,tensorflow是可以用戶自己定義名字的,當然也會系統自己定義。
optim.SGD([
          {'params': weight_p, 'weight_decay':1e-5},
          {'params': bias_p, 'weight_decay':0}
          ], lr=1e-2, momentum=0.9)

Update 2018-12-12:
有朋友說博文的方法好像報錯,我這裏又試了下,並沒有問題。環境是pytorch 1.0.0,jupyter notebook,ubuntu 16.04。完整測試代碼如下:

import torch
import torch.nn as nn
import numpy as np

## build model
class net(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(100,50)
        self.fc2 = nn.Linear(50,1)
        self.relu = nn.ReLU(inplace=True)
    def forward(self, inputs):
        layer = self.fc1(inputs)
        layer = self.relu(layer)
        layer = self.fc2(layer)
        return layer
## analoy inputs and labels
inputs = np.random.normal(size=(8,100))
inputs = torch.tensor(inputs).float()
labels = np.ones((8,1))
labels = torch.tensor(labels).float()

## update the weights and bias with L2 weight decay 
n = net()
weight_p, bias_p = [],[]
for name, p in n.named_parameters():
    if 'bias' in name:
        bias_p += [p]
    else:
        weight_p += [p]
        
criterion = nn.MSELoss()
logit = n(inputs)
loss = criterion(input=logit, target=labels)
opt = torch.optim.SGD([{'params': weight_p, 'weight_decay':1e-5},
                      {'params': bias_p, 'weight_decay':0}], 
                      lr=1e-2, 
                      momentum=0.9)

## update
opt.zero_grad()
loss.backward()
opt.step()        

請各位試試,謝謝。

Reference
[1]. PyTorch Documentation -> torch.optim
--------------------- 
作者:FesianXu 
來源:CSDN 
原文:https://blog.csdn.net/LoseInVain/article/details/81708474 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

(2) Adding L1/L2 regularization in PyTorch?

Following should help for L2 regularization:

optimizer = torch.optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5)

https://discuss.pytorch.org/t/how-does-one-implement-weight-regularization-l1-or-l2-manually-without-optimum/7951/19

(3) pytorch在不同的層使用不同的學習率
有時候我們希望某些層的學習率與整個網絡有些差別,這裏我簡單介紹一下在pytorch裏如何設置,方法略麻煩,如果有更好的方法,請務必教我:

首先我們定義一個網絡:

class net(nn.Module):
    def __init__(self):
        super(net, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, 1)
        self.conv2 = nn.Conv2d(64, 64, 1)
        self.conv3 = nn.Conv2d(64, 64, 1)
        self.conv4 = nn.Conv2d(64, 64, 1)
        self.conv5 = nn.Conv2d(64, 64, 1)
    def forward(self, x):
        out = conv5(conv4(conv3(conv2(conv1(x)))))
        return out

我們希望conv5學習率是其他層的100倍,我們可以:

net = net()
lr = 0.001

conv5_params = list(map(id, net.conv5.parameters()))
base_params = filter(lambda p: id(p) not in conv5_params,
                     net.parameters())
optimizer = torch.optim.SGD([
            {'params': base_params},
            {'params': net.conv5.parameters(), 'lr': lr * 100},
, lr=lr, momentum=0.9)

如果多層,則:

conv5_params = list(map(id, net.conv5.parameters()))
conv4_params = list(map(id, net.conv4.parameters()))
base_params = filter(lambda p: id(p) not in conv5_params + conv4_params,
                     net.parameters())
optimizer = torch.optim.SGD([
            {'params': base_params},
            {'params': net.conv5.parameters(), 'lr': lr * 100},
            {'params': net.conv4.parameters(), 'lr': lr * 100},
            , lr=lr, momentum=0.9)
 

--------------------- 
作者:BinWang-cvlab 
來源:CSDN 
原文:https://blog.csdn.net/wangbin12122224/article/details/79949824 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章