模型参数字典加载

  1. # this is pretrained
  2. pretrained_dict = resnet50.state_dict()
  3. # this is a new model's dict
  4. model_dict = cnn.state_dict()
  5. pretrained = {k:v for k,v in pretrained_dict.items() if k in model_dict.keys()}
  6. # update model_dict
  7. model_dict.update(pretrained)
  8. cnn.load_state_dict(model_dict)

模型参数保存在字典中,其实上述代码就是筛选出预训练模型字典中,同样存在于cnn参数字典中的层,利用前者对后者赋值。

模型参数处理

获取模型的参数:
返回结果:

  • 每一层的参数值;
  • 是否包括梯度;(requires_grad=XXXX)
    1. # 参数转为列表,每个列表元素包括每层的参数值
    2. parameters = list(model.parameters())

    也就是说按照model.parameters()来获取参数,将会得到模型所有的参数,但是这些参数的名称被省略掉。所以为了知道这些参数属于哪个模型,可以采用model.named_parameters()

冻结部分参数

  1. # 冻结前16层的参数(不参与训练)
  2. for i, p in enumerate(model.parameters()):
  3. if i < 16:
  4. p.requires_grad = False # 由此看到,p是一个引用,改变p可以改变原model参数

冻结之后的参数不需要参与训练,同时也无需传入优化器;

  1. optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=0.001)

filter(function, iterable),其中的function是判断函数,返回的是布尔类型 当然也可以不用 enumerate 的方式进行冻结:Pytorch冻结部分层的参数

访问模型指定层

通常来说,模型每一层都有对应的名称,比如:

  1. self.conv1 = nn.Conv2d(in_channels, out_channels, 3, padding=1)

获取指定层的属性

  1. # 获取其属性
  2. in_channels = self.conv1.in_channels
  3. out_channels = self.conv1.out_channels
  4. kernel_size = self.conv1.kernel_size
  5. padding = self.conv1.padding

其中的conv1就可以被访问到

  1. model.conv1 = nn.Conv2d(3, 16, 5, padding=2)

对该属性进行修改,就可以改变网络结构。(说白了,就是一个类而已)

  • 值得一提的是,pytorch打印模型,输出的就是模型中对应的这些属性;(不管有没有参与前向传播)
  • 其实这些层和模型本来都是继承自nn.Module,很大属性都相同!

    提取模型中间层特征

    就是遍历模型的module,将输入不断通过module直到指定的中间层。 ```python

    遍历模型的module进行前向传播

    class FeatureExtractor(nn.Module): def init(self, submodule, extracted_layers):

    1. super(FeatureExtractor,self).__init__()
    2. self.submodule = submodule
    3. self.extracted_layers= extracted_layers

    def forward(self, x):

    1. outputs = []
    2. # modules和_modules的差别?(见后面)
    3. for name, module in self.submodule._modules.items():
    4. if name == "fc":
    5. x = x.view(x.size(0), -1)
    6. x = module(x) # this is important!
    7. print(name)
    8. if name in self.extracted_layers:
    9. outputs.append(x)
    10. return outputs

resnet = models.resnet50(pretrained=True) layes = [‘layer4’]

提取特征

feature = FeatureExtractor(resnet, layers)

  1. 值得注意的是:
  2. - _modules是属性,而不是方法;(可以直接通过net._modules获取,从而打印)
  3. - modules是方法,不是属性;(不能直接打印看到结果,但是可以先转为list,然后打印输出)
  4. - 对于namemodule的访问是按照模型__init__里面的顺序进行访问,如何该顺序和forward顺序不同,则会出错!
  5. 其它属性:
  6. - _parameters;
  7. - _modules;
  8. 常用方法:
  9. - parameters;
  10. - modules;
  11. - children;
  12. - named_children;
  13. - train;
  14. - eval;
  15. - cpu; (model.cup())
  16. - cuda; (model.cuda())
  17. - zero_grad; (每次反向传播之前都需要将优化器zero_grad
  18. <a name="PuVC4"></a>
  19. ### children方法
  20. children方法和module比较类似,都能获取模型的子模块;
  21. ```python
  22. # 返回模型用到了那些module
  23. for child in net.children():
  24. print(child)
  25. # 返回模型用到的module已经其名称
  26. for child in net.named_children():
  27. print(child)

我们的模型会转为一张图或者说一棵树,children含义应该就是树的孩子节点之类的

预训练参数加载

  1. params = np.load(fname).item()
  2. # vgg16
  3. vgg16_dict = faster_rcnn_model.rpn.features.state_dict()
  4. # for vgg16
  5. for name, val in vgg16_dict.items():
  6. if name.find('bn.') >= 0:
  7. continue
  8. i, j = int(name[4]), int(name[6]) + 1
  9. ptype = 'weights' if name[-1] == 't' else 'biases'
  10. key = 'conv{}_{}'.format(i, j)
  11. param = torch.from_numpy(params[key][ptype])
  12. if ptype == 'weights':
  13. param = param.permute(3, 2, 0, 1)
  14. val.copy_(param)