Cheat sheets

Training Neural Networks

Pick the optimizer, init, normalization, regularization and schedule. Then debug the run when the loss misbehaves.

  • Concepts and terms
  • Tasks and commands
  • Annotated code
  • Diagrams
  • Defaults and numbers
  • Troubleshooting
  • Questions and tips

Source

One AdamW step#

AdamWLossforward pass outputloss.backward()chain rule fills gradsclip_grad_norm_max_norm=1.0First moment m_tmean, beta1 0.9Second moment v_tvariance, beta2 0.999Bias correctiondivide by 1 - beta^tAdam updatelr · m̂ / (√v̂ + ε)Decoupled decayminus lr · λ · wAdamWLossforward passoutputloss.backward()chain rulefills gradsclip_grad_norm_max_norm=1.0Firstmoment m_tmean, beta10.9Secondmoment v_tvariance,beta2 0.999Biascorrectiondivide by 1 -beta^tAdam updatelr · m̂ /(√v̂ + ε)Decoupleddecayminus lr · λ· w

From Lesson 03.06

The training step#

1zero_gradclear the gradients from the last batch.2Forwardrun the model on the batch.3Losscompare the output with the targets.4backwardcompute the gradient of every parameter.5Clipcap the global gradient norm. This step isoptional.6stepthe optimizer updates the weights.7Schedulescheduler.step() comes after optimizer.step().

From Lesson 03.06

Training loop with AdamW and cosine#

optimizer = optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.01)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)
for epoch in range(100):
optimizer.zero_grad()clear old gradients
output = model(torch.randn(32, 784))forward pass
loss = torch.nn.functional.cross_entropy(output, torch.randint(0, 10, (32,)))
loss.backward()fill .grad by chain rule
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()update the weights
scheduler.step()after optimizer.step()
Warmup then cosine, from the HuggingFace library
scheduler = get_cosine_schedule_with_warmup(
optimizer, num_warmup_steps=2000, num_training_steps=100000)

From Lesson 03.06, Lesson 03.09

Key formulas#

Chain rule
\frac{dy}{dx} = f'(g(x)) \cdot g'(x)
Adam moments
m_t = \beta_1 m_{t-1} + (1 - \beta_1) \cdot \text{gradient} and v_t = \beta_2 v_{t-1} + (1 - \beta_2) \cdot \text{gradient}^2
Bias correction
\hat{m} = \frac{m_t}{1 - \beta_1^t} and \hat{v} = \frac{v_t}{1 - \beta_2^t}
AdamW update
w = w - \text{lr} \cdot \frac{\hat{m}}{\sqrt{\hat{v}} + \epsilon} - \text{lr} \cdot \lambda w
Cosine decay
\text{lr}(t) = \text{lr}_{\min} + 0.5 \cdot (\text{lr}_{\max} - \text{lr}_{\min}) \cdot \left(1 + \cos\left(\frac{\pi t}{T}\right)\right)
Linear warmup
\text{lr}(t) = \text{lr}_{\max} \cdot \frac{t}{\text{warmup\_steps}} \quad \text{for } t < \text{warmup\_steps}
Init variance
Kaiming \mathrm{Var}(w) = \frac{2}{\text{fan}_{\text{in}}}, Xavier \mathrm{Var}(w) = \frac{2}{\text{fan}_{\text{in}} + \text{fan}_{\text{out}}}
Inverted dropout
\text{output} = \text{activation}(z) \cdot \text{mask} / (1 - p) during training

From Lesson 03.03, Lesson 03.06, Lesson 03.07, Lesson 03.08, Lesson 03.09

Pick by situation#

SituationChoice
Transformer or LLMAdamW, lr=1e-4, wd=0.01-0.1
CNN or ResNetSGD + Momentum, lr=0.1, momentum=0.9
GANAdam, lr=2e-4, beta1=0.5
Fine-tuningAdamW, lr=2e-5, wd=0.01
Not sure yetAdamW, lr=3e-4, wd=0.01
Sigmoid or tanh layersXavier init
ReLU, GELU or Swish layersKaiming init
Transformer residual layersscale by 1/sqrt(2N), N layers

From Lesson 03.06, Lesson 03.08

Init, norm and regularization in code#

TaskCode
Kaiming init for ReLUnn.init.kaiming_normal_(layer.weight, nonlinearity='relu')
Xavier initnn.init.xavier_uniform_(layer.weight)
BatchNorm after a Linearnn.BatchNorm1d(256)
LayerNorm in a transformernn.LayerNorm(d_model)
Dropout in an MLPnn.Dropout(0.3)
Cosine decay to a floorCosineAnnealingLR(optimizer, T_max=1000, eta_min=1e-5)
Find the first NaN or Infwith torch.autograd.detect_anomaly():
Measure the gradient normtorch.nn.utils.clip_grad_norm_(model.parameters(), float("inf"))

From Lesson 03.08, Lesson 03.07, Lesson 03.09, Lesson 03.13

Optimizer defaults#

SettingDefaultNote
Adam lr0.001change lr first
beta10.9almost never change
beta20.999change second if needed
epsilon1e-8almost never change
AdamW weight_decay0.01not scaled by the adaptive rate
SGD momentum0.9about the last 10 gradients
SGD weight decay on CNNs1e-4with step or cosine schedule
Gradient clip max_norm1.0clip by global norm

From Lesson 03.06

Regularization and schedule defaults#

SettingDefaultNote
Dropout, transformers0.1LayerNorm models
Dropout, MLPs0.5half the neurons off
BatchNorm momentum0.190% old plus 10% new
BatchNorm eps1e-5added to the variance
Warmup share3-5%of total steps
Cosine floor eta_min1e-5lowest lr
Step decay factor0.1at fixed epochs
Log clamp eps1e-7keeps log(p) finite

From Lesson 03.07, Lesson 03.09, Lesson 03.13

Troubleshooting#

SymptomCauseFix
Loss stuck at -log(1/num_classes)model predicts a uniform distributioncheck data pipeline and labels
Loss NaN after a few stepslearning rate too highreduce lr by 10x
Loss NaN at oncelog(0) or division by zeroclamp predictions to [eps, 1-eps]
Loss oscillatesno optimizer.zero_grad()call it before loss.backward()
Test accuracy varies between runsno model.eval()add model.eval() and torch.no_grad()
Train acc high, test acc lowoverfittingdropout, weight decay, more data
Gradients all zerodead ReLUs or detached graphLeakyReLU, check .requires_grad
Early layers stop learningsigmoid derivative is at most 0.25ReLU or GELU with Kaiming init

From Lesson 03.13, Lesson 03.03, Lesson 03.08

Glossary#

SGD
stochastic gradient descent on a mini-batch.
AdamW
Adam with decoupled weight decay.
BatchNorm
normalizes each feature across the mini-batch.
LayerNorm
normalizes each sample across its features.
RMSNorm
LayerNorm without the mean subtraction.
1cycle
lr goes up, then down, in one cycle.
SGDR
cosine annealing with warm restarts.
LR range test
raise lr during a short run and find where loss diverges.

From Lesson 03.06, Lesson 03.07, Lesson 03.09, Lesson 03.13

Questions#

Why AdamW and not Adam plus L2?
Adam scales the L2 term by its adaptive rate. AdamW shrinks every weight by the same proportion.
Why warmup?
Adam moments start at zero. Large early steps follow bad statistics.
Why bias correction?
At step 1 with beta1 0.9, m is 0.1 times the gradient.
Why LayerNorm in transformers?
It does not depend on batch size or sequence length.
Why Kaiming for ReLU?
ReLU zeros half the activations, so the variance is 2/fan_in.

From Lesson 03.06, Lesson 03.09, Lesson 03.07, Lesson 03.08

Tips#

  • Run the overfit-one-batch test first. Loss must go to nearly zero.
  • Try 3 learning rates 10x apart before you blame anything else.
  • If you tune one hyperparameter, tune the learning rate.
  • Print tensor shapes after every operation while you debug.
  • Check that gradient sizes are similar across layers.
  • Use .to(device) on the model and the data.

From Lesson 03.13, Lesson 03.06