Hi,

Not sure what you refer to in that question.
You should always call super().__init__() if you subclass an nn.Module() and you write a custom __init__() function.
The autograd allows for that. Just note that no gradient (a gradient of 0) will flow back on the side of x<5 because this gives a piece-wise constant output which has a gradient of 0 almost everywhere. In general, the autograd engine will raise an exception if it cannot compute the gradients you ask for.
You want to use nn.Module over just a python function if you have some parameters. Which is your case here actually. Note as well that parameters should be of type nn.Parameter (in your case: self.W = nn.Parameter(torch.randn(dim, 1).type(dtype)) so that it will be properly found as a parameter of your network when you do net.parameters() (for example to give all your parameters to your optimizer).
If you do the function you showed, then it will generate random weights every time and no learning will happen, which is not what you want I guess as you set requires_grad = True here.
Keep in mind that in pytorch, your code is run at every forward pass.