Neural Network Debug Checklist
Systematic debugging protocol for when training goes wrong. Work through these in order -- most bugs are caught in the first 3 steps.
Before training (prevent bugs)
- Print model architecture and parameter count. Does the size make sense for your data?
- Run a single forward pass with random input. Does the output shape match your target shape?
- Check that labels are the correct dtype (CrossEntropyLoss needs Long, BCELoss needs Float)
- Verify data normalization: inputs should have mean near 0 and std near 1
- Print 5 random (input, label) pairs. Do the labels match what you expect?
- Confirm train/test split has no duplicate samples
Overfit-one-batch test (60 seconds, catches 80% of bugs)
- Take 8-32 samples from your training set
- Train for 200 steps with a reasonable learning rate
- Loss should approach 0. Training accuracy should hit 100%
- If it fails: the bug is in your model, loss function, or training loop -- not your data or hyperparameters
- If it passes: proceed to full training
Loss not decreasing
- Check learning rate. Try 3 values: current/10, current, current*10
- Print gradient norms per layer. All zeros means dead network or detached graph
- Check
requires_grad=Trueon parameters. Check thatloss.backward()is called - Check that
optimizer.zero_grad()is called beforeloss.backward() - Check that
optimizer.step()is called afterloss.backward() - Verify model parameters are passed to the optimizer:
optimizer = Adam(model.parameters())
Loss is NaN or Inf
- Reduce learning rate by 10x
- Add epsilon to all log() calls:
torch.log(x + 1e-7) - Add epsilon to all division:
x / (y + 1e-8) - Clamp predictions:
torch.clamp(pred, 1e-7, 1 - 1e-7)before BCE loss - Use
torch.autograd.detect_anomaly()to find the exact operation - Check for NaN in input data:
assert not torch.isnan(x).any()
Loss oscillating
- Reduce learning rate by 3-10x
- Increase batch size (reduces gradient noise)
- Add gradient clipping:
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) - Switch from SGD to Adam (adaptive LR per parameter)
- Add learning rate warmup for the first 5-10% of training
Overfitting (train acc high, test acc low)
- Add dropout (start with p=0.1, increase to 0.5)
- Add weight decay to optimizer:
Adam(params, weight_decay=1e-4) - Reduce model size (fewer layers or narrower layers)
- Add data augmentation
- Use early stopping: stop when validation loss increases for 5+ epochs
- Check for data leakage between train and test sets
Underfitting (both train and test acc low)
- Increase model capacity (more layers, wider layers)
- Train for more epochs
- Increase learning rate (carefully)
- Remove regularization temporarily to verify the model can learn
- Check that your model is expressive enough for the task
Dead ReLU neurons
- Check fraction of zero activations per layer. >50% is a problem
- Switch to LeakyReLU(0.01) or GELU
- Use Kaiming initialization for weights
- Reduce learning rate (large updates can push neurons into the dead zone)
- Add batch normalization before activation functions
Quick reference: learning rate starting points
| Optimizer | Task | Starting LR |
|---|---|---|
| Adam | Training from scratch | 1e-3 |
| Adam | Fine-tuning pretrained | 1e-5 |
| SGD + momentum | Training from scratch | 1e-1 |
| SGD + momentum | Fine-tuning pretrained | 1e-3 |
| AdamW | Transformer training | 3e-4 |
Quick reference: batch size effects
| Batch size | Gradient noise | Memory | Generalization |
|---|---|---|---|
| 8-16 | High (noisy) | Low | Often better |
| 32-64 | Moderate | Moderate | Good default |
| 128-256 | Low (smooth) | High | May need warmup |
| 512+ | Very low | Very high | Needs LR scaling |
When nothing works
- Simplify the model to 1 hidden layer. Does it learn?
- Simplify the data to 100 samples. Does it overfit?
- Replace your loss with MSE. Does it converge?
- Replace your optimizer with SGD(lr=0.01). Does it make progress?
- Replace your data with synthetic data (e.g., y = x[0] > 0). Does it learn?
- If none of these work: the bug is in code you are not looking at (data loading, preprocessing, tensor shapes)