PyTorch保存模型與加載模型+Finetune預訓練模型使用


參數初始化參

數的初始化其實就是對參數賦值。而我們需要學習的參數其實都是Variable,它其實是對Tensor的封裝,同時提供了data,grad等借口,這就意味着我們可以直接對這些參數進行操作賦值了。這就是PyTorch簡潔高效所在。所以我們可以進行如下操作進行初始化,當然其實有其他的方法,但是這種方法是PyTorch作者所推崇的:

def weight_init(m):
# 使用isinstance來判斷m屬於什么類型
    if isinstance(m, nn.Conv2d):
        n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
        m.weight.data.normal_(0, math.sqrt(2. / n))
    elif isinstance(m, nn.BatchNorm2d):
# m中的weight,bias其實都是Variable,為了能學習參數以及后向傳播
        m.weight.data.fill_(1)
        m.bias.data.zero_()

Finetune

往往在加載了預訓練模型的參數之后,我們需要finetune模型,可以使用不同的方式finetune。
局部微調:有時候我們加載了訓練模型后,只想調節最后的幾層,其他層不訓練。其實不訓練也就意味着不進行梯度計算,PyTorch中提供的requires_grad使得對訓練的控制變得非常簡單。

model = torchvision.models.resnet18(pretrained=True)
for param in model.parameters():
    param.requires_grad = False
# 替換最后的全連接層, 改為訓練100類
# 新構造的模塊的參數默認requires_grad為True
model.fc = nn.Linear(512, 100)

# 只優化最后的分類層
optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)

全局微調:有時候我們需要對全局都進行finetune,只不過我們希望改換過的層和其他層的學習速率不一樣,這時候我們可以把其他層和新層在optimizer中單獨賦予不同的學習速率。比如:

ignored_params = list(map(id, model.fc.parameters()))
base_params = filter(lambda p: id(p) not in ignored_params,
                     model.parameters())

optimizer = torch.optim.SGD([
            {'params': base_params},
            {'params': model.fc.parameters(), 'lr': 1e-3}
            ], lr=1e-2, momentum=0.9)
其中base_params使用1e-3來訓練,model.fc.parameters使用1e-2來訓練,momentum是二者共有的。

加載部分預訓練模型:其實大多數時候我們需要根據我們的任務調節我們的模型,所以很難保證模型和公開的模型完全一樣,但是預訓練模型的參數確實有助於提高訓練的准確率,為了結合二者的優點,就需要我們加載部分預訓練模型。

pretrained_dict = model_zoo.load_url(model_urls['resnet152']) 
model_dict = model.state_dict()

# 將pretrained_dict里不屬於model_dict的鍵剔除掉
pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
# 更新現有的model_dict
model_dict.update(pretrained_dict)
# 加載我們真正需要的state_dict
model.load_state_dict(model_dict)

如果模型的key值和在大數據集上訓練時的key值是一樣的

我們可以通過下列算法進行讀取模型

    model_dict = model.state_dict()

    pretrained_dict = torch.load(model_path)
 # 1. filter out unnecessary keys
    diff = {k: v for k, v in model_dict.items() if \
            k in pretrained_dict and pretrained_dict[k].size() == v.size()}
    pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict and model_dict[k].size() == v.size()}
    pretrained_dict.update(diff)
    # 2. overwrite entries in the existing state dict
    model_dict.update(pretrained_dict)
    # 3. load the new state dict
    model.load_state_dict(model_dict)

如果模型的key值和在大數據集上訓練時的key值是不一樣的,但是順序是一樣的

    model_dict = model.state_dict()

    pretrained_dict = torch.load(model_path)
    keys = []
    for k,v in pretrained_dict.items():
        keys.append(k)
    i = 0
    for k,v in model_dict.items():
        if v.size() == pretrained_dict[keys[i]].size():
            print(k, ',', keys[i])
            model_dict[k]=pretrained_dict[keys[i]]
        i = i + 1
    model.load_state_dict(model_dict)

如果模型的key值和在大數據集上訓練時的key值是不一樣的,但是順序是也不一樣的

自己找對應關系,一個key對應一個key的賦值


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM