pytorch学习笔记十五:查看模型的层(子模块)的几种方式

首先我们先搭建一个模型:

import torch 
from torch import nn 
import torch.nn.functional  as F

class Net(nn.Module):
    
    def __init__(self):
        super(Net, self).__init__()
        
        self.embedding = nn.Embedding(num_embeddings = 10000,
        							  embedding_dim = 3,padding_idx = 1)
        self.conv = nn.Sequential()
        self.conv.add_module("conv_1",nn.Conv1d(in_channels = 3,
        					  out_channels = 16,kernel_size = 5))
        self.conv.add_module("pool_1",nn.MaxPool1d(kernel_size = 2))
        self.conv.add_module("relu_1",nn.ReLU())
        self.conv.add_module("conv_2",nn.Conv1d(in_channels = 16,
        										out_channels = 128,
        										kernel_size = 2))
        self.conv.add_module("pool_2",nn.MaxPool1d(kernel_size = 2))
        self.conv.add_module("relu_2",nn.ReLU())
        
        self.dense = nn.Sequential()
        self.dense.add_module("flatten",nn.Flatten())
        self.dense.add_module("linear",nn.Linear(6144,1))
        self.dense.add_module("sigmoid",nn.Sigmoid())
        
    def forward(self,x):
        x = self.embedding(x).transpose(1,2)
        x = self.conv(x)
        y = self.dense(x)
        return y

net = Net()

一、.modules(),返回一个生成器,包括模块下的所有各个层级的模块,也包括模块本身

1、先打印看一下返回值:

print(list(net.modules()))

输出

[Net(
  (embedding): Embedding(10000, 3, padding_idx=1)
  (conv): Sequential(
    (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
    (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (relu_1): ReLU()
    (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
    (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (relu_2): ReLU()
  )
  (dense): Sequential(
    (flatten): Flatten()
    (linear): Linear(in_features=6144, out_features=1, bias=True)
    (sigmoid): Sigmoid()
  )
), 

Embedding(10000, 3, padding_idx=1), 

Sequential(
  (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
  (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_1): ReLU()
  (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
  (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_2): ReLU()
), 
Conv1d(3, 16, kernel_size=(5,), stride=(1,)), 
MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False), ReLU(), 
Conv1d(16, 128, kernel_size=(2,), stride=(1,)), 
MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False), ReLU(), 

Sequential(
  (flatten): Flatten()
  (linear): Linear(in_features=6144, out_features=1, bias=True)
  (sigmoid): Sigmoid()
), 
Flatten(), 
Linear(in_features=6144, out_features=1, bias=True), 
Sigmoid()]

可以看出该属性返回的信息比较多,你可以理解为它会一级一级的返回信息,先返回整个模块本身,然后是第一级子模块,然后再返回各个一级子模块里的子模块,也就是二级子模块。其实只要具体的模型具体分析,每次都按照上述方式打印出来看一看这些子模块是怎样保存的,那么就可以正确的索引到你想要的某一特定层。

2、下面就来获取指定的某一层,然后获取之后还能获取该层的属性信息:

modules=list(net.modules())
print(modules[2][1])
print(modules[2][1].kernel_size,modules[2][1].ceil_mode)

输出

MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)

2 False

二、.named_modules(),返回一个生成器,包括模块下的所有各个层级的模块以及它们的名字,也包括模块本身

1、先打印看一下返回值:

print(list(net.named_modules()))

输出

[('', Net(
  (embedding): Embedding(10000, 3, padding_idx=1)
  (conv): Sequential(
    (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
    (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (relu_1): ReLU()
    (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
    (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (relu_2): ReLU()
  )
  (dense): Sequential(
    (flatten): Flatten()
    (linear): Linear(in_features=6144, out_features=1, bias=True)
    (sigmoid): Sigmoid()
  )
)), 


('embedding', Embedding(10000, 3, padding_idx=1)), 


('conv', Sequential(
  (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
  (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_1): ReLU()
  (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
  (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_2): ReLU()
)), 
('conv.conv_1', Conv1d(3, 16, kernel_size=(5,), stride=(1,))), 
('conv.pool_1', MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)), 
('conv.relu_1', ReLU()), 
('conv.conv_2', Conv1d(16, 128, kernel_size=(2,), stride=(1,))), 
('conv.pool_2', MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)), 
('conv.relu_2', ReLU()), 


('dense', Sequential(
  (flatten): Flatten()
  (linear): Linear(in_features=6144, out_features=1, bias=True)
  (sigmoid): Sigmoid()
)), 
('dense.flatten', Flatten()), 
('dense.linear', Linear(in_features=6144, out_features=1, bias=True)), 
('dense.sigmoid', Sigmoid())]

2、下面就来获取指定的某一层,然后获取之后还能获取该层的属性信息:

modules=list(net.named_modules())
print(modules[2][1][1])
print(modules[2][1][1].kernel_size,modules[2][1][1].ceil_mode)

输出

MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)

2 False

可以看出,和第一种方式相比,我们取的是同一层,但是在索引上多了一维,那是因为每一层的名称占了一维。

三、._modules,返回的是一个有序字典,里面包含了各个一级子模块,不包含本身,也不包含更低级的子模块。

1、先打印看一下返回值:

print(net._modules)

输出

OrderedDict([('embedding', Embedding(10000, 3, padding_idx=1)), 

('conv', Sequential(
  (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
  (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_1): ReLU()
  (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
  (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_2): ReLU()
)), 

('dense', Sequential(
  (flatten): Flatten()
  (linear): Linear(in_features=6144, out_features=1, bias=True)
  (sigmoid): Sigmoid()
))])

2、再遍历一下该字典,注意需要遍历其.items()属性:

for name,layer in net._modules.items():
    print(name)
    print(layer)

输出

embedding
Embedding(10000, 3, padding_idx=1)

conv
Sequential(
  (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
  (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_1): ReLU()
  (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
  (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_2): ReLU()
)

dense
Sequential(
  (flatten): Flatten()
  (linear): Linear(in_features=6144, out_features=1, bias=True)
  (sigmoid): Sigmoid()
)

可以看出,和.modules()相比,返回的信息简洁了很多,因为它只返回第一级子模块,没有继续的返回各个子模块的子模块。

3、下面我们就来看一下如何去除具体的某一层,并打印出该层的属性:

modules=net._modules
print(modules['conv'][0])
print(modules['conv'][0].kernel_size,modules['conv'][0].stride)

输出

Conv1d(3, 16, kernel_size=(5,), stride=(1,))
(5,) (1,)

四、children() : 返回一个生成器,包括模块下的所有子模块

print(list(net.children()))

输出

[Embedding(10000, 3, padding_idx=1), 
 
 Sequential(
  (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
  (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_1): ReLU()
  (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
  (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_2): ReLU()
), 

Sequential(
  (flatten): Flatten()
  (linear): Linear(in_features=6144, out_features=1, bias=True)
  (sigmoid): Sigmoid()
)]

五、named_children():返回一个生成器,包括模块下的所有子模块,以及它们的名字

print(list(net.named_children()))

输出

[('embedding', Embedding(10000, 3, padding_idx=1)), 

 ('conv', Sequential(
  (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
  (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_1): ReLU()
  (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
  (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (relu_2): ReLU()
)), 

('dense', Sequential(
  (flatten): Flatten()
  (linear): Linear(in_features=6144, out_features=1, bias=True)
  (sigmoid): Sigmoid()
))]

六、小结

可以看到,当返回的是生成器的时候,我们需要使用list将其变成能够显示具体内容的列表,否则直接打印的话是不显示具体内容的。当然我们可以直接遍历该生成器,此时就不需要使用list了。

你可能感兴趣的:(PyTorch学习笔记,python,pytorch,深度学习)