Python OOP 问题:class 中的函数如何获取输入值,而 __init__() 函数中未将其作为参数提及?

Python OOP issue: How a function in a class is getting input value, when it is not mentioned in __init__() function as a parameter?

我是面向对象编程的新手,目前正在从事生成对抗网络项目。我遇到了 maxout 激活函数。该函数是通过maxoutclass定义的。请看下面的代码:

class maxout(torch.nn.Module):
    def __init__(self, num_pieces):
        
        super(maxout, self).__init__()
        
        self.num_pieces = num_pieces
        
    def forward(self, x):
        
        assert x.shape[1] % self.num_pieces == 0  # 625 % 5 = 0
        
        ret = x.view(*x.shape[:1], # batch_size
                      x.shape[1] // self.num_pieces, 
                      self.num_pieces, # num_pieces
                      *x.shape[2:]    )
                     
        ret, _ = ret.max(dim=2)
        
        return ret

此 maxout 函数后来用于鉴别器 class。以下是鉴别器 class.

的代码
class discriminator(torch.nn.Module):
    
    def __init__(self):
        
        super(discriminator, self).__init__()
        
        self.fcn = torch.nn.Sequential(
            # Fully connected layer 1
            torch.nn.Linear(
                in_features = 784,
                out_features=240,
                bias = True
            ),
            maxout(5),
            
            # Fully connected layer 2
            torch.nn.Linear(
                in_features = 48,
                out_features=1,
                bias = True
            )  )
        
    def forward(self, batch):
        inputs = batch.view(batch.size(0), -1)
        outputs = self.fcn(inputs)
        outputs = outputs.mean(0)
        return outputs.view(1)  # it will return a single value

代码运行良好,但根据我对面向对象编程的天真理解,maxout class 中 forward() 函数中 'x' 的值应通过 提供初始化() 函数。

我的问题是:maxout class 的 forward() 函数如何接收输入 'x',而不通过 init() 获取输入功能。

这个问题的另一种表达方式是:How output of Linear layer in discriminator class is passed to maxout function as 'x'?

方法与常规函数的不同之处仅在于它们的第一个参数是定义方法的 class 的对象,并且可以使用点运算符提供第一个参数。 只有程序员决定通过 __init__ 传递哪些值以将它们分配给对象属性,以及在第一个 self 参数之后将哪些值作为参数传递。没有要求首先通过 __init__ 方法传递我们给其他方法的所有值。

回答你的问题: torch.nn.Sequential 保存你传递的函数列表,在本例中它的长度为 3,并输出一些可调用对象(一个可以像函数一样工作的对象)。您将其保存到 self.fcn。然后,当您调用 self.fcn 时,它会调用第一个 torch.nn.Linearforward 方法,然后将它的 return 值传递给 [=] 的 forward 方法19=] 对象 - 那就是给出 x 的地方! - 然后将 maxout(5) 对象的输出传递给第二个 torch.nn.Linearforward 方法,并 return 得到结果。

您将层传递给 Sequential 模型的构造函数,该模型分配给 self.fcn,而不是您在 discriminator.forward 中调用此模型。它是 __call__ 方法,而不是调用它包含的层的所有前向函数。

你可以想象这样的事情正在发生

...
def forward(self, batch):
   return torch.nn.Linear(
       in_features = 48,
       out_features=1,
       bias = True
   ).forward(
       maxout(5).forward(
           torch.nn.Linear(
                in_features = 784,
                out_features=240,
                bias = True
           ).forward(batch.view(batch.size(0), -1)
       )
    ).mean(0).view(1)