Hyper-parameters: the knobs you turn before training
Learning rate, batch size, optimiser, weight decay, dropout, schedulers, and seeds — what they do, why they matter, and the exact values used for the xBD damage-assessment project.
A neural network has two kinds of numbers: parameters (the millions of weights inside the model, learned automatically by gradient descent) and hyper-parameters (a handful of numbers you pick before training starts). Think of it like baking a cake: the recipe ingredients are parameters that get mixed together, but the oven temperature, the baking time, and the pan size are hyper-parameters — you choose them, and a bad choice ruins the cake no matter how good the ingredients are.
This lecture walks through every hyper-parameter we use in the xBD project, explains what each one actually does, shows the equation behind it, and lists the value we chose with the reasoning. By the end you should be able to defend each number on the hyper-parameter table in your project write-up.
Parameters vs. hyper-parameters
The single most important distinction.
A model's parameters are the weights and biases that gradient descent updates every batch. A ResNet-50 has roughly 25 million of them. We never set these by hand. Hyper-parameters are the small set of decisions that govern how the parameters are learned — the learning rate, the optimiser, the batch size, how long to train, how much to regularise, and so on. Figure 1 makes the boundary explicit.
loss.backward() it is a parameter. If you set it once at the top of your training script, it is a hyper-parameter.The learning rate — η
The single most impactful hyper-parameter in deep learning.
Gradient descent updates each weight by walking downhill on the loss surface. The learning rate η controls how big each step is:
- — weights at step t
- — learning rate — the step size
- — gradient of the loss with respect to the weights — points uphill
Too small and the network crawls; too large and it overshoots the minimum and diverges. Figure 2 shows the three regimes on a simple bowl-shaped loss.
In practice we never use a single fixed for the whole run. We warm up (start tiny, ramp up linearly for the first few epochs to avoid blowing up randomly-initialised weights), then anneal (smoothly shrink so the network can settle into a narrow minimum at the end). Figure 3 plots the three schedulers you will see in the wild.
For the xBD project we use warm-up + cosine annealing over 50 epochs:
- — current epoch (0, 1, …, E−1)
- — number of warm-up epochs (we use 5)
- — total epochs (we use 50)
- — peak learning rate at the end of warm-up (3 × 10⁻⁴)
- — floor learning rate at the end of training (1 × 10⁻⁶)
Batch size — B
Statistical noise vs. memory vs. speed.
The batch size is how many training examples we average gradients over before taking one optimiser step. Small batches give noisy gradients that act as a mild regulariser; large batches give precise gradients but need a proportionally larger learning rate to compensate.
- — batch size
- — learning rate that already works for B_{base}
| Batch size | GPU VRAM (≈) | Steps per epoch | Pros | Cons |
|---|---|---|---|---|
| 4 | ~6 GB | ~22 k | Fits any GPU | Very noisy gradients |
| 16 | ~12 GB | ~5.5 k | Good noise/precision balance | Slower per epoch |
| 32 | ~22 GB | ~2.7 k | Project default | Needs a 24 GB GPU |
| 64 | ~44 GB | ~1.4 k | Faster convergence | Needs A100, may need LR re-tune |
Optimisers
SGD, Adam, AdamW — and why we use AdamW.
The optimiser is the algorithm that uses the gradient to update the weights. Plain SGD uses the gradient directly. Adam adapts a per-weight step size based on the running mean and running variance of the gradient — much faster on noisy problems like ours.
- — current gradient \nabla_{\theta}\mathcal{L}
- — running average of the gradient (momentum, β₁ = 0.9)
- — running average of the squared gradient (β₂ = 0.999)
- — bias-corrected versions of m and v
- — small constant (10⁻⁸) to avoid division by zero
AdamW is Adam with the weight-decay term decoupled from the gradient update (Loshchilov & Hutter, 2017). Standard Adam mixes weight decay into the running averages, which under-penalises large weights. AdamW fixes this and is the modern default for both ViT and CNN training.
Weight decay & dropout
Two regularisers that fight overfitting.
Overfitting happens when the network memorises the training set instead of learning patterns that generalise to new tiles. Figure 4 is the classic shape: train loss keeps dropping while validation loss bottoms out and then climbs.
We push the validation curve down (and rightward) with two cheap regularisers:
- — the usual data loss (Focal + Dice in our case)
- — sum of squared weights — large weights are heavily penalised
- — weight-decay strength (small, but nonzero)
- — activation of neuron i in the layer
- — drop probability — fraction of neurons to silence each step
- — 1 with probability 1-p, otherwise 0 — the random mask
- — rescale so the average activation stays the same
Other knobs you must set
| Hyper-parameter | What it controls | Project value | Why |
|---|---|---|---|
| Epochs E | How many full passes through the data | 50 | Validation F1 plateaus around epoch 42 — leave 8-epoch safety margin |
| Warm-up epochs E_w | Length of the linear LR ramp | 5 | Standard for AdamW with batch size 32 |
| Loss weights (Focal, Dice) | Relative pull of each loss term | α=1.0, β=1.0 | Equal balance worked best in our pilot ablation |
| Class weights w_c | Up-weight rare damage classes | [0.5, 1.0, 2.5, 5.0, 5.0] | Inverse √frequency from xBD train split |
| Augmentation strength | How aggressive the random flips/colour jitter are | Medium (Albumentations 'default') | Heavy aug hurt small-building recall in pilot |
| Random seed | Reproducibility of weights, shuffles, augmentations | 1337 | We re-run 3 seeds to report mean ± std |
| Gradient clipping | Cap on the global gradient norm | 1.0 | Stops occasional exploding-gradient spikes from ViT-like layers |
The tuning workflow
How to find a good setting without burning a thousand GPU hours.
- Start from published defaults. ResNet-50 + U-Net on segmentation? Use AdamW, η = 3e-4, B = 32. Don't invent.
- Sanity-overfit one batch. Take 8 tiles, train for 200 steps, and confirm loss reaches near-zero. If it doesn't, the bug is in your code, not your hyper-parameters.
- Run an LR finder. Sweep η from 10−6 to 10−1 for ~100 steps and plot loss; pick the value one order of magnitude below the point where loss explodes.
- Tune one knob at a time. Just like an ablation study — change one number, keep everything else fixed, measure the validation F1, decide.
- Lock in and run the full 50 epochs with seeds and a logger (TensorBoard or W&B).
Common failure modes
If your training looks like one of these, you have a hyper-parameter problem, not a model problem.
| Symptom | Likely cause | Fix |
|---|---|---|
| Loss is NaN after a few steps | η too high or no gradient clipping | Halve η, set clip_grad_norm=1.0 |
| Loss flatlines from step 1 | η too low, or learning-rate not connected to optimiser | Run the LR finder; verify the scheduler is stepped each epoch |
| Train F1 great, val F1 terrible | Overfitting | Increase weight decay, dropout, augmentation; reduce epochs; early-stop |
| Different runs disagree by > 3 F1 | Insufficient seed averaging | Run 3+ seeds, report mean ± std |
| First epoch loss spikes then recovers | No warm-up; AdamW state is cold | Add 3–5 warm-up epochs |
Wrap-up & next lecture
Hyper-parameters are the unglamorous half of deep learning — but they decide whether the same architecture gets 0.55 or 0.71 macro-F1. The values in Table 2 are the ones we lock down across every ablation run so that any metric change is attributable to the component we changed, not to a lucky learning rate.
- η (eta) / LR
- — learning rate; step size of each weight update.
- B
- — batch size; examples averaged per optimiser step.
- E / E_w
- — total epochs / warm-up epochs (linear ramp at start).
- epoch
- — one full pass over the training set.
- SGD
- — Stochastic Gradient Descent: the plain "take a step downhill" optimiser.
- Adam / AdamW
- — adaptive optimiser; AdamW decouples weight decay (modern default).
- β₁, β₂
- — Adam's momentum decay rates (0.9, 0.999 by default).
- m_t, v_t
- — Adam's running mean and variance of the gradient.
- λ (lambda)
- — weight-decay strength; bigger λ → smaller weights → less overfitting.
- L2 / ‖θ‖²
- — sum of squared weights, the thing weight decay penalises.
- Dropout p
- — probability of zeroing a neuron during training (we use 0.1 in the decoder).
- Cosine annealing
- — half-cosine schedule that smoothly drops η from η_max → η_min.
- Warm-up
- — linear ramp from 0 → η_max during the first E_w epochs.
- Grad clipping
- — cap the gradient's norm to a fixed value (we use 1.0) to stop explosions.
- Early stop
- — stop training once validation loss stops improving.
- VRAM
- — GPU memory. Bigger B → more VRAM.
- Seed
- — fixed random number so a run is reproducible.
- F1 / macro-F1
- — F1 averaged equally over all classes (rare classes count the same as common).