Two methods, infinite power
Every neural network component in PyTorch — from a single linear layer to a 70B-parameter transformer — is an nn.Module. Subclassing it is the single most important Python pattern you'll use in this framework, so internalize the contract:
- Override
__init__. Always callsuper().__init__()first. Create child modules and parameters by assigning them toself(e.g.self.layer1 = nn.Linear(10, 20)). PyTorch hooks the__setattr__to register them. - Override
forward(self, x, ...). Define the computation. Never call this directly — call the module instance like a function:model(x), notmodel.forward(x). The instance call routes through__call__, which runs registered hooks, handles training/eval modes for children, and threads through the autograd machinery properly.
What you get for free
model.parameters()— iterator over every learnable tensor, no matter how nested.model.named_parameters()— same, with the dotted-path name attached.model.to(device)— moves all parameters AND buffers to a device.model.train()/model.eval()— flips behavior of children that care (Dropout, BatchNorm).model.state_dict()/load_state_dict()— serialization-ready dict of all parameters and buffers.
All of this depends on you using nn.Module's machinery (assigning to self, using nn.ModuleList instead of plain Python lists for collections, using nn.Parameter for raw learnable tensors). Skip those, and the auto-magic stops working silently.