Pytorch:了解 nn.Module 类的内部工作原理

Bra*_*wan 4 python deep-learning pytorch

通常, ann.Module可以被子类继承,如下所示。

def init_weights(m):
    if type(m) == nn.Linear:
        torch.nn.init.xavier_uniform(m.weight)  # 

class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.fc1 = nn.Linear(20, 1)
        self.apply(init_weights)

    def forward(self, x):
        x = self.fc1(x)
        return x
Run Code Online (Sandbox Code Playgroud)

我的第一个问题是,为什么我可以简单地运行下面的代码,即使我__init__没有任何 positinoal 参数,training_signals并且它看起来像training_signals传递给forward()方法。它是如何工作的?

model = LinearRegression()
training_signals = torch.rand(1000,20)
model(training_signals)
Run Code Online (Sandbox Code Playgroud)

第二个问题是self.apply(init_weights)内部如何运作?它是在调用forward方法之前执行吗?

Ber*_*iel 9

Q1:为什么即使我__init__没有任何位置参数,我也可以简单地运行下面的代码,training_signals并且看起来它training_signals已传递给forward()方法。它是如何工作的?

首先,__init__当您运行此行时会调用 :

model = LinearRegression()
Run Code Online (Sandbox Code Playgroud)

如您所见,您没有传递任何参数,而且您不应该传递任何参数。您的签名__init__与基类的签名相同(您在运行时调用super(LinearRegression, self).__init__())。正如您在此处看到的,nn.Module的 init 签名很简单def __init__(self)(就像您的一样)。

第二,model现在是一个对象。当您运行以下行时:

model(training_signals)
Run Code Online (Sandbox Code Playgroud)

您实际上是在调用该__call__方法并training_signals作为位置参数传递。正如您在此处看到的,除许多其他事项外,该__call__方法调用该forward方法:

result = self.forward(*input, **kwargs)
Run Code Online (Sandbox Code Playgroud)

将 的所有参数(位置和命名)传递__call__forward.

Q2:self.apply(init_weights)内部如何运作?它是在调用 forward 方法之前执行的吗?

PyTorch 是开源的,因此您只需转到源代码并检查它。正如您在此处看到的,实现非常简单:

def apply(self, fn):
    for module in self.children():
        module.apply(fn)
    fn(self)
    return self
Run Code Online (Sandbox Code Playgroud)

引用函数的文档:它“递归地应用于fn每个子模块(由 返回.children())以及self”。基于实现,您还可以了解需求:

  • fn 必须是可调用的;
  • fn仅接收一个Module对象作为输入;