PyTorch中“模块”的定义到底是什么?

时间:2018-08-12 00:05:43

标签: python class pytorch

请原谅新手问题,但是Module与说model一样吗?

当文档说的时候,听起来就是这样:

  

每当您希望模型比现有模块的简单序列复杂时,都需要定义模型(作为自定义Module子类)。

或者...当他们提到Module时,是指更正式,更计算机科学的东西,例如协议/接口类型的东西吗?

4 个答案:

答案 0 :(得分:5)

我没有成为pytorch专家,我的理解是pytorch上下文中的模块只是一个容器,它将接收张量作为输入并计算张量作为输出。

因此,总而言之,您的模型很可能由多个模块组成,例如,您可能有3个模块,每个模块代表一个神经网络层。因此,它们在某种意义上是相关的,您需要模块来实现您的模型,但是它们不是一回事。

希望有帮助

答案 1 :(得分:4)

这是一个简单的容器。

来自nn.Module

的文档
Base class for all neural network modules.
Your models should also subclass this class.
Modules can also contain other Modules, allowing to nest them in a tree structure. 
You can assign the submodules as regular attributes.
Submodules assigned in this way will be registered, 
and will have their parameters converted too when you call `.cuda()`, etc.

来自tutorial

All network components should inherit from nn.Module and override the forward() method. 
That is about it, as far as the boilerplate is concerned. 
Inheriting from nn.Module provides functionality to your component. 
For example, it makes it keep track of its trainable parameters, 
you can swap it between CPU and GPU with the .to(device) method, 
where device can be a CPU device torch.device("cpu") or CUDA device torch.device("cuda:0").

模块是一个容器,层,模型子部分(例如BasicBlock的{​​{1}}中的resnet)和模型都应从中继承。为什么要这样?由于继承自torchvision,因此您可以轻松调用nn.Moduleto("cuda:0").eval()之类的方法或注册钩子。

  • 为什么不只是将“模块”称为模型,而将图层称为“图层”?我想这可能只是语义上的和分散的内容,但仍然...

这是API设计的选择,我发现只有一个.parameters()类,而不是两个单独的ModuleModel,以便更清洁并允许更多的自由(发送一个模型的一部分添加到GPU,仅获取某些图层的参数...)。

答案 2 :(得分:0)

  

为什么不只将“模块”称为模型,又将图层称为“图层”?

这是通过继承实现的,因为PyTorch继承了最初用Torch编写的Lua,在那里他们将其称为模块。

  

PyTorch中“模块”的确切定义是什么?

通常有不同种类的定义。

这里是一个务实的人:

  • 模块是具有某种结构的东西,它在该结构中向前运行以获取输出(返回值)。

这是结构性的:

  • 模块也知道状态,因为您可以要求向您提供参数列表:module.parameters()

这是一个功能:

  • 模块可以调用module.zero_grad()来将内部所有参数的梯度设置为零。在每个反向传播步骤之后,我们都应该这样做。这表明模块还必须处理反向传播,这是标记为更新的参数将被更新的步骤。

标记为要更新的模块参数具有requires_grad=True,如下所示:

Parameter containing:
tensor([-0.4411, -0.2094, -0.5322, -0.0154, -0.1009], requires_grad=True)

您可以说参数就像张量一样,除了它们具有属性requires_grad之外,您可以在其中确定在反向传播期间是否更新参数。

最后,回到forward步骤以获取重要提示:

class ZebraNet(nn.Module):

    def __init__(self, num_classes=1000):
        super(self).__init__()
        self.convpart = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(64, 192, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(192, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        self.avgpooling = nn.AdaptiveAvgPool2d((6, 6))
        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes),
        )

    def forward(self, x):
        x = self.convpart(x)
        x = self.avgpooling(x)
        x = x.view(x.size(0), 256 * 6 * 6)
        x = self.classifier(x)
        return x

您将看到如何在__init__中设置结构,以及forward()将如何告诉您输入x会发生什么以及将返回什么。此返回值将具有我们所需输出的尺寸。根据我们预测输出的精确度,我们会得出更差或更好的准确性,这通常是我们跟踪进度的指标。

答案 3 :(得分:0)

  

为什么不只将“模块”称为模型,又将图层称为“图层”?

在数据结构课程中,您像这样定义二叉树

class tree:
    def __init__(self, value, left, right):
        self.value = value
        self.left = left
        self.right = right

您可以向树中添加子树或叶子以形成新树,就像您可以向模块中添加子模块以形成新模块一样(您不想对树和树这两种不同的数据结构进行子处理,不想叶子和树这两个不同的数据结构,因为毕竟它们都是树,所以您想使用模块来表示模型和层...认为它是递归的,这是使事情整洁的API设计选择。 )

  

PyTorch中“模块”的确切定义是什么?

我想将模块视为某种东西需要输入和输出的东西,就像一个函数一样……这就是模块类中的正向方法要做的事情(指定函数是什么),并且您需要覆盖默认的正向方法,因为否则pytorch不知道该函数是什么...

def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2, 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2, 2)
        x = x.view(-1, 4*4*50)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)

另一个示例是nn.sequential,它也是一个模块,但是一个特殊的例子,它获取模块列表a,并将这些模块的输入和输出链接在一起。

nn.sequential(a, b c) # a->b->c

这就是为什么您不需要指定forward方法的原因,因为它是隐式指定的(只需获取前一个模块的输出并馈送到下一个模块即可)。

另一个示例是conv2d,它也是一个模块,并且其forward方法也已经定义,因此您无需指定它...

class _ConvNd(Module):
    # omit 
class Conv2d(_ConvNd):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1,

                 padding=0, dilation=1, groups=1,

                 bias=True, padding_mode='zeros'):

        kernel_size = _pair(kernel_size)

        stride = _pair(stride)

        padding = _pair(padding)

        dilation = _pair(dilation)

        super(Conv2d, self).__init__(

            in_channels, out_channels, kernel_size, stride, padding, dilation,

            False, _pair(0), groups, bias, padding_mode)



    def conv2d_forward(self, input, weight):

        if self.padding_mode == 'circular':

            expanded_padding = ((self.padding[1] + 1) // 2, self.padding[1] // 2,

                                (self.padding[0] + 1) // 2, self.padding[0] // 2)

            return F.conv2d(F.pad(input, expanded_padding, mode='circular'),

                            weight, self.bias, self.stride,

                            _pair(0), self.dilation, self.groups)

        return F.conv2d(input, weight, self.bias, self.stride,

                        self.padding, self.dilation, self.groups)



    def forward(self, input):

        return self.conv2d_forward(input, self.weight)

如果有人想知道pytorch如何构建图形并进行反向传播...

检查一下...(请不​​要认真对待这段代码,因为我不确定这是否是pytorch的实现方式...但是把这个想法带给您,它可以帮助您了解pytorch的工作原理)

some silly code 希望这会有所帮助:)

PS,我是深度学习和pytorch的新手。可能其中包含一些错误,请仔细阅读...