获取模型中间层的权重和其他参数
#先设定如下网络
#定义网络结构
class net(nn.Module):
def __init__(self):
super().__init__()
self.c1 = nn.Sequential(
nn.Conv2d(3,16,5,1,2),
nn.ReLU()
)
self.c2 = nn.Sequential(
nn.Conv2d(16,32,5,1,2),
nn.ReLU(),
)
self.fc = nn.Linear(2097152,2)
def forward(self,x):
x = self.c1(x)
x = self.c2(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
model = net()
model = model.cuda()
#载入先前训练好并保存的模型权重
model.load_state_dict(torch.load('model_wts.pkl'))
#此时网络的结构为
model
>>
net(
(c1): Sequential(
(0): Conv2d(3, 16, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(1): ReLU()
)
(c2): Sequential(
(0): Conv2d(16, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(1): ReLU()
)
(fc): Linear(in_features=2097152, out_features=2, bias=True)
)
#获取某一层
model.c1
>>
Sequential(
(0): Conv2d(3, 16, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(1): ReLU()
)
model.fc
>>
Linear(in_features=1048576, out_features=2, bias=True)
#获取Sequential里的子层
model.c1[0]
>>
Conv2d(3, 16, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
#获得某层的权重
model.c1[0].weight
>>
Parameter containing:
tensor([[[[ 2.7182e-03, -8.7767e-03, 3.2988e-02, -1.0006e-01, -1.1177e-01],
[-2.9155e-02, -6.2152e-02, 4.1465e-02, -4.5812e-02, 6.7885e-02],
[-1.0680e-01, -1.0023e-01, -1.7158e-02, -1.3828e-02, 5.7319e-02],
[ 5.1668e-02, -4.2982e-02, 2.7770e-02, -1.1801e-01, 7.9863e-02],
[ 1.1050e-01, 2.4979e-02, 5.1047e-03, -4.6120e-02, -9.9121e-02]],
··························#省略
#参数
model.c1[0].parameters()为该层的参数,包含梯度等等
parameters()输出的参数在训练的时候需要传入优化器,比如在训练网络的时候,model的所有参数
都要传入优化器,则是 optimizer = torch.optim.Adam(model.parameters(),lr=LR)
又如下面一条迁移学习,只要训练最后一层,就只将最后一层的参数传入了优化器
#层的迭代器
for layer in model.SequentialName.children():
pass
#应用方法可以见下面迁移学习部分
所以如果要进行迁移学习
#以VGG举例
VGG的结构为
VGG{
(features):Sequential(....略....)
(classifier):Sequntial(....略.........(6)Linear(4096->1000))
}
#这里采用预训练的,[创建vgg网络实例]
vgg = models.vgg16(pretrained=True)
#[设置冻结层](只改变classifier里的最后一个线性层,特征提取层不变)
#冻结住特征提取层(vgg取名叫features)的参数
for param in vgg.features.parameters():
param.requires_grad=False
#[微调模型](只改变最后一层fc层,将1000类分类变为我想要的2类分类)
#注意如果用vgg.classifier[6].out_features = 2的话以后会遇到问题,输出还是1000种类
vgg.classifier[6] = nn.Linear(4096,2)
#优化器设置 (由于我们直接用预训练的权重,所以只需要训练分类器的参数,所以只将最后一个分类器层的classifier.parameters传入优化器)
optimizer = optim.SGD(vgg.classifier.parameters(),lr=0.0001,momentum=0.5)
#还可以继续对模型进行一些修改,比如修改最后一层中的dropout
#这里使用了迭代器
for layer in vgg.classifier.children():
if (type(layer) == nn.Dropout):
layer.p=0.2
使用pytorch hook进行中间层输出与可视化
(这里hook上面第一节中创建的网络)
#定义用于hook的类
class LayerActivations():
#定义这个变量用于储存结果
features = None
#类初始化。当前向传播的时候(即图像数据通过层传输的时候),调用register_forward_hook方法。
#register_forward_hook方法即为[钩子],此方法返回一个句柄保存到self.hook
def __init__(self,model,layer_num):
self.hook = model[layer_num].register_forward_hook(self.hook_fn)
#hook函数具体执行的方法,即hook方法
#register_forward_hook将三个参数传入hook_fn方法内
#module:允许访问层本身 input:流进层的数据 output:层变换后的流出的数据或激活
def hook_fn(self,module,input,output):
#将输出保存到[自己设置的features变量中]
self.features = output.cpu()
#注销句柄self.hook
def remove(self):
self.hook.remove()
#定义hook类实例
conv_out = LayerActivations(model.c1,0)
#运行模型
output = model(img)
#注销函数
conv_out.remove()
# 在hook class中被保存到了features变量的即为输出,自己定义的
activations = conv_out.features
#activations 即为层输出
#对其进行可视化
fig = plt.figure(figsize=(20,50))
fig.subplots_adjust(left=0,right=1,bottom=0,top=0.8,hspace=0,wspace=0.2)
for i in range(30):
ax = fig.add_subplot(12,5,i+1,xticks=[],yticks=[])
ax.imshow(activations[0][i].detach().numpy())
中间层参数可视化
有两种方法
#方法一
for param in nn.parameters():
xxx
#方法二
weight = model.state_dict()['features.0.weight']