Skip to content

Latest commit

 

History

History
513 lines (428 loc) · 16.2 KB

6-1,构建模型的3种方法.md

File metadata and controls

513 lines (428 loc) · 16.2 KB

6-1, 3 ways to build a model

You can use the following 3 ways to build a model:

  1. Inherit the nn.Module base class to build a custom model.

  2. Use nn.Sequential to build the model in layer order.

  3. Inherit the nn.Module base class to build a model and assist the application model container to encapsulate (nn.Sequential, nn.ModuleList, nn.ModuleDict).

Among them, the first method is the most common, the second method is the simplest, and the third method is the most flexible and more complex.

It is recommended to use the first method to build the model.

import torch
from torch import nn
from torchkeras import summary

One, inherit the nn.Module base class to build a custom model

The following is an example of building a custom model by inheriting the nn.Module base class. The layers used in the model are generally defined in the __init__ function, and then the forward propagation logic of the model is defined in the forward method.

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)
        self.sigmoid = nn.Sigmoid()
        
    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)
        x = self.linear2(x)
        y = self.sigmoid(x)
        return y
        
net = Net()
print(net)
Net(
  (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
  (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1))
  (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (dropout): Dropout2d(p=0.1, inplace=False)
  (adaptive_pool): AdaptiveMaxPool2d(output_size=(1, 1))
  (flatten): Flatten()
  (linear1): Linear(in_features=64, out_features=32, bias=True)
  (relu): ReLU()
  (linear2): Linear(in_features=32, out_features=1, bias=True)
  (sigmoid): Sigmoid()
)
summary(net,input_shape= (3,32,32))
-------------------------------------------------- --------------
        Layer (type) Output Shape Param #
================================================= ==============
            Conv2d-1 [-1, 32, 30, 30] 896
         MaxPool2d-2 [-1, 32, 15, 15] 0
            Conv2d-3 [-1, 64, 11, 11] 51,264
         MaxPool2d-4 [-1, 64, 5, 5] 0
         Dropout2d-5 [-1, 64, 5, 5] 0
 AdaptiveMaxPool2d-6 [-1, 64, 1, 1] 0
           Flatten-7 [-1, 64] 0
            Linear-8 [-1, 32] 2,080
              ReLU-9 [-1, 32] 0
           Linear-10 [-1, 1] 33
          Sigmoid-11 [-1, 1] 0
================================================= ==============
Total params: 54,273
Trainable params: 54,273
Non-trainable params: 0
-------------------------------------------------- --------------
Input size (MB): 0.011719
Forward/backward pass size (MB): 0.359634
Params size (MB): 0.207035
Estimated Total Size (MB): 0.578388
-------------------------------------------------- --------------

Second, use nn.Sequential to build the model in layer order

Use nn.Sequential to build a model in layer order without defining the forward method. Only suitable for simple models.

The following are some equivalent ways to build models using nn.Sequential.

  1. Use the add_module method
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))
net.add_module("sigmoid",nn.Sigmoid())

print(net)
Sequential(
  (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
  (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1))
  (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (dropout): Dropout2d(p=0.1, inplace=False)
  (adaptive_pool): AdaptiveMaxPool2d(output_size=(1, 1))
  (flatten): Flatten()
  (linear1): Linear(in_features=64, out_features=32, bias=True)
  (relu): ReLU()
  (linear2): Linear(in_features=32, out_features=1, bias=True)
  (sigmoid): Sigmoid()
)
  1. Using variable length parameters

When constructing in this way, you cannot assign a name to each layer.

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),
    nn.Sigmoid()
)

print(net)
Sequential(
  (0): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
  (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1))
  (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (4): Dropout2d(p=0.1, inplace=False)
  (5): AdaptiveMaxPool2d(output_size=(1, 1))
  (6): Flatten()
  (7): Linear(in_features=64, out_features=32, bias=True)
  (8): ReLU()
  (9): Linear(in_features=32, out_features=1, bias=True)
  (10): Sigmoid()
)
  1. Use 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)),
            ("sigmoid",nn.Sigmoid())
          ])
        )
print(net)
Sequential(
  (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
  (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1))
  (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (dropout): Dropout2d(p=0.1, inplace=False)
  (adaptive_pool): AdaptiveMaxPool2d(output_size=(1, 1))
  (flatten): Flatten()
  (linear1): Linear(in_features=64, out_features=32, bias=True)
  (relu): ReLU()
  (linear2): Linear(in_features=32, out_features=1, bias=True)
  (sigmoid): Sigmoid()
)
summary(net,input_shape= (3,32,32))
-------------------------------------------------- --------------
        Layer (type) Output Shape Param #
================================================= ==============
            Conv2d-1 [-1, 32, 30, 30] 896
         MaxPool2d-2 [-1, 32, 15, 15] 0
            Conv2d-3 [-1, 64, 11, 11] 51,264
         MaxPool2d-4 [-1, 64, 5, 5] 0
         Dropout2d-5 [-1, 64, 5, 5] 0
 AdaptiveMaxPool2d-6 [-1, 64, 1, 1] 0
           Flatten-7 [-1, 64] 0
            Linear-8 [-1, 32] 2,080
              ReLU-9 [-1, 32] 0
           Linear-10 [-1, 1] 33
          Sigmoid-11 [-1, 1] 0
================================================= ==============
Total params: 54,273
Trainable params: 54,273
Non-trainable params: 0
-------------------------------------------------- --------------
Input size (MB): 0.011719
Forward/backward pass size (MB): 0.359634
Params size (MB): 0.207035
Estimated Total Size (MB): 0.578388
-------------------------------------------------- --------------

Third, inherit the nn.Module base class to build a model and assist the application model container to encapsulate

When the structure of the model is more complex, we can use the model container (nn.Sequential, nn.ModuleList, nn.ModuleDict) to encapsulate part of the model structure.

Doing so will make the overall model more hierarchical and sometimes reduce the amount of code.

Note that in the following example we only use one model container at a time, but in fact the use of these model containers is very flexible and can be used in any combination and nesting in a model.

  1. nn.Sequential as a model container
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),
            nn.Sigmoid()
        )
    def forward(self,x):
        x = self.conv(x)
        y = self.dense(x)
        return y
    
net = Net()
print(net)
Net(
  (conv): Sequential(
    (0): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
    (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1))
    (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (4): Dropout2d(p=0.1, inplace=False)
    (5): AdaptiveMaxPool2d(output_size=(1, 1))
  )
  (dense): Sequential(
    (0): Flatten()
    (1): Linear(in_features=64, out_features=32, bias=True)
    (2): ReLU()
    (3): Linear(in_features=32, out_features=1, bias=True)
    (4): Sigmoid()
  )
)
  1. nn.ModuleList as a model container

Note that the ModuleList in the following cannot be replaced by a list in 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),
            nn.Sigmoid()]
        )
    def forward(self,x):
        for layer in self.layers:
            x = layer(x)
        return x
net = Net()
print(net)
Net(
  (layers): ModuleList(
    (0): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
    (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1))
    (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (4): Dropout2d(p=0.1, inplace=False)
    (5): AdaptiveMaxPool2d(output_size=(1, 1))
    (6): Flatten()
    (7): Linear(in_features=64, out_features=32, bias=True)
    (8): ReLU()
    (9): Linear(in_features=32, out_features=1, bias=True)
    (10): Sigmoid()
  )
)
summary(net,input_shape= (3,32,32))
-------------------------------------------------- --------------
        Layer (type) Output Shape Param #
================================================= ==============
            Conv2d-1 [-1, 32, 30, 30] 896
         MaxPool2d-2 [-1, 32, 15, 15] 0
            Conv2d-3 [-1, 64, 11, 11] 51,264
         MaxPool2d-4 [-1, 64, 5, 5] 0
         Dropout2d-5 [-1, 64, 5, 5] 0
 AdaptiveMaxPool2d-6 [-1, 64, 1, 1] 0
           Flatten-7 [-1, 64] 0
            Linear-8 [-1, 32] 2,080
              ReLU-9 [-1, 32] 0
           Linear-10 [-1, 1] 33
          Sigmoid-11 [-1, 1] 0
================================================= ==============
Total params: 54,273
Trainable params: 54,273
Non-trainable params: 0
-------------------------------------------------- --------------
Input size (MB): 0.011719
Forward/backward pass size (MB): 0.359634
Params size (MB): 0.207035
Estimated Total Size (MB): 0.578388
-------------------------------------------------- --------------
  1. nn.ModuleDict as a model container

Note that ModuleDict in the following cannot be replaced by a dictionary in 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),
               "sigmoid": nn.Sigmoid()
              })
    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)
        return x
net = Net()
print(net)
Net(
  (layers_dict): ModuleDict(
    (adaptive): AdaptiveMaxPool2d(output_size=(1, 1))
    (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
    (conv2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1))
    (dropout): Dropout2d(p=0.1, inplace=False)
    (flatten): Flatten()
    (linear1): Linear(in_features=64, out_features=32, bias=True)
    (linear2): Linear(in_features=32, out_features=1, bias=True)
    (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (relu): ReLU()
    (sigmoid): Sigmoid()
  )
)
summary(net,input_shape= (3,32,32))
-------------------------------------------------- --------------
        Layer (type) Output Shape Param #
================================================= ==============
            Conv2d-1 [-1, 32, 30, 30] 896
         MaxPool2d-2 [-1, 32, 15, 15] 0
            Conv2d-3 [-1, 64, 11, 11] 51,264
         MaxPool2d-4 [-1, 64, 5, 5] 0
         Dropout2d-5 [-1, 64, 5, 5] 0
 AdaptiveMaxPool2d-6 [-1, 64, 1, 1] 0
           Flatten-7 [-1, 64] 0
            Linear-8 [-1, 32] 2,080
              ReLU-9 [-1, 32] 0
           Linear-10 [-1, 1] 33
          Sigmoid-11 [-1, 1] 0
================================================= ==============
Total params: 54,273
Trainable params: 54,273
Non-trainable params: 0
-------------------------------------------------- --------------
Input size (MB): 0.011719
Forward/backward pass size (MB): 0.359634
Params size (MB): 0.207035
Estimated Total Size (MB): 0.578388
-------------------------------------------------- --------------

If this book is helpful to you and want to encourage the author, remember to add a star⭐️ to this project and share it with your friends 😊!

If you need to further communicate with the author on the understanding of the content of this book, please leave a message under the public account "Algorithm Food House". The author has limited time and energy and will respond as appropriate.

You can also reply to keywords in the background of the official account: Add group, join the reader exchange group and discuss with you.

算法美食屋logo.png