• 6-1 pytorch中构建模型的3种方法


    可以使用以下3种方式构建模型:
    1,继承nn.Module基类构建自定义模型。
    2,使用nn.Sequential按层顺序构建模型。
    3,继承nn.Module基类构建模型并辅助应用模型容器进行封装(nn.Sequential,nn.ModuleList,nn.ModuleDict)。
    其中 第1种方式最为常见,第2种方式最简单,第3种方式最为灵活也较为复杂。
    推荐使用第1种方式构建模型。

    一、继承nn.Module基类构建自定义模型

    以下是继承nn.Module基类构建自定义模型的一个范例。模型中的用到的层一般在__init__函数中定义,然后在forward方法中定义模型的正向传播逻辑

    from torch import nn 
    class Net(nn.Module):
        
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = nn.Conv2d(in_channels=3,out_channels=32,kernel_size = 3)
            self.pool1 = nn.MaxPool2d(kernel_size = 2,stride = 2)
            self.conv2 = nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5)
            self.pool2 = nn.MaxPool2d(kernel_size = 2,stride = 2)
            self.dropout = nn.Dropout2d(p = 0.1)
            self.adaptive_pool = nn.AdaptiveMaxPool2d((1,1))
            self.flatten = nn.Flatten()
            self.linear1 = nn.Linear(64,32)
            self.relu = nn.ReLU()
            self.linear2 = nn.Linear(32,1)
            
        def forward(self,x):
            x = self.conv1(x)
            x = self.pool1(x)
            x = self.conv2(x)
            x = self.pool2(x)
            x = self.dropout(x)
            x = self.adaptive_pool(x)
            x = self.flatten(x)
            x = self.linear1(x)
            x = self.relu(x)
            y = self.linear2(x)
            return y
            
    net = Net()
    print(net)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    image.png

    from torchkeras import summary 
    summary(net,input_shape= (3,32,32));
    
    • 1
    • 2

    nn.Conv1d:普通一维卷积,常用于文本。参数个数 = 输入通道数×卷积核尺寸(如3)×卷积核个数 + 卷积核尺寸(如3)=卷积核尺寸(如3乘3)x输出通道数+输出通道数(偏置数量)
    nn.Conv2d:普通二维卷积,常用于图像。参数个数 = 输入通道数×卷积核尺寸(如3乘3)×卷积核个数 + 卷积核尺寸(如3乘3)。=卷积核尺寸(如3乘3)x输入通道数x输出通道数+输出通道数(偏置数量)) 通过调整dilation参数大于1,可以变成空洞卷积,增加感受野。 通过调整groups参数不为1,可以变成分组卷积。分组卷积中每个卷积核仅对其对应的一个分组进行操作。 当groups参数数量等于输入通道数时,相当于tensorflow中的二维深度卷积层tf.keras.layers.DepthwiseConv2D。 利用分组卷积和1乘1卷积的组合操作,可以构造相当于Keras中的二维深度可分离卷积层tf.keras.layers.SeparableConv2D。
    image.png

    二、使用nn.Sequential按层顺序构建模型

    使用nn.Sequential按层顺序构建模型无需定义forward方法仅仅适合于简单的模型。
    以下是使用nn.Sequential搭建模型的一些等价方法。

    利用add_module方法

    
    net = nn.Sequential()
    net.add_module("conv1",nn.Conv2d(in_channels=3,out_channels=32,kernel_size = 3))
    net.add_module("pool1",nn.MaxPool2d(kernel_size = 2,stride = 2))
    net.add_module("conv2",nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5))
    net.add_module("pool2",nn.MaxPool2d(kernel_size = 2,stride = 2))
    net.add_module("dropout",nn.Dropout2d(p = 0.1))
    net.add_module("adaptive_pool",nn.AdaptiveMaxPool2d((1,1)))
    net.add_module("flatten",nn.Flatten())
    net.add_module("linear1",nn.Linear(64,32))
    net.add_module("relu",nn.ReLU())
    net.add_module("linear2",nn.Linear(32,1))
    print(net)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    image.png

    利用变长参数

    这种方式构建时不能给每个层指定名称。

    net = nn.Sequential(
        nn.Conv2d(in_channels=3,out_channels=32,kernel_size = 3),
        nn.MaxPool2d(kernel_size = 2,stride = 2),
        nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5),
        nn.MaxPool2d(kernel_size = 2,stride = 2),
        nn.Dropout2d(p = 0.1),
        nn.AdaptiveMaxPool2d((1,1)),
        nn.Flatten(),
        nn.Linear(64,32),
        nn.ReLU(),
        nn.Linear(32,1)
    )
    
    print(net)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    image.png

    利用OrderedDict

    键值对形式:键为层的名字,值为层的定义

    from collections import OrderedDict
    
    net = nn.Sequential(OrderedDict(
              [("conv1",nn.Conv2d(in_channels=3,out_channels=32,kernel_size = 3)),
                ("pool1",nn.MaxPool2d(kernel_size = 2,stride = 2)),
                ("conv2",nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5)),
                ("pool2",nn.MaxPool2d(kernel_size = 2,stride = 2)),
                ("dropout",nn.Dropout2d(p = 0.1)),
                ("adaptive_pool",nn.AdaptiveMaxPool2d((1,1))),
                ("flatten",nn.Flatten()),
                ("linear1",nn.Linear(64,32)),
                ("relu",nn.ReLU()),
                ("linear2",nn.Linear(32,1))
              ])
            )
    print(net)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    image.png

    三、继承nn.Module基类构建模型并辅助应用模型容器进行封装

    当模型的结构比较复杂时,我们可以应用模型容器(nn.Sequential,nn.ModuleList,nn.ModuleDict)对模型的部分结构进行封装。
    这样做会让模型整体更加有层次感,有时候也能减少代码量。(复杂模型的时候比较常用)
    注意,在下面的范例中我们每次仅仅使用一种模型容器,但实际上这些模型容器的使用是非常灵活的,可以在一个模型中任意组合任意嵌套使用。
    相当于结合以上两种方式。

    nn.Sequential作为模型容器

    class Net(nn.Module):
        
        def __init__(self):
            super(Net, self).__init__()
            self.conv = nn.Sequential(
                nn.Conv2d(in_channels=3,out_channels=32,kernel_size = 3),
                nn.MaxPool2d(kernel_size = 2,stride = 2),
                nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5),
                nn.MaxPool2d(kernel_size = 2,stride = 2),
                nn.Dropout2d(p = 0.1),
                nn.AdaptiveMaxPool2d((1,1))
            )
            self.dense = nn.Sequential(
                nn.Flatten(),
                nn.Linear(64,32),
                nn.ReLU(),
                nn.Linear(32,1)
            )
        def forward(self,x):
            x = self.conv(x)
            y = self.dense(x)
            return y 
        
    net = Net()
    print(net)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    image.png

    nn.ModuleList作为模型容器

    注意下面中的ModuleList不能用Python中的列表代替。(即不用省略)

    class Net(nn.Module):
        
        def __init__(self):
            super(Net, self).__init__()
            self.layers = nn.ModuleList([
                nn.Conv2d(in_channels=3,out_channels=32,kernel_size = 3),
                nn.MaxPool2d(kernel_size = 2,stride = 2),
                nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5),
                nn.MaxPool2d(kernel_size = 2,stride = 2),
                nn.Dropout2d(p = 0.1),
                nn.AdaptiveMaxPool2d((1,1)),
                nn.Flatten(),
                nn.Linear(64,32),
                nn.ReLU(),
                nn.Linear(32,1)]
            )
        def forward(self,x):
            for layer in self.layers:
                x = layer(x)
            return x
    net = Net()
    print(net)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    image.png

    nn.ModuleDict作为模型容器

    注意下面中的ModuleDict不能用Python中的字典代替。

    class Net(nn.Module):
        
        def __init__(self):
            super(Net, self).__init__()
            self.layers_dict = nn.ModuleDict({"conv1":nn.Conv2d(in_channels=3,out_channels=32,kernel_size = 3),
                   "pool": nn.MaxPool2d(kernel_size = 2,stride = 2),
                   "conv2":nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5),
                   "dropout": nn.Dropout2d(p = 0.1),
                   "adaptive":nn.AdaptiveMaxPool2d((1,1)),
                   "flatten": nn.Flatten(),
                   "linear1": nn.Linear(64,32),
                   "relu":nn.ReLU(),
                   "linear2": nn.Linear(32,1)
                  })
        def forward(self,x):
            layers = ["conv1","pool","conv2","pool","dropout","adaptive",
                      "flatten","linear1","relu","linear2","sigmoid"]
            for layer in layers:
                x = self.layers_dict[layer](x) # 只找有的 sigmoid是没有的
            return x
    net = Net()
    print(net)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    image.png
    参考:https://github.com/lyhue1991/eat_pytorch_in_20_days

  • 相关阅读:
    Gradle转Maven项目图文及问题
    多商户商城系统功能拆解38讲-平台端营销-砍价商品
    JS数组排序
    C++深拷贝和浅拷贝
    eigen::Affine3d 转换
    JVM-虚拟机的故障处理与调优案例分析
    进程,线程,并发相关入门
    机器学习(6)——数据探索与可视化(2)
    MySQL面试题大全(陆续更新)
    养了个羊(简易版)
  • 原文地址:https://blog.csdn.net/hxhabcd123/article/details/132996782