Match the loss to the task
The loss is the contract between your data and your optimizer. Pick the wrong one and the model will learn the wrong thing — even if accuracy looks superficially fine.
- Multi-class classification —
nn.CrossEntropyLoss. Takes raw logits, expects integer class labels. - Multi-label classification —
nn.BCEWithLogitsLoss. One sigmoid per label, BCE per label. - Binary classification —
nn.BCEWithLogitsLosswith a single output. - Regression (squared error) —
nn.MSELoss. Sensitive to outliers. - Regression (robust) —
nn.SmoothL1Lossornn.HuberLoss. - Ranking / similarity — triplet loss, contrastive loss, InfoNCE.
- Sequence generation — token-level cross-entropy with optional label smoothing.
Cross-entropy is the workhorse
Cross-entropy loss for a single example with logits z and true class c is -log(softmax(z)[c]). It pushes the logit of the right class up and the logits of the wrong classes down, and the gradient is beautifully clean: softmax(z) - one_hot(c).
For balanced classes, plain cross-entropy works. For imbalanced classes, you can pass weight= per class, or use focal loss (down-weights easy examples). For very large vocabularies (LLMs), you can sample subsets of negatives instead of computing the full softmax.
Class weights, label smoothing, and friends
For imbalanced data, pass weight=class_weights. For overconfident models, use label_smoothing=0.1 to soften targets. For multi-label tasks, BCE per label gives you the right shape. These knobs sit on top of the basic loss and rarely change the choice, only the calibration.