1. 程式人生 > >nn.moduleList 和Sequential由來、用法和例項 —— 寫網路模型

nn.moduleList 和Sequential由來、用法和例項 —— 寫網路模型

對於cnn前饋神經網路如果前饋一次寫一個forward函式會有些麻煩,在此就有兩種簡化方式,ModuleList和Sequential。其中Sequential是一個特殊的module,它包含幾個子Module,前向傳播時會將輸入一層接一層的傳遞下去。ModuleList也是一個特殊的module,可以包含幾個子module,可以像用list一樣使用它,但不能直接把輸入傳給ModuleList。下面舉例說明。


目錄

一、nn.Sequential()物件

1、模型建立方式

第一種寫法:

 第二種寫法:

第三種寫法:

2、檢查以及呼叫模型

檢視模型

根據名字或序號提取子Module物件

呼叫模型

二、nn.ModuleList()物件

為什麼有他?

什麼時候用?

和list的區別?

1. extend和append方法

2. 建立以及使用方法

3. yolo v3構建網路


一、nn.Sequential()物件

建立nn.Sequential()物件,必須小心確保一個塊的輸出大小與下一個塊的輸入大小匹配。基本上,它的行為就像一個nn.Module。

 

1、模型建立方式

第一種寫法:

nn.Sequential()物件.add_module(層名,層class的例項)

1

2

3

4

net1 = nn.Sequential()

net1.add_module('conv', nn.Conv2d(333))

net1.add_module('batchnorm', nn.BatchNorm2d(3))

net1.add_module('activation_layer', nn.ReLU())

 第二種寫法:

nn.Sequential(*多個層class的例項)

1

2

3

4

5

net2 = nn.Sequential(

        nn.Conv2d(333),

        nn.BatchNorm2d(3),

        nn.ReLU()

        )

第三種寫法:

nn.Sequential(OrderedDict([*多個(層名,層class的例項)]))

1

2

3

4

5

6

from collections import OrderedDict

net3= nn.Sequential(OrderedDict([

          ('conv', nn.Conv2d(333)),

          ('batchnorm', nn.BatchNorm2d(3)),

          ('activation_layer', nn.ReLU())

        ]))

 

 

2、檢查以及呼叫模型

檢視模型

print物件即可

1

2

3

print('net1:', net1)

print('net2:', net2)

print('net3:', net3)

net1: Sequential(
  (conv): Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1))
  (batchnorm): BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True)
  (activation_layer): ReLU()
)
net2: Sequential(
  (0): Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1))
  (1): BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True)
  (2): ReLU()
)
net3: Sequential(
  (conv): Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1))
  (batchnorm): BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True)
  (activation_layer): ReLU()
)

根據名字或序號提取子Module物件

1

2

# 可根據名字或序號取出子module

net1.conv, net2[0], net3.conv

(Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1)),
 Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1)),
 Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1)))

呼叫模型

可以直接網路物件(輸入資料),也可以使用上面的Module子物件分別傳入(input)。

1

2

3

4

5

input = V(t.rand(1344))

output = net1(input)

output = net2(input)

output = net3(input)

output = net3.activation_layer(net1.batchnorm(net1.conv(input)))

 

二、nn.ModuleList()物件

為什麼有他?

寫一個module然後就寫foreword函式很麻煩,所以就有了這兩個。它被設計用來儲存任意數量nn. module

什麼時候用?

如果在建構函式__init__中用到list、tuple、dict等物件時,一定要思考是否應該用ModuleList或ParameterList代替。

如果你想設計一個神經網路的層數作為輸入傳遞。

和list的區別?

ModuleListModule的子類,當在Module中使用它的時候,就能自動識別為子module。

當新增 nn.ModuleList 作為 nn.Module 物件的一個成員時(即當我們新增模組到我們的網路時),所有 nn.ModuleList 內部的 nn.Module 的 parameter 也被新增作為 我們的網路的 parameter

 

class MyModule(nn.Module):
    def __init__(self):
        super(MyModule, self).__init__()
        self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(10)])

    def forward(self, x):
        # ModuleList can act as an iterable, or be indexed         using ints
        for i, l in enumerate(self.linears):
            x = self.linears[i // 2](x) + l(x)
        return x

1. extend和append方法

nn.moduleList定義物件後,有extend和append方法,用法和python中一樣,extend是新增另一個modulelist  append是新增另一個module

class LinearNet(nn.Module):
  def __init__(self, input_size, num_layers, layers_size, output_size):
     super(LinearNet, self).__init__()
 
     self.linears = nn.ModuleList([nn.Linear(input_size, layers_size)])
     self.linears.extend([nn.Linear(layers_size, layers_size) for i in range(1, self.num_layers-1)])
     self.linears.append(nn.Linear(layers_size, output_size)

2. 建立以及使用方法

建立以及使用方法如下,

1

2

3

4

5

6

modellist = nn.ModuleList([nn.Linear(3,4), nn.ReLU(), nn.Linear(4,2)])

input = V(t.randn(13))

for model in modellist:

    input = model(input)

# 下面會報錯,因為modellist沒有實現forward方法

# output = modelist(input)

 

和普通list不一樣,它和torch的其他機制結合緊密,繼承了nn.Module的網路模型class可以使用nn.ModuleList並識別其中的parameters,當然這只是個list,不會自動實現forward方法,

1

2

3

4

5

6

7

8

9

class MyModule(nn.Module):

    def __init__(self):

        super(MyModule, self).__init__()

        self.list = [nn.Linear(34), nn.ReLU()]

        self.module_list = nn.ModuleList([nn.Conv2d(333), nn.ReLU()])

    def forward(self):

        pass

model = MyModule()

print(model)

MyModule(
  (module_list): ModuleList(
    (0): Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1))
    (1): ReLU()
  )
)

1

2

for name, param in model.named_parameters():

    print(name, param.size())

('module_list.0.weight', torch.Size([3, 3, 3, 3]))
('module_list.0.bias', torch.Size([3]))

可見,普通list中的子module並不能被主module所識別,而ModuleList中的子module能夠被主module所識別。這意味著如果用list儲存子module,將無法調整其引數,因其未加入到主module的引數中。

除ModuleList之外還有ParameterList,其是一個可以包含多個parameter的類list物件。在實際應用中,使用方式與ModuleList類似。

 

3. yolo v3構建網路

首先module_list = nn.ModuleList()

然後 

  for index, x in enumerate(blocks[1:]):#根據不同的block 遍歷module

        module = nn.Sequential()

        然後根據cfg讀進來的資料,

        module.add_module("batch_norm_{0}".format(index), bn)

        module.add_module("conv_{0}".format(index), conv)

         等等

         module_list.append(module)