模型参数字典加载
# this is pretrained
pretrained_dict = resnet50.state_dict()
# this is a new model's dict
model_dict = cnn.state_dict()
pretrained = {k:v for k,v in pretrained_dict.items() if k in model_dict.keys()}
# update model_dict
model_dict.update(pretrained)
cnn.load_state_dict(model_dict)
模型参数保存在字典中,其实上述代码就是筛选出预训练模型字典中,同样存在于cnn参数字典中的层,利用前者对后者赋值。
模型参数处理
获取模型的参数:
返回结果:
- 每一层的参数值;
- 是否包括梯度;(requires_grad=XXXX)
# 参数转为列表,每个列表元素包括每层的参数值
parameters = list(model.parameters())
也就是说按照model.parameters()来获取参数,将会得到模型所有的参数,但是这些参数的名称被省略掉。所以为了知道这些参数属于哪个模型,可以采用
model.named_parameters()
冻结部分参数
# 冻结前16层的参数(不参与训练)
for i, p in enumerate(model.parameters()):
if i < 16:
p.requires_grad = False # 由此看到,p是一个引用,改变p可以改变原model参数
冻结之后的参数不需要参与训练,同时也无需传入优化器;
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=0.001)
filter(function, iterable)
,其中的function是判断函数,返回的是布尔类型 当然也可以不用 enumerate 的方式进行冻结:Pytorch冻结部分层的参数
访问模型指定层
通常来说,模型每一层都有对应的名称,比如:
self.conv1 = nn.Conv2d(in_channels, out_channels, 3, padding=1)
获取指定层的属性
# 获取其属性
in_channels = self.conv1.in_channels
out_channels = self.conv1.out_channels
kernel_size = self.conv1.kernel_size
padding = self.conv1.padding
其中的conv1就可以被访问到
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):
super(FeatureExtractor,self).__init__()
self.submodule = submodule
self.extracted_layers= extracted_layers
def forward(self, x):
outputs = []
# modules和_modules的差别?(见后面)
for name, module in self.submodule._modules.items():
if name == "fc":
x = x.view(x.size(0), -1)
x = module(x) # this is important!
print(name)
if name in self.extracted_layers:
outputs.append(x)
return outputs
resnet = models.resnet50(pretrained=True) layes = [‘layer4’]
提取特征
feature = FeatureExtractor(resnet, layers)
值得注意的是:
- _modules是属性,而不是方法;(可以直接通过net._modules获取,从而打印)
- modules是方法,不是属性;(不能直接打印看到结果,但是可以先转为list,然后打印输出)
- 对于name和module的访问是按照模型__init__里面的顺序进行访问,如何该顺序和forward顺序不同,则会出错!
其它属性:
- _parameters;
- _modules;
常用方法:
- parameters;
- modules;
- children;
- named_children;
- train;
- eval;
- cpu; (model.cup())
- cuda; (model.cuda())
- zero_grad; (每次反向传播之前都需要将优化器zero_grad)
<a name="PuVC4"></a>
### children方法
children方法和module比较类似,都能获取模型的子模块;
```python
# 返回模型用到了那些module
for child in net.children():
print(child)
# 返回模型用到的module已经其名称
for child in net.named_children():
print(child)
我们的模型会转为一张图或者说一棵树,children含义应该就是树的孩子节点之类的
预训练参数加载
params = np.load(fname).item()
# vgg16
vgg16_dict = faster_rcnn_model.rpn.features.state_dict()
# for vgg16
for name, val in vgg16_dict.items():
if name.find('bn.') >= 0:
continue
i, j = int(name[4]), int(name[6]) + 1
ptype = 'weights' if name[-1] == 't' else 'biases'
key = 'conv{}_{}'.format(i, j)
param = torch.from_numpy(params[key][ptype])
if ptype == 'weights':
param = param.permute(3, 2, 0, 1)
val.copy_(param)