Modules, data and saving
Writing models as nn.Module, feeding data with Dataset/DataLoader, and persisting weights correctly.
A model is a class
import torch
from torch import nn
class TabularNet(nn.Module):
def __init__(self, n_features, n_classes):
super().__init__() # always call this first
self.net = nn.Sequential(
nn.Linear(n_features, 64),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(64, n_classes),
)
def forward(self, x): # defines the computation
return self.net(x)
model = TabularNet(20, 3)
sum(p.numel() for p in model.parameters())- Submodules assigned as attributes are registered automatically — that is how
.parameters()finds them. - Define layers in
__init__, computation inforward. nn.CrossEntropyLossexpects raw logits, so no softmax in the model.nn.Sequentialis enough for straight-line stacks; use explicit modules when you need branches or shared layers.
Dataset and DataLoader
from torch.utils.data import Dataset, DataLoader
class CSVData(Dataset):
def __init__(self, X, y):
self.X = torch.as_tensor(X, dtype=torch.float32)
self.y = torch.as_tensor(y, dtype=torch.long)
def __len__(self):
return len(self.y)
def __getitem__(self, i):
return self.X[i], self.y[i]
loader = DataLoader(CSVData(X, y), batch_size=64, shuffle=True,
num_workers=2, pin_memory=True)| Argument | Why |
|---|---|
shuffle=True | Training only — shuffling validation adds noise for nothing |
num_workers | Parallel data loading; 0 on Windows if workers misbehave |
pin_memory | Speeds up host-to-GPU copies |
drop_last | Avoids tiny final batches that skew batchnorm |
Saving and loading
torch.save(model.state_dict(), "model.pt")
model = TabularNet(20, 3)
model.load_state_dict(torch.load("model.pt", map_location="cpu"))
model.eval() # do not forget: affects dropout and batchnorm
# resuming training keeps the optimiser too
torch.save({"model": model.state_dict(),
"optim": optimizer.state_dict(),
"epoch": epoch}, "checkpoint.pt")⚠️
Prefer
state_dict() over pickling the whole model: it survives refactoring, is portable across devices, and does not execute arbitrary code on load. Always call model.eval() before inference.FAQ
How do I use a pretrained model?
Load the backbone, replace the final layer for your number of classes, and optionally freeze the backbone while the new head trains. Fine-tune the whole network only when you have enough data.
Where do dropout and batchnorm bite?
They behave differently in training and evaluation. Forgetting
model.eval() makes inference inconsistent and is one of the most common production bugs.Related
The training loop Pipelines and saving models
Last refreshed 2026-09-18.