天天看點

模型模型的定義權值初始化模型finetune(遷移學習)

模型的定義

首先,必須繼承 nn.Module 類。

其次,在__init__(self)中設定好需要的“元件"(如 conv、 pooling、 Linear、 BatchNorm等)。

最後,在 forward(self, x)中用定義好的“元件”進行組裝。

class Net(nn.Module):
    def __init__(self):    # 初始化,定義元件
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool1 = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.pool2 = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):    # 搭建網絡結構
        x = self.pool1(F.relu(self.conv1(x)))    # x 經過 conv1,然後經過激活函數 relu,再經過 pool1 操作
        x = self.pool2(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)    # 将 x 進行 reshape,為了後面做為全連接配接層的輸入
        x = F.relu(self.fc1(x))    # 先經過全連接配接層 fc,然後經過 relu
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x
           

至此,一個模型定義完畢,接着就可以在後面進行使用。例如,執行個體化一個模型

net = Net()

,然後把輸入 inputs 扔進去,

outputs = net(inputs)

,就可以得到輸出 outputs。

torch.nn.Sequential 容器,将一系列操作按先後順序給包起來,友善重複使用。

權值初始化

第一步,先設定什麼層用什麼初始化方法,初始化方法在 torch.nn.init 中給出;

第二步,執行個體化一個模型之後,執行該函數,即可完成初始化。

def initialize_weights(self):
        for m in self.modules():  # 周遊每一層
            if isinstance(m, nn.Conv2d):  # 判斷各層屬于什麼類型
                torch.nn.init.xavier_normal_(m.weight.data)  # 設定不同的權值初始化方法
                if m.bias is not None:  # 判斷是否存在偏置,若存在,初始化為全0
                    m.bias.data.zero_()
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()
            elif isinstance(m, nn.Linear):
                torch.nn.init.normal_(m.weight.data, 0, 0.01)
                m.bias.data.zero_()
           

常用初始化方法

Xavier 均勻分布

torch.nn.init.xavier_uniform_(tensor, gain=1)

Xavier 正态分布

torch.nn.init.xavier_normal_(tensor, gain=1)

kaiming 均勻分布

torch.nn.init.kaiming_uniform_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu')

kaiming 正态分布

torch.nn.init.kaiming_normal_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu')

均勻分布初始化

torch.nn.init.uniform_(tensor, a=0, b=1)

正态分布初始化

torch.nn.init.normal_(tensor, mean=0, std=1)

常數初始化

torch.nn.init.constant_(tensor, val)

機關矩陣初始化

torch.nn.init.eye_(tensor)

正交初始化

torch.nn.init.orthogonal_(tensor, gain=1)

稀疏初始化

torch.nn.init.sparse_(tensor, sparsity, std=0.01)

計算增益

torch.nn.init.calculate_gain(nonlinearity, param=None)

PyTorch預設初始化

在建立網絡執行個體的過程中, 一旦調用 nn.Conv2d 的時候就會有對權值進行初始化。采用的是均勻分布,其中-stdv 與 kernel 的 size 有關。在 PyTorch1.0 版本中,這裡改用了 kaiming_uniform_()進行初始化。

模型finetune(遷移學習)

在實際應用中,我們通常采用一個已經訓練模型的模型的權值參數作為我們模型的初始化參數,也稱之為 Finetune, 更寬泛的稱之為遷移學習。

net = Net()     # 建立一個網絡
# ================================ #
#        finetune 權值初始化
# ================================ #
# load params
pretrained_dict = torch.load('net_params.pkl')
# 擷取目前網絡的dict
net_state_dict = net.state_dict()
# 剔除不比對的權值參數
pretrained_dict_1 = {k: v for k, v in pretrained_dict.items() if k in net_state_dict}
# 更新新模型參數字典
net_state_dict.update(pretrained_dict_1)
# 将包含預訓練模型參數的字典"放"到新模型中
net.load_state_dict(net_state_dict)
           

流程如下:

第一步:儲存模型,擁有一個預訓練模型;

net = Net()

torch.save(net.state_dict(), 'net_params.pkl')

第二步:加載模型,把預訓練模型中的權值取出來;

pretrained_dict = torch.load('net_params.pkl')

第三步:初始化,将權值對應的“放”到新模型中

首先我們建立新模型,并且擷取新模型的參數字典

net_state_dict = net.state_dict()

接着将 pretrained_dict 裡不屬于 net_state_dict 的鍵剔除掉

pretrained_dict_1 = {k: v for k, v in pretrained_dict.items() if k in net_state_dict}

然後,用預訓練模型的參數字典 對 新模型的參數字典 net_state_dict 進行更新

net_state_dict.update(pretrained_dict_1)

最後,将更新了參數的字典 “放”回到網絡中

net.load_state_dict(net_state_dict)

不同層設定不同的學習率

為不同層設定不同的學習率,隻需要将原始的參數組,劃分成兩個,甚至更多的參數組,然後分别進行設定學習率。

ignored_params = list(map(id, net.fc3.parameters())) # 傳回的是 parameters 的 記憶體位址
base_params = filter(lambda p: id(p) not in ignored_params, net.parameters())  # 剝離了 fc3 層的參數的其餘參數
 # base_params 中的層,用 0.001, momentum=0.9,weight_decay=1e-4, fc3 層設定學習率為: 0.001*10
optimizer = optim.SGD([
{'params': base_params},  # base_params 是一個 list,每個元素是一個 Parameter 類
{'params': net.fc3.parameters(), 'lr': 0.001*10}], 0.001, momentum=0.9, weight_decay=1e-4)
           

摘自《Pytorch模型訓練實用教程》。詳情見:https://github.com/tensor-yu/PyTorch_Tutorial

繼續閱讀