首页 > 解决方案 > 激活没有变量分配的pytorch网络节点?

问题描述

在 PyTorch 网络的教程中,我们通常会看到如下实现:

from torch.nn.functional import hardtanh, sigmoid
import torch.nn as nn

class great_network(nn.Module):
    def __init__(self):
        super(great_network, self).__init__()  
        self.layer1 = nn.Conv2d(2, 2, 3)
        self.pool_1 = nn.MaxPool2d(1, 1)
        self.layer3 = nn.ConvTranspose2d(2, 2, 3)
        self.out_layer = nn.Conv2d(1, 1, 3)

    def forward(self, x):
        x = hardtanh(self.layer1(x))
        x = self.pool_1(x)
        x = hardtanh(self.layer3(x))
        x = sigmoid(self.out_layer(x))
        return x
    
net = great_network()
print(net)

great_network(
  (layer1): Conv2d(2, 2, kernel_size=(3, 3), stride=(1, 1))
  (pool_1): MaxPool2d(kernel_size=1, stride=1, padding=0, dilation=1, ceil_mode=False)
  (layer3): ConvTranspose2d(2, 2, kernel_size=(3, 3), stride=(1, 1))
  (out_layer): Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1))
)

如果我要动态更改此网络的大小以运行多个实验,我必须在没有多个分配的情况下模拟上述代码(类似于数据块代码膨胀)。

这样的事情可能会做:

from torch.nn.functional import hardtanh, sigmoid
import torch.nn as nn
import numpy as np

class not_so_great_network(nn.Module):
    def __init__(self, n):
        super(not_so_great_network, self).__init__()
        self.pre_layers = self.generate_pre_layers(n)
        self.post_layers = self.generate_post_layers(n)
        self.pool = nn.MaxPool2d(1, 1)
        self.out = nn.Conv2d(1, 1, 3)

    def generate_pre_layers(self, layer_num):
        layers = np.empty(layer_num, dtype = object)
        for lay in range(0, len(layers)):
            layers[lay] = nn.Conv2d(2, 2, 3)
        return layers

    def generate_post_layers(self, layer_num):
        layers = np.empty(layer_num, dtype = object)
        for lay in range(0, len(layers)):
            layers[lay] = nn.Conv2d(2, 2, 3)
        return layers

    def forward(self, x):
        for pre in self.pre_layers:
            x = hardtanh(pre(x))
            x = self.pool(x)
            
        for post in self.post_layers:
            x = hardtanh(post(x))

        x = sigmoid(self.out(x))
        
        return x

但是,并非所有层都存在:

if __name__ == '__main__':
    layer_num = 5
    net = not_so_great_network(layer_num)
    print(net)

not_so_great_network(
  (pool): MaxPool2d(kernel_size=1, stride=1, padding=0, dilation=1, ceil_mode=False)
  (out): Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1))
)

我没有分配变量,因为如果我可以在不复制和粘贴的情况下生成不同大小的网络,这可能会更强大。如何模拟输出,以便以后可以使用激活函数激活节点?

标签: pythonpython-3.xpytorchrefactoring

解决方案


另一种方法是使用ModuleList

from torch import nn
from torch.nn.functional import hardtanh, sigmoid

class maybe_great_network(nn.Module):
    def __init__(self, n):
        super().__init__()
        self.pre_layers = self.generate_pre_layers(n)
        self.post_layers = self.generate_post_layers(n)
        self.pool = nn.MaxPool2d(1, 1)
        self.out = nn.Conv2d(1, 1, 3)

    def generate_pre_layers(self, layer_num):
        return nn.ModuleList([
            nn.Conv2d(2, 2, 3)
            for l in range(0, layer_num)
        ])

    def generate_post_layers(self, layer_num):
        return nn.ModuleList([
            nn.Conv2d(2, 2, 3)
            for l in range(0, layer_num)
        ])

    def forward(self, x):
        for pre in self.pre_layers:
            x = hardtanh(pre(x))
            x = self.pool(x)
        for post in self.post_layers:
            x = hardtanh(post(x))
        x = sigmoid(self.out(x))
        return x

然后:

>>> m = maybe_great_network(3)
>>> m
maybe_great_network(
  (pre_layers): ModuleList(
    (0): Conv2d(2, 2, kernel_size=(3, 3), stride=(1, 1))
    (1): Conv2d(2, 2, kernel_size=(3, 3), stride=(1, 1))
    (2): Conv2d(2, 2, kernel_size=(3, 3), stride=(1, 1))
  )
  (post_layers): ModuleList(
    (0): Conv2d(2, 2, kernel_size=(3, 3), stride=(1, 1))
    (1): Conv2d(2, 2, kernel_size=(3, 3), stride=(1, 1))
    (2): Conv2d(2, 2, kernel_size=(3, 3), stride=(1, 1))
  )
  (pool): MaxPool2d(kernel_size=1, stride=1, padding=0, dilation=1, ceil_mode=False)
  (out): Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1))
)

推荐阅读