What does Pytorch's nn.Linear(x,y) return?
I am new to object orientation, and I am having troubles understanding the following:
import torch.nn as nn

class mynet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(20, 64)
    
    def forward(self, x):
        x = self.fc1(x)


The line self.fc1 = nn.Linear(20, 64)  is supposed to create a member variable fc1 to my class, right? But what is the return value of nn.Linear(20, 64)?
According to the documentation, nn.Linear is defined as
class torch.nn.Linear(in_features: int, out_features: int, bias: bool = True).
However, in my basic OOP tutorial I have only seen something like class CLASSNAME(BASECLASS) so that the class CLASSNAME inherits from BASECLASS. What does the documentation mean with its way of writing all that stuff in between the brackets?
Also, the line x=fc1(x) somehow makes it look as if fc1 was a function now.
I seem to lack OOP knowledge here... Any help appreciated!

You can create a little examination:
import torch
import torch.nn as nnn
fc1 = nn.Linear(20, 64)
print(fc1, type(fc1))
ret = fc1(torch.randn(20))
print(ret, type(ret), ret.shape)

Out:
Linear(in_features=20, out_features=64, bias=True) &lt;class 'torch.nn.modules.linear.Linear'&gt;
tensor([-0.2795,  0.8476, -0.8207,  0.3943,  0.1464, -0.2174,  0.6605,  0.6072,
        -0.6881, -0.1118,  0.8226,  0.1515,  1.3658,  0.0814, -0.8751, -0.9587,
         0.1310,  0.2539, -0.3072, -0.0225,  0.4663, -0.0019,  0.0404,  0.9279,
         0.4948, -0.3420,  0.9061,  0.1752,  0.1809,  0.5917, -0.1010, -0.3210,
         1.1910,  0.5145,  0.2254,  0.2077, -0.0040, -0.6406, -0.1885,  0.5270,
         0.0824, -0.0787,  1.5140, -0.7958,  1.1727,  0.1862, -1.0700,  0.0431,
         0.6849,  0.1393,  0.7547,  0.0917, -0.3264, -0.2152, -0.0728, -0.6441,
        -0.1162,  0.4154,  0.3486, -0.1693,  0.6697,  0.0229,  0.0311,  0.1433],
       grad_fn=&lt;AddBackward0&gt;) &lt;class 'torch.Tensor'&gt; torch.Size([64])

fc1 is of type class 'torch.nn.modules.linear.Linear'.
It needs some &quot;juice&quot; to work. In your case it needs the input tensor torch.randn(20) to return the output of  torch.Size([64]).
So fc1 is a class instance that you can run with () in which case the forward() method of a class nn.Linear will be called.
In most cases when working with your modules (like mynet in your case) you will list the modules in __init__, and then in the forward of your module you will be defining what will happen (the behavior).
The three kind of modules in PyTorch are:

Functional modules
Default modules
Custom modules

Custom modules like mynet you created typically use default modules:

nn.Identity()
nn.Embedding()
nn.Linear()
nn.Conv2d()
nn.BatchNorm() (BxHxW)
nn.LayerNorm() (CxHxW)
nn.Dropout()
nn.ReLU()

And many many other modules that I haven't set. But of course, you can create custom modules without any default modules, just by using nn.Parameter(), see the last example.
The third kind functional modules are defined here.
Also check nn.Linear implementation. You may note the F.linear() functional module is used.
You may test the naive implementation of Linear from Fastai Book:
import torch
import torch.nn as nn
import math

class Linear(nn.Module):
    def __init__(self, n_in, n_out):
        super().__init__()
        self.weight = nn.Parameter(torch.randn(n_out, n_in) * math.sqrt(2/n_in))
        self.bias = nn.Parameter(torch.zeros(n_out))
    
    def forward(self, x): return x @ self.weight.T + self.bias
    
fc = Linear(20,64)
ret = fc(torch.randn(20))
print(ret.shape) # 64

You may try to understand the difference between the naive implementation provided inside PyTorch.
