1. 程式人生 > >【深度學習】關於pytorch中使用pretrained的模型,對模型進行調整

【深度學習】關於pytorch中使用pretrained的模型,對模型進行調整

在pytorch中對model進行調整有多種方法。但是總有些莫名奇妙會報錯的。
下面有三種,詳情見部落格

一是載入完模型後直接修改,(對於resnet比較適用,對於vgg就不能用了)比如:
model.fc = nn.Linear(fc_features, 9)
這種情況,適用於修改的層,可以由self.層的名字獲取到。
如果層在sequential中。因為sequential型別沒有定義setitem,只有getitem 所以不能直接獲取某一層並進行修改。就是sequential[0]=nn.Linear(fc_features, 9)是會報錯的。(不知道有沒有別的方法。)
二是用引數覆蓋的方法

,即自己先定義一個類似的網路,再將預訓練中的引數提取到自己的網路中來。這裡以resnet預訓練模型舉例。
這個方法不太理解。。我還是不知道怎麼用到sequential裡面。。感覺改動會比較大。
通過state_dict() 去獲取每一層的名字並給予權重。就是新定義的網路要注意不能和pretrained的網路有同樣名字的層。
三是使用nn.module的model.children()的函式,重新定義自己model的層。這個比較靈活。
self.layer= nn.Sequential(*list(model.children())[:-2])
例如對於vgg11 我想修改成1channel輸入 ,輸出是100個類別的實現如下:修改和新增的程式碼比較少。

import torch.nn as nn
import torch.utils.model_zoo as model_zoo
import math

class VGG(nn.Module):

    def __init__(self, features, num_classes=1000, init_weights=True):
        super(VGG, self).__init__()
        self.features = features
        self.classifier = nn.Sequential(
            nn.Linear(512
* 7 * 7, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, num_classes), ) if init_weights: self._initialize_weights() def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) x = self.classifier(x) return x def _initialize_weights(self): for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') if m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.BatchNorm2d): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0) elif isinstance(m, nn.Linear): nn.init.normal_(m.weight, 0, 0.01) nn.init.constant_(m.bias, 0) def make_layers(cfg, batch_norm=False): layers = [] in_channels = 3 for v in cfg: if v == 'M': layers += [nn.MaxPool2d(kernel_size=2, stride=2)] else: conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) if batch_norm: layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)] else: layers += [conv2d, nn.ReLU(inplace=True)] in_channels = v return nn.Sequential(*layers) #生成一個1channel輸入的model def make_one_channel_layers(cfg, batch_norm=False): layers = [] in_channels = 1 for v in cfg: if v == 'M': layers += [nn.MaxPool2d(kernel_size=2, stride=2)] else: conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) if batch_norm: layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)] else: layers += [conv2d, nn.ReLU(inplace=True)] in_channels = v return nn.Sequential(*layers) cfg = { 'A': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], 'B': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], 'D': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'], 'E': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'], } def vgg11(pretrained=False, **kwargs): """VGG 11-layer model (configuration "A") Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ if pretrained: kwargs['init_weights'] = False model = VGG(make_layers(cfg['A']), **kwargs) #輸出為100個類別 mymodel=VGG(make_one_channel_layers(cfg['A']),num_classes=100, **kwargs) if pretrained: model.load_state_dict(model_zoo.load_url(model_urls['vgg11'])) #在預訓練好的model中選擇要的部分,拼接自己定義的mymodel型別部分 model.features=nn.Sequential(list(mymodel.features.children())[0],*list(model.features.children())[1:]) mymodel.classifier=nn.Sequential(*list(model.classifier.children())[:-1],list(mymodel.classifier.children())[-1]) return mymodel

呃。。。。。。。。。。。

其實不用上面那麼麻煩 直接修改需要修改的層就可以了像

model.features=nn.Sequential(nn.Conv2d(1, 96, kernel_size=7, stride=2),*list(model.features.children())[1:])

另外直接用
model_conv.classifier[6].out_features = Output_features
這樣直接修改引數,輸出模型是修改之後的,但是執行時還是會報錯Given groups=1, weight[64, 3, 3, 3], so expected input[32, 1, 224, 224] to have 3 channels, but got 1 channels 這樣的錯。。。所以。。不知道怎麼改,如果可以這樣的話,就會很方便呀!!!可是報錯。。。

附上部分更新模型引數的方法(新模型增加了一些層)

pretrained_dict = ...
model_dict = model.state_dict()
# 1. filter out unnecessary keys
pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
# 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)