PyTorch中两种模型构造方式区别分析-普通前向传递与nn.Sequential()

PyTorch代码中存在两种常用的模型构造方式

1.普通方法——在构造函数中定义模型不同的层,在forward函数中输入的X依据指定的顺序进行前向传递

import torch
import torch.nn as nn

class Net(nn.Module):
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net, self).__init__()
        self.hidden = nn.Linear(n_feature, n_hidden)
        self.predict = nn.Linear(n_hidden, n_output)

    def forward(self, x):
        x = F.relu(self.hidden(x))      # hidden后接relu层
        x = self.predict(x)
        return x

model_1 = Net(1, 10, 1)
print(model_1)


'''运行结果为:

Net(
  (hidden): Linear(in_features=1, out_features=10, bias=True)
  (predict): Linear(in_features=10, out_features=1, bias=True)
)

'''

2.使用nn.Sequential按顺序构造所有层,在forward函数中直接调用

nn.Sequential的特点:将容器视为单个模块,即一个模块可以包含许多层

nn.Sequential有三种常见定义模型的方式:

① 基本实现方式:顺序定义每一层,特点:每一层没有名字,仅能通过下标访问各层

import torch
import torch.nn as nn

class Net(nn.Module):
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net,self).__init__()
        self.net_1 = nn.Sequential(
            nn.Linear(n_feature, n_hidden),
            nn.ReLU(),
            nn.Linear(n_hidden, n_output)
        )
    
    def forward(self,x):
        x = self.net_1(x)
        return x

model_2 = Net(1,10,1)
print(model_2)


'''运行结果为:

Net(
  (net_1): Sequential(
    (0): Linear(in_features=1, out_features=10, bias=True)
    (1): ReLU()
    (2): Linear(in_features=10, out_features=1, bias=True)
  )
)

'''

② 给每一层自定义名称

import torch.nn as nn
from collections import OrderedDict


model = nn.Sequential(OrderedDict([
     ('conv1', nn.Conv2d(1, 20, 5)),
     ('relu1', nn.ReLU()),
     ('conv2', nn.Conv2d(20, 64, 5)),
     ('relu2', nn.ReLU())
 ]))
 
 print(model)
 print(model[2])  # 通过索引获取第几个层
 print(model.conv1)

 '''运行结果为:

 Sequential(
   (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
   (relu1): ReLU()
   (conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
   (relu2): ReLU()
 )
 Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
 Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))

 '''

③ 使用add_module方法逐层加入Sequential中,该方法是从nn.Module类继承而来,nn.Sequental本身没有该方法,可通过自定义名称访问。

 1 import torch.nn as nn
 2 from collections import OrderedDict
 3 

 4 model = nn.Sequential()
 5 model.add_module("conv1", nn.Conv2d(1, 20, 5))
 6 model.add_module('relu1', nn.ReLU())
 7 model.add_module('conv2', nn.Conv2d(20, 64, 5))
 8 model.add_module('relu2', nn.ReLU())
 9 
10 print(model)
11 print(model[2])  # 通过索引获取第几个层
12 print(model.conv1)


13 '''运行结果为:

14 Sequential(
15   (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
16   (relu1): ReLU()
17   (conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
18   (relu2): ReLU()
19 )
20 Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
21 Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))

22 '''

通过观察两种不同的模型构造方式,可以发现以下区别:

① nn.Sequential在模型定义和前向传递过程中,定义的层只需出现一次,可以简化代码

② 普通模型构造方法需要多个函数嵌套,在模型较大,层数较多时会非常混乱,容易出错

③ nn.Sequential是将内部各模块按顺序排列的,因此不适合实现特殊结构,比如ResNet就无法使用nn.Sequential完整表示出来(这是普通方法构造模型的必然性)

④ 较小的模型可以使用nn.Sequential或者普通方法构造模型,较大的模型可以使用nn.Sequential方法,比较复杂的模型可以结合两者优点,来达到既简化模型,又灵活实现的目的。

参考资料 :



(45条消息) nn.Sequential方法介绍_Raywit的博客-CSDN博客_nn.sequential

1、nn.Sequential类-使用Sequential类来自定义顺序连接模型 - 小吴的日常 - 博客园 (cnblogs.com)

最后:

受作者水平限制,文章可能有内容描述不够准确恰当,欢迎在评论中指出,文章将持续更新

谢谢!

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